@orbcharts/core 3.0.0-alpha.43 → 3.0.0-alpha.45

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +97 -97
  3. package/dist/orbcharts-core.umd.js +2 -2
  4. package/dist/src/series/seriesObservables.d.ts +3 -3
  5. package/dist/src/types/ContextObserverSeries.d.ts +1 -1
  6. package/dist/src/types/DataFormatterSeries.d.ts +3 -3
  7. package/package.json +41 -41
  8. package/src/AbstractChart.ts +48 -48
  9. package/src/GridChart.ts +20 -20
  10. package/src/MultiGridChart.ts +20 -20
  11. package/src/MultiValueChart.ts +20 -20
  12. package/src/RelationshipChart.ts +20 -20
  13. package/src/SeriesChart.ts +20 -20
  14. package/src/TreeChart.ts +20 -20
  15. package/src/base/createBaseChart.ts +368 -367
  16. package/src/base/createBasePlugin.ts +89 -89
  17. package/src/defaults.ts +220 -220
  18. package/src/defineGridPlugin.ts +3 -3
  19. package/src/defineMultiGridPlugin.ts +3 -3
  20. package/src/defineMultiValuePlugin.ts +3 -3
  21. package/src/defineNoneDataPlugin.ts +4 -4
  22. package/src/defineRelationshipPlugin.ts +3 -3
  23. package/src/defineSeriesPlugin.ts +3 -3
  24. package/src/defineTreePlugin.ts +3 -3
  25. package/src/grid/computeGridData.ts +134 -134
  26. package/src/grid/createGridContextObserver.ts +147 -147
  27. package/src/grid/gridObservables.ts +573 -573
  28. package/src/index.ts +21 -21
  29. package/src/multiGrid/computeMultiGridData.ts +130 -130
  30. package/src/multiGrid/createMultiGridContextObserver.ts +40 -40
  31. package/src/multiGrid/multiGridObservables.ts +350 -350
  32. package/src/multiValue/computeMultiValueData.ts +143 -143
  33. package/src/multiValue/createMultiValueContextObserver.ts +12 -12
  34. package/src/relationship/computeRelationshipData.ts +118 -118
  35. package/src/relationship/createRelationshipContextObserver.ts +12 -12
  36. package/src/series/computeSeriesData.ts +90 -90
  37. package/src/series/createSeriesContextObserver.ts +93 -93
  38. package/src/series/seriesObservables.ts +175 -175
  39. package/src/tree/computeTreeData.ts +131 -131
  40. package/src/tree/createTreeContextObserver.ts +61 -61
  41. package/src/tree/treeObservables.ts +94 -94
  42. package/src/types/Chart.ts +48 -48
  43. package/src/types/ChartParams.ts +51 -51
  44. package/src/types/ComputedData.ts +83 -83
  45. package/src/types/ComputedDataGrid.ts +13 -13
  46. package/src/types/ComputedDataMultiGrid.ts +2 -2
  47. package/src/types/ComputedDataMultiValue.ts +9 -9
  48. package/src/types/ComputedDataRelationship.ts +19 -19
  49. package/src/types/ComputedDataSeries.ts +7 -7
  50. package/src/types/ComputedDataTree.ts +19 -19
  51. package/src/types/ContextObserver.ts +38 -38
  52. package/src/types/ContextObserverGrid.ts +41 -41
  53. package/src/types/ContextObserverMultiGrid.ts +15 -15
  54. package/src/types/ContextObserverMultiValue.ts +4 -4
  55. package/src/types/ContextObserverRelationship.ts +4 -4
  56. package/src/types/ContextObserverSeries.ts +29 -29
  57. package/src/types/ContextObserverTree.ts +11 -11
  58. package/src/types/ContextSubject.ts +18 -18
  59. package/src/types/Data.ts +45 -45
  60. package/src/types/DataFormatter.ts +74 -74
  61. package/src/types/DataFormatterGrid.ts +67 -67
  62. package/src/types/DataFormatterMultiGrid.ts +44 -44
  63. package/src/types/DataFormatterMultiValue.ts +23 -23
  64. package/src/types/DataFormatterRelationship.ts +25 -25
  65. package/src/types/DataFormatterSeries.ts +20 -20
  66. package/src/types/DataFormatterTree.ts +12 -12
  67. package/src/types/DataGrid.ts +11 -11
  68. package/src/types/DataMultiGrid.ts +6 -6
  69. package/src/types/DataMultiValue.ts +12 -12
  70. package/src/types/DataRelationship.ts +27 -27
  71. package/src/types/DataSeries.ts +11 -11
  72. package/src/types/DataTree.ts +20 -20
  73. package/src/types/Event.ts +153 -153
  74. package/src/types/Layout.ts +11 -11
  75. package/src/types/Padding.ts +5 -5
  76. package/src/types/Plugin.ts +60 -60
  77. package/src/types/TransformData.ts +7 -7
  78. package/src/types/index.ts +37 -37
  79. package/src/utils/commonUtils.ts +50 -50
  80. package/src/utils/d3Utils.ts +89 -89
  81. package/src/utils/index.ts +4 -4
  82. package/src/utils/observables.ts +201 -201
  83. package/src/utils/orbchartsUtils.ts +349 -349
  84. package/tsconfig.json +13 -13
  85. package/vite.config.js +44 -44
@@ -1,574 +1,574 @@
1
- import {
2
- combineLatest,
3
- distinctUntilChanged,
4
- filter,
5
- map,
6
- merge,
7
- takeUntil,
8
- shareReplay,
9
- switchMap,
10
- Subject,
11
- Observable } from 'rxjs'
12
- import type {
13
- AxisPosition,
14
- ChartType,
15
- ChartParams,
16
- ComputedDataTypeMap,
17
- ComputedDatumTypeMap,
18
- ContextObserverFn,
19
- DataTypeMap,
20
- DataGridDatum,
21
- ComputedDatumGrid,
22
- DataFormatterTypeMap,
23
- DataFormatterGrid,
24
- DataFormatterValueAxis,
25
- DataFormatterGroupAxis,
26
- ComputedLayoutDatumGrid,
27
- ComputedLayoutDataGrid,
28
- GridContainerPosition,
29
- HighlightTarget,
30
- Layout,
31
- TransformData } from '../types'
32
- import { getMinAndMaxGrid } from '../utils/orbchartsUtils'
33
- import { createAxisLinearScale, createAxisPointScale, createAxisQuantizeScale } from '../utils/d3Utils'
34
- import { highlightObservable } from '../utils/observables'
35
- import { calcGridContainerLayout } from '../utils/orbchartsUtils'
36
- import { DATA_FORMATTER_GRID_GRID_DEFAULT } from '../defaults'
37
- import { getMinAndMaxValue, transposeData, createGridSeriesLabels, createGridGroupLabels, seriesColorPredicate } from '../utils/orbchartsUtils'
38
-
39
- export const gridComputedLayoutDataObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
40
- computedData$: Observable<ComputedDataTypeMap<'grid'>>
41
- fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
42
- layout$: Observable<Layout>
43
- }): Observable<ComputedLayoutDatumGrid[][]> => {
44
-
45
- // 未篩選group範圍前的group scale
46
- function createOriginGroupScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
47
- const groupAxisWidth = (dataFormatter.grid.groupAxis.position === 'top' || dataFormatter.grid.groupAxis.position === 'bottom')
48
- ? layout.width
49
- : layout.height
50
- const groupEndIndex = computedData[0] ? computedData[0].length - 1 : 0
51
- const groupScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
52
- maxValue: groupEndIndex,
53
- minValue: 0,
54
- axisWidth: groupAxisWidth,
55
- scaleDomain: [0, groupEndIndex], // 不使用dataFormatter設定
56
- scaleRange: [0, 1] // 不使用dataFormatter設定
57
- })
58
- return groupScale
59
- }
60
-
61
- // 未篩選group範圍及visible前的value scale
62
- function createOriginValueScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
63
- const valueAxisWidth = (dataFormatter.grid.valueAxis.position === 'left' || dataFormatter.grid.valueAxis.position === 'right')
64
- ? layout.height
65
- : layout.width
66
-
67
- const listData = computedData.flat()
68
- const [minValue, maxValue] = getMinAndMaxValue(listData)
69
-
70
- const valueScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
71
- maxValue,
72
- minValue,
73
- axisWidth: valueAxisWidth,
74
- scaleDomain: [minValue, maxValue], // 不使用dataFormatter設定
75
- scaleRange: [0, 1] // 不使用dataFormatter設定
76
- })
77
-
78
- return valueScale
79
- }
80
-
81
- return combineLatest({
82
- computedData: computedData$,
83
- fullDataFormatter: fullDataFormatter$,
84
- layout: layout$
85
- }).pipe(
86
- switchMap(async d => d),
87
- map(data => {
88
- const groupScale = createOriginGroupScale(data.computedData, data.fullDataFormatter, data.layout)
89
- const valueScale = createOriginValueScale(data.computedData, data.fullDataFormatter, data.layout)
90
- const zeroY = valueScale(0)
91
-
92
- return data.computedData.map((seriesData, seriesIndex) => {
93
- return seriesData.map((groupDatum, groupIndex) => {
94
- const axisX = groupScale(groupIndex)
95
- const axisY = valueScale(groupDatum.value ?? 0)
96
- return {
97
- ...groupDatum,
98
- axisX,
99
- axisY,
100
- axisYFromZero: axisY - zeroY
101
- }
102
- })
103
- })
104
- })
105
- )
106
- }
107
-
108
- export const gridAxesTransformObservable = ({ fullDataFormatter$, layout$ }: {
109
- fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
110
- layout$: Observable<Layout>
111
- }): Observable<TransformData> => {
112
- const destroy$ = new Subject()
113
-
114
- function calcAxesTransform ({ xAxis, yAxis, width, height }: {
115
- xAxis: DataFormatterGroupAxis | DataFormatterValueAxis,
116
- yAxis: DataFormatterValueAxis,
117
- width: number,
118
- height: number
119
- }): TransformData {
120
- if (!xAxis || !yAxis) {
121
- return {
122
- translate: [0, 0],
123
- scale: [1, 1],
124
- rotate: 0,
125
- rotateX: 0,
126
- rotateY: 0,
127
- value: ''
128
- }
129
- }
130
- // const width = size.width - fullChartParams.layout.left - fullChartParams.layout.right
131
- // const height = size.height - fullChartParams.layout.top - fullChartParams.layout.bottom
132
- let translateX = 0
133
- let translateY = 0
134
- let rotate = 0
135
- let rotateX = 0
136
- let rotateY = 0
137
- if (xAxis.position === 'bottom') {
138
- if (yAxis.position === 'left') {
139
- rotateX = 180
140
- translateY = height
141
- } else if (yAxis.position === 'right') {
142
- rotateX = 180
143
- rotateY = 180
144
- translateX = width
145
- translateY = height
146
- } else {
147
- // 預設
148
- rotateX = 180
149
- translateY = height
150
- }
151
- } else if (xAxis.position === 'top') {
152
- if (yAxis.position === 'left') {
153
- } else if (yAxis.position === 'right') {
154
- rotateY = 180
155
- translateX = width
156
- } else {
157
- // 預設
158
- rotateX = 180
159
- translateY = height
160
- }
161
- } else if (xAxis.position === 'left') {
162
- if (yAxis.position === 'bottom') {
163
- rotate = -90
164
- translateY = height
165
- } else if (yAxis.position === 'top') {
166
- rotate = -90
167
- rotateY = 180
168
- } else {
169
- // 預設
170
- rotateX = 180
171
- translateY = height
172
- }
173
- } else if (xAxis.position === 'right') {
174
- if (yAxis.position === 'bottom') {
175
- rotate = -90
176
- rotateX = 180
177
- translateY = height
178
- translateX = width
179
- } else if (yAxis.position === 'top') {
180
- rotate = -90
181
- rotateX = 180
182
- rotateY = 180
183
- translateX = width
184
- } else {
185
- // 預設
186
- rotateX = 180
187
- translateY = height
188
- }
189
- }
190
- // selection.style('transform', `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`)
191
-
192
- return {
193
- translate: [translateX, translateY],
194
- scale: [1, 1],
195
- rotate,
196
- rotateX,
197
- rotateY,
198
- value: `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
199
- }
200
- }
201
-
202
- return new Observable(subscriber => {
203
- combineLatest({
204
- fullDataFormatter: fullDataFormatter$,
205
- layout: layout$
206
- }).pipe(
207
- takeUntil(destroy$),
208
- switchMap(async (d) => d),
209
- ).subscribe(data => {
210
- const axesTransformData = calcAxesTransform({
211
- xAxis: data.fullDataFormatter.grid.groupAxis,
212
- yAxis: data.fullDataFormatter.grid.valueAxis,
213
- width: data.layout.width,
214
- height: data.layout.height
215
- })
216
-
217
- subscriber.next(axesTransformData)
218
- })
219
-
220
- return function unscbscribe () {
221
- destroy$.next(undefined)
222
- }
223
- })
224
- }
225
-
226
-
227
- export const gridAxesReverseTransformObservable = ({ gridAxesTransform$ }: {
228
- gridAxesTransform$: Observable<TransformData>
229
- }): Observable<TransformData> => {
230
- return gridAxesTransform$.pipe(
231
- map(d => {
232
- // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
233
- const translate: [number, number] = [0, 0] // 無需逆轉
234
- const scale: [number, number] = [1 / d.scale[0], 1 / d.scale[1]]
235
- const rotate = d.rotate * -1
236
- const rotateX = d.rotateX * -1
237
- const rotateY = d.rotateY * -1
238
- return {
239
- translate,
240
- scale,
241
- rotate,
242
- rotateX,
243
- rotateY,
244
- value: `translate(${translate[0]}px, ${translate[1]}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
245
- }
246
- }),
247
- )
248
- }
249
-
250
- export const gridGraphicTransformObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
251
- computedData$: Observable<ComputedDataTypeMap<'grid'>>
252
- fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
253
- layout$: Observable<Layout>
254
- }): Observable<TransformData> => {
255
- const destroy$ = new Subject()
256
-
257
- function calcGridDataAreaTransform ({ data, groupAxis, valueAxis, width, height }: {
258
- data: ComputedDataTypeMap<'grid'>
259
- groupAxis: DataFormatterGroupAxis
260
- valueAxis: DataFormatterValueAxis
261
- width: number
262
- height: number
263
- }): TransformData {
264
- let translateX = 0
265
- let translateY = 0
266
- let scaleX = 0
267
- let scaleY = 0
268
-
269
- // -- groupScale --
270
- const groupAxisWidth = (groupAxis.position === 'top' || groupAxis.position === 'bottom')
271
- ? width
272
- : height
273
- const groupMin = 0
274
- const groupMax = data[0] ? data[0].length - 1 : 0
275
- const groupScaleDomainMin = groupAxis.scaleDomain[0] === 'auto'
276
- ? groupMin - groupAxis.scalePadding
277
- : groupAxis.scaleDomain[0] as number - groupAxis.scalePadding
278
- const groupScaleDomainMax = groupAxis.scaleDomain[1] === 'auto'
279
- ? groupMax + groupAxis.scalePadding
280
- : groupAxis.scaleDomain[1] as number + groupAxis.scalePadding
281
-
282
- const groupScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
283
- maxValue: groupMax,
284
- minValue: groupMin,
285
- axisWidth: groupAxisWidth,
286
- // scaleDomain: groupAxis.scaleDomain,
287
- scaleDomain: [groupScaleDomainMin, groupScaleDomainMax],
288
- scaleRange: [0, 1]
289
- })
290
-
291
- // -- translateX, scaleX --
292
- const rangeMinX = groupScale(groupMin)
293
- const rangeMaxX = groupScale(groupMax)
294
- if (groupMin == groupMax) {
295
- // 當group只有一個
296
- translateX = 0
297
- scaleX = 1
298
- } else {
299
- translateX = rangeMinX
300
- const gWidth = rangeMaxX - rangeMinX
301
- scaleX = gWidth / groupAxisWidth
302
- }
303
-
304
- // -- valueScale --
305
- const filteredData = data.map((d, i) => {
306
- return d.filter((_d, _i) => {
307
- return _i >= groupScaleDomainMin && _i <= groupScaleDomainMax && _d.visible == true
308
- })
309
- })
310
-
311
- const filteredMinAndMax = getMinAndMaxGrid(filteredData)
312
-
313
- const valueAxisWidth = (valueAxis.position === 'left' || valueAxis.position === 'right')
314
- ? height
315
- : width
316
-
317
- const valueScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
318
- maxValue: filteredMinAndMax[1],
319
- minValue: filteredMinAndMax[0],
320
- axisWidth: valueAxisWidth,
321
- scaleDomain: valueAxis.scaleDomain,
322
- scaleRange: valueAxis.scaleRange
323
- })
324
-
325
- // -- translateY, scaleY --
326
- const minAndMax = getMinAndMaxGrid(data)
327
- const rangeMinY = valueScale(minAndMax[0])
328
- const rangeMaxY = valueScale(minAndMax[1])
329
- translateY = rangeMinY
330
- const gHeight = rangeMaxY - rangeMinY
331
- scaleY = gHeight / valueAxisWidth
332
-
333
- return {
334
- translate: [translateX, translateY],
335
- scale: [scaleX, scaleY],
336
- rotate: 0,
337
- rotateX: 0,
338
- rotateY: 0,
339
- value: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`
340
- }
341
- }
342
-
343
- return new Observable(subscriber => {
344
- combineLatest({
345
- computedData: computedData$,
346
- fullDataFormatter: fullDataFormatter$,
347
- layout: layout$
348
- }).pipe(
349
- takeUntil(destroy$),
350
- switchMap(async (d) => d),
351
- ).subscribe(data => {
352
- const dataAreaTransformData = calcGridDataAreaTransform ({
353
- data: data.computedData,
354
- groupAxis: data.fullDataFormatter.grid.groupAxis,
355
- valueAxis: data.fullDataFormatter.grid.valueAxis,
356
- width: data.layout.width,
357
- height: data.layout.height
358
- })
359
-
360
- subscriber.next(dataAreaTransformData)
361
- })
362
-
363
- return function unscbscribe () {
364
- destroy$.next(undefined)
365
- }
366
- })
367
- }
368
-
369
- export const gridGraphicReverseScaleObservable = ({ gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
370
- gridContainerPosition$: Observable<GridContainerPosition[]>
371
- gridAxesTransform$: Observable<TransformData>
372
- gridGraphicTransform$: Observable<TransformData>
373
- }): Observable<[number, number][]> => {
374
- return combineLatest({
375
- gridContainerPosition: gridContainerPosition$,
376
- gridAxesTransform: gridAxesTransform$,
377
- gridGraphicTransform: gridGraphicTransform$,
378
- }).pipe(
379
- switchMap(async (d) => d),
380
- map(data => {
381
- if (data.gridAxesTransform.rotate == 0 || data.gridAxesTransform.rotate == 180) {
382
- return data.gridContainerPosition.map((series, seriesIndex) => {
383
- return [
384
- 1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[0],
385
- 1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[1],
386
- ]
387
- })
388
- } else {
389
- return data.gridContainerPosition.map((series, seriesIndex) => {
390
- // 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
391
- return [
392
- 1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[1],
393
- 1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[0],
394
- ]
395
- })
396
- }
397
- }),
398
- )
399
- }
400
-
401
- export const gridAxesSizeObservable = ({ fullDataFormatter$, layout$ }: {
402
- fullDataFormatter$: Observable<DataFormatterGrid>
403
- layout$: Observable<Layout>
404
- }): Observable<{
405
- width: number;
406
- height: number;
407
- }> => {
408
- const destroy$ = new Subject()
409
-
410
- function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
411
- xAxisPosition: AxisPosition
412
- yAxisPosition: AxisPosition
413
- width: number
414
- height: number
415
- }) {
416
- if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
417
- return { width, height }
418
- } else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
419
- return {
420
- width: height,
421
- height: width
422
- }
423
- }
424
- }
425
-
426
- return new Observable(subscriber => {
427
- combineLatest({
428
- fullDataFormatter: fullDataFormatter$,
429
- layout: layout$
430
- }).pipe(
431
- takeUntil(destroy$),
432
- switchMap(async (d) => d),
433
- ).subscribe(data => {
434
-
435
- const axisSize = calcAxesSize({
436
- xAxisPosition: data.fullDataFormatter.grid.groupAxis.position,
437
- yAxisPosition: data.fullDataFormatter.grid.valueAxis.position,
438
- width: data.layout.width,
439
- height: data.layout.height,
440
- })
441
-
442
- subscriber.next(axisSize)
443
-
444
- return function unsubscribe () {
445
- destroy$.next(undefined)
446
- }
447
- })
448
- })
449
- }
450
-
451
- // export const gridHighlightObservable = ({ computedData$, fullChartParams$, event$ }: {
452
- // computedData$: Observable<ComputedDataTypeMap<'grid'>>
453
- // fullChartParams$: Observable<ChartParams>
454
- // event$: Subject<any>
455
- // }): Observable<string[]> => {
456
- // const datumList$ = computedData$.pipe(
457
- // map(d => d.flat())
458
- // )
459
- // return highlightObservable ({ datumList$, fullChartParams$, event$ })
460
- // }
461
-
462
- export const seriesLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'grid'>> }) => {
463
- return computedData$.pipe(
464
- map(data => {
465
- return data
466
- .filter(series => series.length)
467
- .map(series => {
468
- return series[0].seriesLabel
469
- })
470
- }),
471
- distinctUntilChanged((a, b) => {
472
- return JSON.stringify(a).length === JSON.stringify(b).length
473
- }),
474
- )
475
- }
476
-
477
- export const gridVisibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'grid'>> }) => {
478
- return computedData$.pipe(
479
- map(data => {
480
- const visibleComputedData = data
481
- .map(d => {
482
- return d.filter(_d => {
483
- return _d.visible == true
484
- })
485
- })
486
- .filter(d => d.length)
487
- return visibleComputedData
488
- })
489
- )
490
- }
491
-
492
- export const gridVisibleComputedLayoutDataObservable = ({ computedLayoutData$ }: { computedLayoutData$: Observable<ComputedLayoutDataGrid> }) => {
493
- return computedLayoutData$.pipe(
494
- map(data => {
495
- const visibleComputedData = data
496
- .map(d => {
497
- return d.filter(_d => {
498
- return _d.visible == true
499
- })
500
- })
501
- .filter(d => d.length)
502
- return visibleComputedData
503
- })
504
- )
505
- }
506
-
507
- // export const isSeriesSeprateObservable = ({ computedData$, fullDataFormatter$ }: {
508
- // computedData$: Observable<ComputedDataTypeMap<'grid'>>
509
- // fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
510
- // }) => {
511
- // return combineLatest({
512
- // computedData: computedData$,
513
- // fullDataFormatter: fullDataFormatter$
514
- // }).pipe(
515
- // map(data => {
516
- // return data.fullDataFormatter.grid.seriesSlotIndexes && data.fullDataFormatter.grid.seriesSlotIndexes.length === data.computedData.length
517
- // ? true
518
- // : false
519
- // }),
520
- // distinctUntilChanged()
521
- // )
522
- // }
523
-
524
- // 所有container位置(對應series)
525
- export const gridContainerPositionObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
526
- computedData$: Observable<ComputedDataTypeMap<'grid'>>
527
- fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
528
- layout$: Observable<Layout>
529
- }): Observable<GridContainerPosition[]> => {
530
-
531
- const gridContainerPosition$ = combineLatest({
532
- computedData: computedData$,
533
- fullDataFormatter: fullDataFormatter$,
534
- layout: layout$,
535
- }).pipe(
536
- switchMap(async (d) => d),
537
- map(data => {
538
-
539
- if (data.fullDataFormatter.grid.separateSeries) {
540
- // -- 依slotIndexes計算 --
541
- return calcGridContainerLayout(data.layout, data.fullDataFormatter.container, data.computedData.length)
542
- // return data.computedData.map((seriesData, seriesIndex) => {
543
- // const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
544
- // const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
545
- // const { translate, scale } = calcGridContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
546
- // return {
547
- // slotIndex: seriesIndex,
548
- // rowIndex,
549
- // columnIndex,
550
- // translate,
551
- // scale,
552
- // }
553
- // })
554
- } else {
555
- // -- 無拆分 --
556
- return calcGridContainerLayout(data.layout, data.fullDataFormatter.container, 1)
557
- // const columnIndex = 0
558
- // const rowIndex = 0
559
- // return data.computedData.map((seriesData, seriesIndex) => {
560
- // const { translate, scale } = calcGridContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
561
- // return {
562
- // slotIndex: 0,
563
- // rowIndex,
564
- // columnIndex,
565
- // translate,
566
- // scale,
567
- // }
568
- // })
569
- }
570
- })
571
- )
572
-
573
- return gridContainerPosition$
1
+ import {
2
+ combineLatest,
3
+ distinctUntilChanged,
4
+ filter,
5
+ map,
6
+ merge,
7
+ takeUntil,
8
+ shareReplay,
9
+ switchMap,
10
+ Subject,
11
+ Observable } from 'rxjs'
12
+ import type {
13
+ AxisPosition,
14
+ ChartType,
15
+ ChartParams,
16
+ ComputedDataTypeMap,
17
+ ComputedDatumTypeMap,
18
+ ContextObserverFn,
19
+ DataTypeMap,
20
+ DataGridDatum,
21
+ ComputedDatumGrid,
22
+ DataFormatterTypeMap,
23
+ DataFormatterGrid,
24
+ DataFormatterValueAxis,
25
+ DataFormatterGroupAxis,
26
+ ComputedLayoutDatumGrid,
27
+ ComputedLayoutDataGrid,
28
+ GridContainerPosition,
29
+ HighlightTarget,
30
+ Layout,
31
+ TransformData } from '../types'
32
+ import { getMinAndMaxGrid } from '../utils/orbchartsUtils'
33
+ import { createAxisLinearScale, createAxisPointScale, createAxisQuantizeScale } from '../utils/d3Utils'
34
+ import { highlightObservable } from '../utils/observables'
35
+ import { calcGridContainerLayout } from '../utils/orbchartsUtils'
36
+ import { DATA_FORMATTER_GRID_GRID_DEFAULT } from '../defaults'
37
+ import { getMinAndMaxValue, transposeData, createGridSeriesLabels, createGridGroupLabels, seriesColorPredicate } from '../utils/orbchartsUtils'
38
+
39
+ export const gridComputedLayoutDataObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
40
+ computedData$: Observable<ComputedDataTypeMap<'grid'>>
41
+ fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
42
+ layout$: Observable<Layout>
43
+ }): Observable<ComputedLayoutDatumGrid[][]> => {
44
+
45
+ // 未篩選group範圍前的group scale
46
+ function createOriginGroupScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
47
+ const groupAxisWidth = (dataFormatter.grid.groupAxis.position === 'top' || dataFormatter.grid.groupAxis.position === 'bottom')
48
+ ? layout.width
49
+ : layout.height
50
+ const groupEndIndex = computedData[0] ? computedData[0].length - 1 : 0
51
+ const groupScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
52
+ maxValue: groupEndIndex,
53
+ minValue: 0,
54
+ axisWidth: groupAxisWidth,
55
+ scaleDomain: [0, groupEndIndex], // 不使用dataFormatter設定
56
+ scaleRange: [0, 1] // 不使用dataFormatter設定
57
+ })
58
+ return groupScale
59
+ }
60
+
61
+ // 未篩選group範圍及visible前的value scale
62
+ function createOriginValueScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
63
+ const valueAxisWidth = (dataFormatter.grid.valueAxis.position === 'left' || dataFormatter.grid.valueAxis.position === 'right')
64
+ ? layout.height
65
+ : layout.width
66
+
67
+ const listData = computedData.flat()
68
+ const [minValue, maxValue] = getMinAndMaxValue(listData)
69
+
70
+ const valueScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
71
+ maxValue,
72
+ minValue,
73
+ axisWidth: valueAxisWidth,
74
+ scaleDomain: [minValue, maxValue], // 不使用dataFormatter設定
75
+ scaleRange: [0, 1] // 不使用dataFormatter設定
76
+ })
77
+
78
+ return valueScale
79
+ }
80
+
81
+ return combineLatest({
82
+ computedData: computedData$,
83
+ fullDataFormatter: fullDataFormatter$,
84
+ layout: layout$
85
+ }).pipe(
86
+ switchMap(async d => d),
87
+ map(data => {
88
+ const groupScale = createOriginGroupScale(data.computedData, data.fullDataFormatter, data.layout)
89
+ const valueScale = createOriginValueScale(data.computedData, data.fullDataFormatter, data.layout)
90
+ const zeroY = valueScale(0)
91
+
92
+ return data.computedData.map((seriesData, seriesIndex) => {
93
+ return seriesData.map((groupDatum, groupIndex) => {
94
+ const axisX = groupScale(groupIndex)
95
+ const axisY = valueScale(groupDatum.value ?? 0)
96
+ return {
97
+ ...groupDatum,
98
+ axisX,
99
+ axisY,
100
+ axisYFromZero: axisY - zeroY
101
+ }
102
+ })
103
+ })
104
+ })
105
+ )
106
+ }
107
+
108
+ export const gridAxesTransformObservable = ({ fullDataFormatter$, layout$ }: {
109
+ fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
110
+ layout$: Observable<Layout>
111
+ }): Observable<TransformData> => {
112
+ const destroy$ = new Subject()
113
+
114
+ function calcAxesTransform ({ xAxis, yAxis, width, height }: {
115
+ xAxis: DataFormatterGroupAxis | DataFormatterValueAxis,
116
+ yAxis: DataFormatterValueAxis,
117
+ width: number,
118
+ height: number
119
+ }): TransformData {
120
+ if (!xAxis || !yAxis) {
121
+ return {
122
+ translate: [0, 0],
123
+ scale: [1, 1],
124
+ rotate: 0,
125
+ rotateX: 0,
126
+ rotateY: 0,
127
+ value: ''
128
+ }
129
+ }
130
+ // const width = size.width - fullChartParams.layout.left - fullChartParams.layout.right
131
+ // const height = size.height - fullChartParams.layout.top - fullChartParams.layout.bottom
132
+ let translateX = 0
133
+ let translateY = 0
134
+ let rotate = 0
135
+ let rotateX = 0
136
+ let rotateY = 0
137
+ if (xAxis.position === 'bottom') {
138
+ if (yAxis.position === 'left') {
139
+ rotateX = 180
140
+ translateY = height
141
+ } else if (yAxis.position === 'right') {
142
+ rotateX = 180
143
+ rotateY = 180
144
+ translateX = width
145
+ translateY = height
146
+ } else {
147
+ // 預設
148
+ rotateX = 180
149
+ translateY = height
150
+ }
151
+ } else if (xAxis.position === 'top') {
152
+ if (yAxis.position === 'left') {
153
+ } else if (yAxis.position === 'right') {
154
+ rotateY = 180
155
+ translateX = width
156
+ } else {
157
+ // 預設
158
+ rotateX = 180
159
+ translateY = height
160
+ }
161
+ } else if (xAxis.position === 'left') {
162
+ if (yAxis.position === 'bottom') {
163
+ rotate = -90
164
+ translateY = height
165
+ } else if (yAxis.position === 'top') {
166
+ rotate = -90
167
+ rotateY = 180
168
+ } else {
169
+ // 預設
170
+ rotateX = 180
171
+ translateY = height
172
+ }
173
+ } else if (xAxis.position === 'right') {
174
+ if (yAxis.position === 'bottom') {
175
+ rotate = -90
176
+ rotateX = 180
177
+ translateY = height
178
+ translateX = width
179
+ } else if (yAxis.position === 'top') {
180
+ rotate = -90
181
+ rotateX = 180
182
+ rotateY = 180
183
+ translateX = width
184
+ } else {
185
+ // 預設
186
+ rotateX = 180
187
+ translateY = height
188
+ }
189
+ }
190
+ // selection.style('transform', `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`)
191
+
192
+ return {
193
+ translate: [translateX, translateY],
194
+ scale: [1, 1],
195
+ rotate,
196
+ rotateX,
197
+ rotateY,
198
+ value: `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
199
+ }
200
+ }
201
+
202
+ return new Observable(subscriber => {
203
+ combineLatest({
204
+ fullDataFormatter: fullDataFormatter$,
205
+ layout: layout$
206
+ }).pipe(
207
+ takeUntil(destroy$),
208
+ switchMap(async (d) => d),
209
+ ).subscribe(data => {
210
+ const axesTransformData = calcAxesTransform({
211
+ xAxis: data.fullDataFormatter.grid.groupAxis,
212
+ yAxis: data.fullDataFormatter.grid.valueAxis,
213
+ width: data.layout.width,
214
+ height: data.layout.height
215
+ })
216
+
217
+ subscriber.next(axesTransformData)
218
+ })
219
+
220
+ return function unscbscribe () {
221
+ destroy$.next(undefined)
222
+ }
223
+ })
224
+ }
225
+
226
+
227
+ export const gridAxesReverseTransformObservable = ({ gridAxesTransform$ }: {
228
+ gridAxesTransform$: Observable<TransformData>
229
+ }): Observable<TransformData> => {
230
+ return gridAxesTransform$.pipe(
231
+ map(d => {
232
+ // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
233
+ const translate: [number, number] = [0, 0] // 無需逆轉
234
+ const scale: [number, number] = [1 / d.scale[0], 1 / d.scale[1]]
235
+ const rotate = d.rotate * -1
236
+ const rotateX = d.rotateX * -1
237
+ const rotateY = d.rotateY * -1
238
+ return {
239
+ translate,
240
+ scale,
241
+ rotate,
242
+ rotateX,
243
+ rotateY,
244
+ value: `translate(${translate[0]}px, ${translate[1]}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
245
+ }
246
+ }),
247
+ )
248
+ }
249
+
250
+ export const gridGraphicTransformObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
251
+ computedData$: Observable<ComputedDataTypeMap<'grid'>>
252
+ fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
253
+ layout$: Observable<Layout>
254
+ }): Observable<TransformData> => {
255
+ const destroy$ = new Subject()
256
+
257
+ function calcGridDataAreaTransform ({ data, groupAxis, valueAxis, width, height }: {
258
+ data: ComputedDataTypeMap<'grid'>
259
+ groupAxis: DataFormatterGroupAxis
260
+ valueAxis: DataFormatterValueAxis
261
+ width: number
262
+ height: number
263
+ }): TransformData {
264
+ let translateX = 0
265
+ let translateY = 0
266
+ let scaleX = 0
267
+ let scaleY = 0
268
+
269
+ // -- groupScale --
270
+ const groupAxisWidth = (groupAxis.position === 'top' || groupAxis.position === 'bottom')
271
+ ? width
272
+ : height
273
+ const groupMin = 0
274
+ const groupMax = data[0] ? data[0].length - 1 : 0
275
+ const groupScaleDomainMin = groupAxis.scaleDomain[0] === 'auto'
276
+ ? groupMin - groupAxis.scalePadding
277
+ : groupAxis.scaleDomain[0] as number - groupAxis.scalePadding
278
+ const groupScaleDomainMax = groupAxis.scaleDomain[1] === 'auto'
279
+ ? groupMax + groupAxis.scalePadding
280
+ : groupAxis.scaleDomain[1] as number + groupAxis.scalePadding
281
+
282
+ const groupScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
283
+ maxValue: groupMax,
284
+ minValue: groupMin,
285
+ axisWidth: groupAxisWidth,
286
+ // scaleDomain: groupAxis.scaleDomain,
287
+ scaleDomain: [groupScaleDomainMin, groupScaleDomainMax],
288
+ scaleRange: [0, 1]
289
+ })
290
+
291
+ // -- translateX, scaleX --
292
+ const rangeMinX = groupScale(groupMin)
293
+ const rangeMaxX = groupScale(groupMax)
294
+ if (groupMin == groupMax) {
295
+ // 當group只有一個
296
+ translateX = 0
297
+ scaleX = 1
298
+ } else {
299
+ translateX = rangeMinX
300
+ const gWidth = rangeMaxX - rangeMinX
301
+ scaleX = gWidth / groupAxisWidth
302
+ }
303
+
304
+ // -- valueScale --
305
+ const filteredData = data.map((d, i) => {
306
+ return d.filter((_d, _i) => {
307
+ return _i >= groupScaleDomainMin && _i <= groupScaleDomainMax && _d.visible == true
308
+ })
309
+ })
310
+
311
+ const filteredMinAndMax = getMinAndMaxGrid(filteredData)
312
+
313
+ const valueAxisWidth = (valueAxis.position === 'left' || valueAxis.position === 'right')
314
+ ? height
315
+ : width
316
+
317
+ const valueScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
318
+ maxValue: filteredMinAndMax[1],
319
+ minValue: filteredMinAndMax[0],
320
+ axisWidth: valueAxisWidth,
321
+ scaleDomain: valueAxis.scaleDomain,
322
+ scaleRange: valueAxis.scaleRange
323
+ })
324
+
325
+ // -- translateY, scaleY --
326
+ const minAndMax = getMinAndMaxGrid(data)
327
+ const rangeMinY = valueScale(minAndMax[0])
328
+ const rangeMaxY = valueScale(minAndMax[1])
329
+ translateY = rangeMinY
330
+ const gHeight = rangeMaxY - rangeMinY
331
+ scaleY = gHeight / valueAxisWidth
332
+
333
+ return {
334
+ translate: [translateX, translateY],
335
+ scale: [scaleX, scaleY],
336
+ rotate: 0,
337
+ rotateX: 0,
338
+ rotateY: 0,
339
+ value: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`
340
+ }
341
+ }
342
+
343
+ return new Observable(subscriber => {
344
+ combineLatest({
345
+ computedData: computedData$,
346
+ fullDataFormatter: fullDataFormatter$,
347
+ layout: layout$
348
+ }).pipe(
349
+ takeUntil(destroy$),
350
+ switchMap(async (d) => d),
351
+ ).subscribe(data => {
352
+ const dataAreaTransformData = calcGridDataAreaTransform ({
353
+ data: data.computedData,
354
+ groupAxis: data.fullDataFormatter.grid.groupAxis,
355
+ valueAxis: data.fullDataFormatter.grid.valueAxis,
356
+ width: data.layout.width,
357
+ height: data.layout.height
358
+ })
359
+
360
+ subscriber.next(dataAreaTransformData)
361
+ })
362
+
363
+ return function unscbscribe () {
364
+ destroy$.next(undefined)
365
+ }
366
+ })
367
+ }
368
+
369
+ export const gridGraphicReverseScaleObservable = ({ gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
370
+ gridContainerPosition$: Observable<GridContainerPosition[]>
371
+ gridAxesTransform$: Observable<TransformData>
372
+ gridGraphicTransform$: Observable<TransformData>
373
+ }): Observable<[number, number][]> => {
374
+ return combineLatest({
375
+ gridContainerPosition: gridContainerPosition$,
376
+ gridAxesTransform: gridAxesTransform$,
377
+ gridGraphicTransform: gridGraphicTransform$,
378
+ }).pipe(
379
+ switchMap(async (d) => d),
380
+ map(data => {
381
+ if (data.gridAxesTransform.rotate == 0 || data.gridAxesTransform.rotate == 180) {
382
+ return data.gridContainerPosition.map((series, seriesIndex) => {
383
+ return [
384
+ 1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[0],
385
+ 1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[1],
386
+ ]
387
+ })
388
+ } else {
389
+ return data.gridContainerPosition.map((series, seriesIndex) => {
390
+ // 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
391
+ return [
392
+ 1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[1],
393
+ 1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[0],
394
+ ]
395
+ })
396
+ }
397
+ }),
398
+ )
399
+ }
400
+
401
+ export const gridAxesSizeObservable = ({ fullDataFormatter$, layout$ }: {
402
+ fullDataFormatter$: Observable<DataFormatterGrid>
403
+ layout$: Observable<Layout>
404
+ }): Observable<{
405
+ width: number;
406
+ height: number;
407
+ }> => {
408
+ const destroy$ = new Subject()
409
+
410
+ function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
411
+ xAxisPosition: AxisPosition
412
+ yAxisPosition: AxisPosition
413
+ width: number
414
+ height: number
415
+ }) {
416
+ if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
417
+ return { width, height }
418
+ } else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
419
+ return {
420
+ width: height,
421
+ height: width
422
+ }
423
+ }
424
+ }
425
+
426
+ return new Observable(subscriber => {
427
+ combineLatest({
428
+ fullDataFormatter: fullDataFormatter$,
429
+ layout: layout$
430
+ }).pipe(
431
+ takeUntil(destroy$),
432
+ switchMap(async (d) => d),
433
+ ).subscribe(data => {
434
+
435
+ const axisSize = calcAxesSize({
436
+ xAxisPosition: data.fullDataFormatter.grid.groupAxis.position,
437
+ yAxisPosition: data.fullDataFormatter.grid.valueAxis.position,
438
+ width: data.layout.width,
439
+ height: data.layout.height,
440
+ })
441
+
442
+ subscriber.next(axisSize)
443
+
444
+ return function unsubscribe () {
445
+ destroy$.next(undefined)
446
+ }
447
+ })
448
+ })
449
+ }
450
+
451
+ // export const gridHighlightObservable = ({ computedData$, fullChartParams$, event$ }: {
452
+ // computedData$: Observable<ComputedDataTypeMap<'grid'>>
453
+ // fullChartParams$: Observable<ChartParams>
454
+ // event$: Subject<any>
455
+ // }): Observable<string[]> => {
456
+ // const datumList$ = computedData$.pipe(
457
+ // map(d => d.flat())
458
+ // )
459
+ // return highlightObservable ({ datumList$, fullChartParams$, event$ })
460
+ // }
461
+
462
+ export const seriesLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'grid'>> }) => {
463
+ return computedData$.pipe(
464
+ map(data => {
465
+ return data
466
+ .filter(series => series.length)
467
+ .map(series => {
468
+ return series[0].seriesLabel
469
+ })
470
+ }),
471
+ distinctUntilChanged((a, b) => {
472
+ return JSON.stringify(a).length === JSON.stringify(b).length
473
+ }),
474
+ )
475
+ }
476
+
477
+ export const gridVisibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'grid'>> }) => {
478
+ return computedData$.pipe(
479
+ map(data => {
480
+ const visibleComputedData = data
481
+ .map(d => {
482
+ return d.filter(_d => {
483
+ return _d.visible == true
484
+ })
485
+ })
486
+ .filter(d => d.length)
487
+ return visibleComputedData
488
+ })
489
+ )
490
+ }
491
+
492
+ export const gridVisibleComputedLayoutDataObservable = ({ computedLayoutData$ }: { computedLayoutData$: Observable<ComputedLayoutDataGrid> }) => {
493
+ return computedLayoutData$.pipe(
494
+ map(data => {
495
+ const visibleComputedData = data
496
+ .map(d => {
497
+ return d.filter(_d => {
498
+ return _d.visible == true
499
+ })
500
+ })
501
+ .filter(d => d.length)
502
+ return visibleComputedData
503
+ })
504
+ )
505
+ }
506
+
507
+ // export const isSeriesSeprateObservable = ({ computedData$, fullDataFormatter$ }: {
508
+ // computedData$: Observable<ComputedDataTypeMap<'grid'>>
509
+ // fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
510
+ // }) => {
511
+ // return combineLatest({
512
+ // computedData: computedData$,
513
+ // fullDataFormatter: fullDataFormatter$
514
+ // }).pipe(
515
+ // map(data => {
516
+ // return data.fullDataFormatter.grid.seriesSlotIndexes && data.fullDataFormatter.grid.seriesSlotIndexes.length === data.computedData.length
517
+ // ? true
518
+ // : false
519
+ // }),
520
+ // distinctUntilChanged()
521
+ // )
522
+ // }
523
+
524
+ // 所有container位置(對應series)
525
+ export const gridContainerPositionObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
526
+ computedData$: Observable<ComputedDataTypeMap<'grid'>>
527
+ fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
528
+ layout$: Observable<Layout>
529
+ }): Observable<GridContainerPosition[]> => {
530
+
531
+ const gridContainerPosition$ = combineLatest({
532
+ computedData: computedData$,
533
+ fullDataFormatter: fullDataFormatter$,
534
+ layout: layout$,
535
+ }).pipe(
536
+ switchMap(async (d) => d),
537
+ map(data => {
538
+
539
+ if (data.fullDataFormatter.grid.separateSeries) {
540
+ // -- 依slotIndexes計算 --
541
+ return calcGridContainerLayout(data.layout, data.fullDataFormatter.container, data.computedData.length)
542
+ // return data.computedData.map((seriesData, seriesIndex) => {
543
+ // const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
544
+ // const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
545
+ // const { translate, scale } = calcGridContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
546
+ // return {
547
+ // slotIndex: seriesIndex,
548
+ // rowIndex,
549
+ // columnIndex,
550
+ // translate,
551
+ // scale,
552
+ // }
553
+ // })
554
+ } else {
555
+ // -- 無拆分 --
556
+ return calcGridContainerLayout(data.layout, data.fullDataFormatter.container, 1)
557
+ // const columnIndex = 0
558
+ // const rowIndex = 0
559
+ // return data.computedData.map((seriesData, seriesIndex) => {
560
+ // const { translate, scale } = calcGridContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
561
+ // return {
562
+ // slotIndex: 0,
563
+ // rowIndex,
564
+ // columnIndex,
565
+ // translate,
566
+ // scale,
567
+ // }
568
+ // })
569
+ }
570
+ })
571
+ )
572
+
573
+ return gridContainerPosition$
574
574
  }