@orbcharts/plugins-basic 3.0.0-alpha.68 → 3.0.0-alpha.69

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +3436 -3358
  3. package/dist/orbcharts-plugins-basic.umd.js +14 -13
  4. package/dist/src/utils/d3Graphics.d.ts +10 -0
  5. package/package.json +42 -42
  6. package/src/base/BaseBarStack.ts +779 -779
  7. package/src/base/BaseBars.ts +764 -764
  8. package/src/base/BaseBarsTriangle.ts +672 -672
  9. package/src/base/BaseDots.ts +513 -513
  10. package/src/base/BaseGroupAxis.ts +675 -652
  11. package/src/base/BaseLegend.ts +642 -642
  12. package/src/base/BaseLineAreas.ts +628 -628
  13. package/src/base/BaseLines.ts +704 -704
  14. package/src/base/BaseValueAxis.ts +578 -578
  15. package/src/base/types.ts +2 -2
  16. package/src/grid/defaults.ts +128 -128
  17. package/src/grid/gridObservables.ts +543 -543
  18. package/src/grid/index.ts +15 -15
  19. package/src/grid/plugins/BarStack.ts +43 -43
  20. package/src/grid/plugins/Bars.ts +44 -44
  21. package/src/grid/plugins/BarsPN.ts +41 -41
  22. package/src/grid/plugins/BarsTriangle.ts +42 -42
  23. package/src/grid/plugins/Dots.ts +37 -37
  24. package/src/grid/plugins/GridLegend.ts +59 -59
  25. package/src/grid/plugins/GroupAux.ts +1014 -991
  26. package/src/grid/plugins/GroupAxis.ts +36 -36
  27. package/src/grid/plugins/LineAreas.ts +40 -40
  28. package/src/grid/plugins/Lines.ts +40 -40
  29. package/src/grid/plugins/ScalingArea.ts +174 -174
  30. package/src/grid/plugins/ValueAxis.ts +36 -36
  31. package/src/grid/plugins/ValueStackAxis.ts +38 -38
  32. package/src/grid/types.ts +123 -123
  33. package/src/index.ts +9 -9
  34. package/src/multiGrid/defaults.ts +158 -158
  35. package/src/multiGrid/index.ts +13 -13
  36. package/src/multiGrid/multiGridObservables.ts +49 -49
  37. package/src/multiGrid/plugins/MultiBarStack.ts +78 -78
  38. package/src/multiGrid/plugins/MultiBars.ts +77 -77
  39. package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -77
  40. package/src/multiGrid/plugins/MultiDots.ts +65 -65
  41. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
  42. package/src/multiGrid/plugins/MultiGroupAxis.ts +70 -70
  43. package/src/multiGrid/plugins/MultiLineAreas.ts +77 -77
  44. package/src/multiGrid/plugins/MultiLines.ts +77 -77
  45. package/src/multiGrid/plugins/MultiValueAxis.ts +69 -69
  46. package/src/multiGrid/plugins/MultiValueStackAxis.ts +69 -69
  47. package/src/multiGrid/plugins/OverlappingValueAxes.ts +170 -170
  48. package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +169 -169
  49. package/src/multiGrid/types.ts +72 -72
  50. package/src/noneData/defaults.ts +102 -102
  51. package/src/noneData/index.ts +3 -3
  52. package/src/noneData/plugins/Container.ts +10 -10
  53. package/src/noneData/plugins/Tooltip.ts +327 -327
  54. package/src/noneData/types.ts +26 -26
  55. package/src/series/defaults.ts +149 -149
  56. package/src/series/index.ts +9 -9
  57. package/src/series/plugins/Bubbles.ts +545 -545
  58. package/src/series/plugins/Pie.ts +584 -584
  59. package/src/series/plugins/PieEventTexts.ts +262 -262
  60. package/src/series/plugins/PieLabels.ts +604 -598
  61. package/src/series/plugins/Rose.ts +481 -481
  62. package/src/series/plugins/RoseLabels.ts +571 -565
  63. package/src/series/plugins/SeriesLegend.ts +59 -59
  64. package/src/series/seriesObservables.ts +145 -145
  65. package/src/series/seriesUtils.ts +51 -51
  66. package/src/series/types.ts +87 -87
  67. package/src/tree/defaults.ts +23 -23
  68. package/src/tree/index.ts +3 -3
  69. package/src/tree/plugins/TreeLegend.ts +59 -59
  70. package/src/tree/plugins/TreeMap.ts +305 -305
  71. package/src/tree/types.ts +23 -23
  72. package/src/utils/commonUtils.ts +21 -21
  73. package/src/utils/d3Graphics.ts +174 -124
  74. package/src/utils/d3Utils.ts +73 -73
  75. package/src/utils/observables.ts +14 -14
  76. package/src/utils/orbchartsUtils.ts +100 -100
  77. package/tsconfig.base.json +13 -13
  78. package/tsconfig.json +2 -2
  79. package/vite.config.js +22 -22
@@ -1,544 +1,544 @@
1
- import * as d3 from 'd3'
2
- import {
3
- Observable,
4
- Subject,
5
- of,
6
- takeUntil,
7
- filter,
8
- map,
9
- switchMap,
10
- combineLatest,
11
- merge,
12
- shareReplay,
13
- distinctUntilChanged
14
- } from 'rxjs'
15
- import type {
16
- ChartParams,
17
- HighlightTarget,
18
- DataFormatterGrid,
19
- ComputedDataGrid,
20
- ComputedDatumGrid,
21
- TransformData,
22
- GridContainerPosition,
23
- Layout } from '@orbcharts/core'
24
- import { createAxisQuantizeScale } from '@orbcharts/core'
25
- import { getClassName, getUniID } from '../utils/orbchartsUtils'
26
- import { d3EventObservable } from '../utils/observables'
27
-
28
- // grid選取器
29
- export const gridSelectionsObservable = ({ selection, pluginName, clipPathID, seriesLabels$, gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
30
- selection: d3.Selection<any, unknown, any, unknown>
31
- pluginName: string
32
- clipPathID: string
33
- // computedData$: Observable<ComputedDataGrid>
34
- seriesLabels$: Observable<string[]>
35
- gridContainerPosition$: Observable<GridContainerPosition[]>
36
- gridAxesTransform$: Observable<TransformData>
37
- gridGraphicTransform$: Observable<TransformData>
38
- }) => {
39
- const seriesClassName = getClassName(pluginName, 'series')
40
- const axesClassName = getClassName(pluginName, 'axes')
41
- const graphicClassName = getClassName(pluginName, 'graphic')
42
-
43
- const seriesSelection$ = seriesLabels$.pipe(
44
- map((existSeriesLabels, i) => {
45
- return selection
46
- .selectAll<SVGGElement, string>(`g.${seriesClassName}`)
47
- .data(existSeriesLabels, d => d)
48
- .join(
49
- enter => {
50
- return enter
51
- .append('g')
52
- .classed(seriesClassName, true)
53
- .each((d, i, g) => {
54
- const axesSelection = d3.select(g[i])
55
- .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${axesClassName}`)
56
- .data([i])
57
- .join(
58
- enter => {
59
- return enter
60
- .append('g')
61
- .classed(axesClassName, true)
62
- .attr('clip-path', `url(#${clipPathID})`)
63
- .each((d, i, g) => {
64
- const defsSelection = d3.select(g[i])
65
- .selectAll<SVGDefsElement, any>('defs')
66
- .data([i])
67
- .join('defs')
68
-
69
- const graphicGSelection = d3.select(g[i])
70
- .selectAll<SVGGElement, any>('g')
71
- .data([i])
72
- .join('g')
73
- .classed(graphicClassName, true)
74
- })
75
- },
76
- update => update,
77
- exit => exit.remove()
78
- )
79
- })
80
- },
81
- update => update,
82
- exit => exit.remove()
83
- )
84
- }),
85
- shareReplay(1)
86
- )
87
-
88
- combineLatest({
89
- seriesSelection: seriesSelection$,
90
- gridContainerPosition: gridContainerPosition$
91
- }).pipe(
92
- switchMap(async d => d)
93
- ).subscribe(data => {
94
- data.seriesSelection
95
- .transition()
96
- .attr('transform', (d, i) => {
97
- const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
98
- const translate = gridContainerPosition.translate
99
- const scale = gridContainerPosition.scale
100
- return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
101
- })
102
- })
103
-
104
- const axesSelection$ = combineLatest({
105
- seriesSelection: seriesSelection$,
106
- gridAxesTransform: gridAxesTransform$
107
- }).pipe(
108
- switchMap(async d => d),
109
- map(data => {
110
- return data.seriesSelection
111
- .select<SVGGElement>(`g.${axesClassName}`)
112
- .style('transform', data.gridAxesTransform.value)
113
- }),
114
- shareReplay(1)
115
- )
116
- const defsSelection$ = axesSelection$.pipe(
117
- map(axesSelection => {
118
- return axesSelection.select<SVGDefsElement>('defs')
119
- }),
120
- shareReplay(1)
121
- )
122
- const graphicGSelection$ = combineLatest({
123
- axesSelection: axesSelection$,
124
- gridGraphicTransform: gridGraphicTransform$
125
- }).pipe(
126
- switchMap(async d => d),
127
- map(data => {
128
- const graphicGSelection = data.axesSelection
129
- .select<SVGGElement>(`g.${graphicClassName}`)
130
- graphicGSelection
131
- .transition()
132
- .duration(50)
133
- .style('transform', data.gridGraphicTransform.value)
134
- return graphicGSelection
135
- }),
136
- shareReplay(1)
137
- )
138
-
139
- return {
140
- seriesSelection$,
141
- axesSelection$,
142
- defsSelection$,
143
- graphicGSelection$
144
- }
145
- }
146
-
147
- // 由事件取得group data的function
148
- // @Q@ 之後重構改用 gridGroupPosition
149
- export const gridGroupPositionFnObservable = ({ fullDataFormatter$, gridAxesSize$, computedData$, fullChartParams$, gridContainerPosition$, layout$ }: {
150
- fullDataFormatter$: Observable<DataFormatterGrid>
151
- gridAxesSize$: Observable<{
152
- width: number;
153
- height: number;
154
- }>
155
- computedData$: Observable<ComputedDataGrid>
156
- // GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
157
- fullChartParams$: Observable<ChartParams>
158
- gridContainerPosition$: Observable<GridContainerPosition[]>
159
- layout$: Observable<Layout>
160
- }): Observable<(event: any) => { groupIndex: number; groupLabel: string }> => {
161
- const destroy$ = new Subject()
162
-
163
- // 顯示範圍內的group labels
164
- // const scaleRangeGroupLabels$: Observable<string[]> = new Observable(subscriber => {
165
- // combineLatest({
166
- // dataFormatter: fullDataFormatter$,
167
- // computedData: computedData$
168
- // }).pipe(
169
- // takeUntil(destroy$),
170
- // switchMap(async (d) => d),
171
- // ).subscribe(data => {
172
- // const groupMin = 0
173
- // const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
174
- // const groupScaleDomainMin = data.dataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
175
- // ? groupMin - data.dataFormatter.grid.groupAxis.scalePadding
176
- // : data.dataFormatter.grid.groupAxis.scaleDomain[0] as number - data.dataFormatter.grid.groupAxis.scalePadding
177
- // const groupScaleDomainMax = data.dataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
178
- // ? groupMax + data.dataFormatter.grid.groupAxis.scalePadding
179
- // : data.dataFormatter.grid.groupAxis.scaleDomain[1] as number + data.dataFormatter.grid.groupAxis.scalePadding
180
-
181
- // // const groupingAmount = data.computedData[0]
182
- // // ? data.computedData[0].length
183
- // // : 0
184
-
185
- // let _labels = data.dataFormatter.grid.seriesDirection === 'row'
186
- // ? (data.computedData[0] ?? []).map(d => d.groupLabel)
187
- // : data.computedData.map(d => d[0].groupLabel)
188
-
189
- // const _axisLabels =
190
- // // new Array(groupingAmount).fill(0)
191
- // // .map((d, i) => {
192
- // // return _labels[i] != null
193
- // // ? _labels[i]
194
- // // : String(i) // 沒有label則用序列號填充
195
- // // })
196
- // _labels
197
- // .filter((d, i) => {
198
- // return i >= groupScaleDomainMin && i <= groupScaleDomainMax
199
- // })
200
- // subscriber.next(_axisLabels)
201
- // })
202
- // })
203
- const groupScaleDomain$ = combineLatest({
204
- fullDataFormatter: fullDataFormatter$,
205
- gridAxesSize: gridAxesSize$,
206
- computedData: computedData$
207
- }).pipe(
208
- switchMap(async (d) => d),
209
- map(data => {
210
- const groupMin = 0
211
- const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
212
- // const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
213
- // ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
214
- // : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
215
- const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] - data.fullDataFormatter.grid.groupAxis.scalePadding
216
- const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'max'
217
- ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
218
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
219
-
220
- return [groupScaleDomainMin, groupScaleDomainMax]
221
- }),
222
- shareReplay(1)
223
- )
224
-
225
- const groupLabels$ = combineLatest({
226
- fullDataFormatter: fullDataFormatter$,
227
- computedData: computedData$
228
- }).pipe(
229
- switchMap(async d => d),
230
- map(data => {
231
- return data.fullDataFormatter.grid.seriesDirection === 'row'
232
- ? (data.computedData[0] ?? []).map(d => d.groupLabel)
233
- : data.computedData.map(d => d[0].groupLabel)
234
- })
235
- )
236
-
237
- // 顯示範圍內的group labels
238
- const scaleRangeGroupLabels$ = combineLatest({
239
- groupScaleDomain: groupScaleDomain$,
240
- groupLabels: groupLabels$
241
- }).pipe(
242
- switchMap(async d => d),
243
- map(data => {
244
- return data.groupLabels
245
- .filter((d, i) => {
246
- return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
247
- })
248
- })
249
- )
250
-
251
- const columnAmount$ = gridContainerPosition$.pipe(
252
- map(gridContainerPosition => {
253
- const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
254
- return current.columnIndex > acc ? current.columnIndex : acc
255
- }, 0)
256
- return maxColumnIndex + 1
257
- }),
258
- distinctUntilChanged()
259
- )
260
-
261
- const rowAmount$ = gridContainerPosition$.pipe(
262
- map(gridContainerPosition => {
263
- const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
264
- return current.rowIndex > acc ? current.rowIndex : acc
265
- }, 0)
266
- return maxRowIndex + 1
267
- }),
268
- distinctUntilChanged()
269
- )
270
-
271
- return new Observable<(event: any) => { groupIndex: number; groupLabel: string }>(subscriber => {
272
- combineLatest({
273
- dataFormatter: fullDataFormatter$,
274
- axisSize: gridAxesSize$,
275
- fullChartParams: fullChartParams$,
276
- scaleRangeGroupLabels: scaleRangeGroupLabels$,
277
- groupScaleDomain: groupScaleDomain$,
278
- columnAmount: columnAmount$,
279
- rowAmount: rowAmount$,
280
- layout: layout$
281
- }).pipe(
282
- takeUntil(destroy$),
283
- switchMap(async (d) => d),
284
- ).subscribe(data => {
285
-
286
- const reverse = data.dataFormatter.grid.valueAxis.position === 'right'
287
- || data.dataFormatter.grid.valueAxis.position === 'bottom'
288
- ? true : false
289
-
290
- // 比例尺座標對應非連續資料索引
291
- const xIndexScale = createAxisQuantizeScale({
292
- axisLabels: data.scaleRangeGroupLabels,
293
- axisWidth: data.axisSize.width,
294
- padding: data.dataFormatter.grid.groupAxis.scalePadding,
295
- reverse
296
- })
297
-
298
- // 依比例尺位置計算座標
299
- const axisValuePredicate = (event: any) => {
300
- return data.dataFormatter.grid.groupAxis.position === 'bottom'
301
- || data.dataFormatter.grid.groupAxis.position === 'top'
302
- ? event.offsetX - data.fullChartParams.padding.left
303
- : event.offsetY - data.fullChartParams.padding.top
304
- }
305
-
306
- // 比例尺座標取得groupData的function
307
- const createEventGroupData: (event: any) => { groupIndex: number; groupLabel: string } = (event: any) => {
308
- // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
309
- const eventData = {
310
- offsetX: event.offsetX * data.columnAmount % data.layout.rootWidth,
311
- offsetY: event.offsetY * data.rowAmount % data.layout.rootHeight
312
- }
313
- // console.log('data.columnAmount', data.columnAmount, 'data.rowAmount', data.rowAmount, 'data.layout.rootWidth', data.layout.rootWidth, 'data.layout.rootHeight', data.layout.rootHeight)
314
- const axisValue = axisValuePredicate(eventData)
315
- const xIndex = xIndexScale(axisValue)
316
- const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
317
- const groupIndex = xIndex + currentxIndexStart
318
- return {
319
- groupIndex,
320
- groupLabel: data.scaleRangeGroupLabels[groupIndex] ?? ''
321
- }
322
- }
323
-
324
- subscriber.next(createEventGroupData)
325
-
326
- return function unsubscribe () {
327
- destroy$.next(undefined)
328
- }
329
- })
330
- })
331
- }
332
-
333
- export const gridGroupPosition = ({ rootSelection, fullDataFormatter$, gridAxesSize$, computedData$, fullChartParams$, gridContainerPosition$, layout$ }: {
334
- rootSelection: d3.Selection<any, unknown, any, unknown>
335
- fullDataFormatter$: Observable<DataFormatterGrid>
336
- gridAxesSize$: Observable<{
337
- width: number;
338
- height: number;
339
- }>
340
- computedData$: Observable<ComputedDataGrid>
341
- fullChartParams$: Observable<ChartParams>
342
- gridContainerPosition$: Observable<GridContainerPosition[]>
343
- layout$: Observable<Layout>
344
- }) => {
345
- const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove')
346
-
347
- const groupScaleDomain$ = combineLatest({
348
- fullDataFormatter: fullDataFormatter$,
349
- gridAxesSize: gridAxesSize$,
350
- computedData: computedData$
351
- }).pipe(
352
- switchMap(async (d) => d),
353
- map(data => {
354
- const groupMin = 0
355
- const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
356
- // const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
357
- // ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
358
- // : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
359
- const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] - data.fullDataFormatter.grid.groupAxis.scalePadding
360
- const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'max'
361
- ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
362
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
363
-
364
- return [groupScaleDomainMin, groupScaleDomainMax]
365
- }),
366
- shareReplay(1)
367
- )
368
-
369
- const groupLabels$ = combineLatest({
370
- fullDataFormatter: fullDataFormatter$,
371
- computedData: computedData$
372
- }).pipe(
373
- switchMap(async d => d),
374
- map(data => {
375
- return data.fullDataFormatter.grid.seriesDirection === 'row'
376
- ? (data.computedData[0] ?? []).map(d => d.groupLabel)
377
- : data.computedData.map(d => d[0].groupLabel)
378
- })
379
- )
380
-
381
- const scaleRangeGroupLabels$ = combineLatest({
382
- groupScaleDomain: groupScaleDomain$,
383
- groupLabels: groupLabels$
384
- }).pipe(
385
- switchMap(async d => d),
386
- map(data => {
387
- return data.groupLabels
388
- .filter((d, i) => {
389
- return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
390
- })
391
- })
392
- )
393
-
394
- const reverse$ = fullDataFormatter$.pipe(
395
- map(d => {
396
- return d.grid.valueAxis.position === 'right' || d.grid.valueAxis.position === 'bottom'
397
- ? true
398
- : false
399
- })
400
- )
401
-
402
- // 比例尺座標對應非連續資料索引
403
- const xIndexScale$ = combineLatest({
404
- reverse: reverse$,
405
- gridAxesSize: gridAxesSize$,
406
- scaleRangeGroupLabels: scaleRangeGroupLabels$,
407
- fullDataFormatter: fullDataFormatter$
408
- }).pipe(
409
- switchMap(async d => d),
410
- map(data => {
411
- return createAxisQuantizeScale({
412
- axisLabels: data.scaleRangeGroupLabels,
413
- axisWidth: data.gridAxesSize.width,
414
- padding: data.fullDataFormatter.grid.groupAxis.scalePadding,
415
- reverse: data.reverse
416
- })
417
- })
418
- )
419
-
420
- const columnAmount$ = gridContainerPosition$.pipe(
421
- map(gridContainerPosition => {
422
- const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
423
- return current.columnIndex > acc ? current.columnIndex : acc
424
- }, 0)
425
- return maxColumnIndex + 1
426
- }),
427
- distinctUntilChanged()
428
- )
429
-
430
- const rowAmount$ = gridContainerPosition$.pipe(
431
- map(gridContainerPosition => {
432
- const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
433
- return current.rowIndex > acc ? current.rowIndex : acc
434
- }, 0)
435
- return maxRowIndex + 1
436
- }),
437
- distinctUntilChanged()
438
- )
439
-
440
- const axisValue$ = combineLatest({
441
- fullDataFormatter: fullDataFormatter$,
442
- fullChartParams: fullChartParams$,
443
- rootMousemove: rootMousemove$,
444
- columnAmount: columnAmount$,
445
- rowAmount: rowAmount$,
446
- layout: layout$
447
- }).pipe(
448
- switchMap(async d => d),
449
- map(data => {
450
- // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
451
- const eventData = {
452
- offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
453
- offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
454
- }
455
- return data.fullDataFormatter.grid.groupAxis.position === 'bottom'
456
- || data.fullDataFormatter.grid.groupAxis.position === 'top'
457
- ? eventData.offsetX - data.fullChartParams.padding.left
458
- : eventData.offsetY - data.fullChartParams.padding.top
459
- })
460
- )
461
-
462
- const groupIndex$ = combineLatest({
463
- xIndexScale: xIndexScale$,
464
- axisValue: axisValue$,
465
- groupScaleDomain: groupScaleDomain$
466
- }).pipe(
467
- switchMap(async d => d),
468
- map(data => {
469
- const xIndex = data.xIndexScale(data.axisValue)
470
- const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
471
- return xIndex + currentxIndexStart
472
- })
473
- )
474
-
475
- const groupLabel$ = combineLatest({
476
- groupIndex: groupIndex$,
477
- groupLabels: groupLabels$
478
- }).pipe(
479
- switchMap(async d => d),
480
- map(data => {
481
- return data.groupLabels[data.groupIndex] ?? ''
482
- })
483
- )
484
-
485
- return combineLatest({
486
- groupIndex: groupIndex$,
487
- groupLabel: groupLabel$
488
- }).pipe(
489
- switchMap(async d => d),
490
- map(data => {
491
- return {
492
- groupIndex: data.groupIndex,
493
- groupLabel: data.groupLabel
494
- }
495
- })
496
- )
497
- }
498
-
499
- // const gridContainerEventData$ = ({ eventData$, gridContainerPosition$, layout$ }: {
500
- // eventData$: Observable<any>
501
- // gridContainerPosition$: Observable<GridContainerPosition[]>
502
- // layout$: Observable<Layout>
503
- // }): Observable<{
504
- // offsetX: number;
505
- // offsetY: number;
506
- // }> => {
507
- // const columnAmount$ = gridContainerPosition$.pipe(
508
- // map(gridContainerPosition => {
509
- // const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
510
- // return current.columnIndex > acc ? current.columnIndex : acc
511
- // }, 0)
512
- // return maxColumnIndex + 1
513
- // }),
514
- // distinctUntilChanged()
515
- // )
516
-
517
- // const rowAmount$ = gridContainerPosition$.pipe(
518
- // map(gridContainerPosition => {
519
- // const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
520
- // return current.rowIndex > acc ? current.rowIndex : acc
521
- // }, 0)
522
- // return maxRowIndex + 1
523
- // }),
524
- // distinctUntilChanged()
525
- // )
526
-
527
- // return combineLatest({
528
- // eventData: eventData$,
529
- // gridContainerPosition: gridContainerPosition$,
530
- // layout: layout$,
531
- // columnAmount: columnAmount$,
532
- // rowAmount: rowAmount$
533
- // }).pipe(
534
- // switchMap(async d => d),
535
- // map(data => {
536
- // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
537
- // const eventData = {
538
- // offsetX: data.eventData.offsetX * data.columnAmount % data.layout.rootWidth,
539
- // offsetY: data.eventData.offsetY * data.rowAmount % data.layout.rootHeight
540
- // }
541
- // return eventData
542
- // })
543
- // )
1
+ import * as d3 from 'd3'
2
+ import {
3
+ Observable,
4
+ Subject,
5
+ of,
6
+ takeUntil,
7
+ filter,
8
+ map,
9
+ switchMap,
10
+ combineLatest,
11
+ merge,
12
+ shareReplay,
13
+ distinctUntilChanged
14
+ } from 'rxjs'
15
+ import type {
16
+ ChartParams,
17
+ HighlightTarget,
18
+ DataFormatterGrid,
19
+ ComputedDataGrid,
20
+ ComputedDatumGrid,
21
+ TransformData,
22
+ GridContainerPosition,
23
+ Layout } from '@orbcharts/core'
24
+ import { createAxisQuantizeScale } from '@orbcharts/core'
25
+ import { getClassName, getUniID } from '../utils/orbchartsUtils'
26
+ import { d3EventObservable } from '../utils/observables'
27
+
28
+ // grid選取器
29
+ export const gridSelectionsObservable = ({ selection, pluginName, clipPathID, seriesLabels$, gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
30
+ selection: d3.Selection<any, unknown, any, unknown>
31
+ pluginName: string
32
+ clipPathID: string
33
+ // computedData$: Observable<ComputedDataGrid>
34
+ seriesLabels$: Observable<string[]>
35
+ gridContainerPosition$: Observable<GridContainerPosition[]>
36
+ gridAxesTransform$: Observable<TransformData>
37
+ gridGraphicTransform$: Observable<TransformData>
38
+ }) => {
39
+ const seriesClassName = getClassName(pluginName, 'series')
40
+ const axesClassName = getClassName(pluginName, 'axes')
41
+ const graphicClassName = getClassName(pluginName, 'graphic')
42
+
43
+ const seriesSelection$ = seriesLabels$.pipe(
44
+ map((existSeriesLabels, i) => {
45
+ return selection
46
+ .selectAll<SVGGElement, string>(`g.${seriesClassName}`)
47
+ .data(existSeriesLabels, d => d)
48
+ .join(
49
+ enter => {
50
+ return enter
51
+ .append('g')
52
+ .classed(seriesClassName, true)
53
+ .each((d, i, g) => {
54
+ const axesSelection = d3.select(g[i])
55
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${axesClassName}`)
56
+ .data([i])
57
+ .join(
58
+ enter => {
59
+ return enter
60
+ .append('g')
61
+ .classed(axesClassName, true)
62
+ .attr('clip-path', `url(#${clipPathID})`)
63
+ .each((d, i, g) => {
64
+ const defsSelection = d3.select(g[i])
65
+ .selectAll<SVGDefsElement, any>('defs')
66
+ .data([i])
67
+ .join('defs')
68
+
69
+ const graphicGSelection = d3.select(g[i])
70
+ .selectAll<SVGGElement, any>('g')
71
+ .data([i])
72
+ .join('g')
73
+ .classed(graphicClassName, true)
74
+ })
75
+ },
76
+ update => update,
77
+ exit => exit.remove()
78
+ )
79
+ })
80
+ },
81
+ update => update,
82
+ exit => exit.remove()
83
+ )
84
+ }),
85
+ shareReplay(1)
86
+ )
87
+
88
+ combineLatest({
89
+ seriesSelection: seriesSelection$,
90
+ gridContainerPosition: gridContainerPosition$
91
+ }).pipe(
92
+ switchMap(async d => d)
93
+ ).subscribe(data => {
94
+ data.seriesSelection
95
+ .transition()
96
+ .attr('transform', (d, i) => {
97
+ const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
98
+ const translate = gridContainerPosition.translate
99
+ const scale = gridContainerPosition.scale
100
+ return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
101
+ })
102
+ })
103
+
104
+ const axesSelection$ = combineLatest({
105
+ seriesSelection: seriesSelection$,
106
+ gridAxesTransform: gridAxesTransform$
107
+ }).pipe(
108
+ switchMap(async d => d),
109
+ map(data => {
110
+ return data.seriesSelection
111
+ .select<SVGGElement>(`g.${axesClassName}`)
112
+ .style('transform', data.gridAxesTransform.value)
113
+ }),
114
+ shareReplay(1)
115
+ )
116
+ const defsSelection$ = axesSelection$.pipe(
117
+ map(axesSelection => {
118
+ return axesSelection.select<SVGDefsElement>('defs')
119
+ }),
120
+ shareReplay(1)
121
+ )
122
+ const graphicGSelection$ = combineLatest({
123
+ axesSelection: axesSelection$,
124
+ gridGraphicTransform: gridGraphicTransform$
125
+ }).pipe(
126
+ switchMap(async d => d),
127
+ map(data => {
128
+ const graphicGSelection = data.axesSelection
129
+ .select<SVGGElement>(`g.${graphicClassName}`)
130
+ graphicGSelection
131
+ .transition()
132
+ .duration(50)
133
+ .style('transform', data.gridGraphicTransform.value)
134
+ return graphicGSelection
135
+ }),
136
+ shareReplay(1)
137
+ )
138
+
139
+ return {
140
+ seriesSelection$,
141
+ axesSelection$,
142
+ defsSelection$,
143
+ graphicGSelection$
144
+ }
145
+ }
146
+
147
+ // 由事件取得group data的function
148
+ // @Q@ 之後重構改用 gridGroupPosition
149
+ export const gridGroupPositionFnObservable = ({ fullDataFormatter$, gridAxesSize$, computedData$, fullChartParams$, gridContainerPosition$, layout$ }: {
150
+ fullDataFormatter$: Observable<DataFormatterGrid>
151
+ gridAxesSize$: Observable<{
152
+ width: number;
153
+ height: number;
154
+ }>
155
+ computedData$: Observable<ComputedDataGrid>
156
+ // GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
157
+ fullChartParams$: Observable<ChartParams>
158
+ gridContainerPosition$: Observable<GridContainerPosition[]>
159
+ layout$: Observable<Layout>
160
+ }): Observable<(event: any) => { groupIndex: number; groupLabel: string }> => {
161
+ const destroy$ = new Subject()
162
+
163
+ // 顯示範圍內的group labels
164
+ // const scaleRangeGroupLabels$: Observable<string[]> = new Observable(subscriber => {
165
+ // combineLatest({
166
+ // dataFormatter: fullDataFormatter$,
167
+ // computedData: computedData$
168
+ // }).pipe(
169
+ // takeUntil(destroy$),
170
+ // switchMap(async (d) => d),
171
+ // ).subscribe(data => {
172
+ // const groupMin = 0
173
+ // const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
174
+ // const groupScaleDomainMin = data.dataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
175
+ // ? groupMin - data.dataFormatter.grid.groupAxis.scalePadding
176
+ // : data.dataFormatter.grid.groupAxis.scaleDomain[0] as number - data.dataFormatter.grid.groupAxis.scalePadding
177
+ // const groupScaleDomainMax = data.dataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
178
+ // ? groupMax + data.dataFormatter.grid.groupAxis.scalePadding
179
+ // : data.dataFormatter.grid.groupAxis.scaleDomain[1] as number + data.dataFormatter.grid.groupAxis.scalePadding
180
+
181
+ // // const groupingAmount = data.computedData[0]
182
+ // // ? data.computedData[0].length
183
+ // // : 0
184
+
185
+ // let _labels = data.dataFormatter.grid.seriesDirection === 'row'
186
+ // ? (data.computedData[0] ?? []).map(d => d.groupLabel)
187
+ // : data.computedData.map(d => d[0].groupLabel)
188
+
189
+ // const _axisLabels =
190
+ // // new Array(groupingAmount).fill(0)
191
+ // // .map((d, i) => {
192
+ // // return _labels[i] != null
193
+ // // ? _labels[i]
194
+ // // : String(i) // 沒有label則用序列號填充
195
+ // // })
196
+ // _labels
197
+ // .filter((d, i) => {
198
+ // return i >= groupScaleDomainMin && i <= groupScaleDomainMax
199
+ // })
200
+ // subscriber.next(_axisLabels)
201
+ // })
202
+ // })
203
+ const groupScaleDomain$ = combineLatest({
204
+ fullDataFormatter: fullDataFormatter$,
205
+ gridAxesSize: gridAxesSize$,
206
+ computedData: computedData$
207
+ }).pipe(
208
+ switchMap(async (d) => d),
209
+ map(data => {
210
+ const groupMin = 0
211
+ const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
212
+ // const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
213
+ // ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
214
+ // : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
215
+ const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] - data.fullDataFormatter.grid.groupAxis.scalePadding
216
+ const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'max'
217
+ ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
218
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
219
+
220
+ return [groupScaleDomainMin, groupScaleDomainMax]
221
+ }),
222
+ shareReplay(1)
223
+ )
224
+
225
+ const groupLabels$ = combineLatest({
226
+ fullDataFormatter: fullDataFormatter$,
227
+ computedData: computedData$
228
+ }).pipe(
229
+ switchMap(async d => d),
230
+ map(data => {
231
+ return data.fullDataFormatter.grid.seriesDirection === 'row'
232
+ ? (data.computedData[0] ?? []).map(d => d.groupLabel)
233
+ : data.computedData.map(d => d[0].groupLabel)
234
+ })
235
+ )
236
+
237
+ // 顯示範圍內的group labels
238
+ const scaleRangeGroupLabels$ = combineLatest({
239
+ groupScaleDomain: groupScaleDomain$,
240
+ groupLabels: groupLabels$
241
+ }).pipe(
242
+ switchMap(async d => d),
243
+ map(data => {
244
+ return data.groupLabels
245
+ .filter((d, i) => {
246
+ return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
247
+ })
248
+ })
249
+ )
250
+
251
+ const columnAmount$ = gridContainerPosition$.pipe(
252
+ map(gridContainerPosition => {
253
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
254
+ return current.columnIndex > acc ? current.columnIndex : acc
255
+ }, 0)
256
+ return maxColumnIndex + 1
257
+ }),
258
+ distinctUntilChanged()
259
+ )
260
+
261
+ const rowAmount$ = gridContainerPosition$.pipe(
262
+ map(gridContainerPosition => {
263
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
264
+ return current.rowIndex > acc ? current.rowIndex : acc
265
+ }, 0)
266
+ return maxRowIndex + 1
267
+ }),
268
+ distinctUntilChanged()
269
+ )
270
+
271
+ return new Observable<(event: any) => { groupIndex: number; groupLabel: string }>(subscriber => {
272
+ combineLatest({
273
+ dataFormatter: fullDataFormatter$,
274
+ axisSize: gridAxesSize$,
275
+ fullChartParams: fullChartParams$,
276
+ scaleRangeGroupLabels: scaleRangeGroupLabels$,
277
+ groupScaleDomain: groupScaleDomain$,
278
+ columnAmount: columnAmount$,
279
+ rowAmount: rowAmount$,
280
+ layout: layout$
281
+ }).pipe(
282
+ takeUntil(destroy$),
283
+ switchMap(async (d) => d),
284
+ ).subscribe(data => {
285
+
286
+ const reverse = data.dataFormatter.grid.valueAxis.position === 'right'
287
+ || data.dataFormatter.grid.valueAxis.position === 'bottom'
288
+ ? true : false
289
+
290
+ // 比例尺座標對應非連續資料索引
291
+ const xIndexScale = createAxisQuantizeScale({
292
+ axisLabels: data.scaleRangeGroupLabels,
293
+ axisWidth: data.axisSize.width,
294
+ padding: data.dataFormatter.grid.groupAxis.scalePadding,
295
+ reverse
296
+ })
297
+
298
+ // 依比例尺位置計算座標
299
+ const axisValuePredicate = (event: any) => {
300
+ return data.dataFormatter.grid.groupAxis.position === 'bottom'
301
+ || data.dataFormatter.grid.groupAxis.position === 'top'
302
+ ? event.offsetX - data.fullChartParams.padding.left
303
+ : event.offsetY - data.fullChartParams.padding.top
304
+ }
305
+
306
+ // 比例尺座標取得groupData的function
307
+ const createEventGroupData: (event: any) => { groupIndex: number; groupLabel: string } = (event: any) => {
308
+ // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
309
+ const eventData = {
310
+ offsetX: event.offsetX * data.columnAmount % data.layout.rootWidth,
311
+ offsetY: event.offsetY * data.rowAmount % data.layout.rootHeight
312
+ }
313
+ // console.log('data.columnAmount', data.columnAmount, 'data.rowAmount', data.rowAmount, 'data.layout.rootWidth', data.layout.rootWidth, 'data.layout.rootHeight', data.layout.rootHeight)
314
+ const axisValue = axisValuePredicate(eventData)
315
+ const xIndex = xIndexScale(axisValue)
316
+ const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
317
+ const groupIndex = xIndex + currentxIndexStart
318
+ return {
319
+ groupIndex,
320
+ groupLabel: data.scaleRangeGroupLabels[groupIndex] ?? ''
321
+ }
322
+ }
323
+
324
+ subscriber.next(createEventGroupData)
325
+
326
+ return function unsubscribe () {
327
+ destroy$.next(undefined)
328
+ }
329
+ })
330
+ })
331
+ }
332
+
333
+ export const gridGroupPosition = ({ rootSelection, fullDataFormatter$, gridAxesSize$, computedData$, fullChartParams$, gridContainerPosition$, layout$ }: {
334
+ rootSelection: d3.Selection<any, unknown, any, unknown>
335
+ fullDataFormatter$: Observable<DataFormatterGrid>
336
+ gridAxesSize$: Observable<{
337
+ width: number;
338
+ height: number;
339
+ }>
340
+ computedData$: Observable<ComputedDataGrid>
341
+ fullChartParams$: Observable<ChartParams>
342
+ gridContainerPosition$: Observable<GridContainerPosition[]>
343
+ layout$: Observable<Layout>
344
+ }) => {
345
+ const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove')
346
+
347
+ const groupScaleDomain$ = combineLatest({
348
+ fullDataFormatter: fullDataFormatter$,
349
+ gridAxesSize: gridAxesSize$,
350
+ computedData: computedData$
351
+ }).pipe(
352
+ switchMap(async (d) => d),
353
+ map(data => {
354
+ const groupMin = 0
355
+ const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
356
+ // const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
357
+ // ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
358
+ // : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
359
+ const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] - data.fullDataFormatter.grid.groupAxis.scalePadding
360
+ const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'max'
361
+ ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
362
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
363
+
364
+ return [groupScaleDomainMin, groupScaleDomainMax]
365
+ }),
366
+ shareReplay(1)
367
+ )
368
+
369
+ const groupLabels$ = combineLatest({
370
+ fullDataFormatter: fullDataFormatter$,
371
+ computedData: computedData$
372
+ }).pipe(
373
+ switchMap(async d => d),
374
+ map(data => {
375
+ return data.fullDataFormatter.grid.seriesDirection === 'row'
376
+ ? (data.computedData[0] ?? []).map(d => d.groupLabel)
377
+ : data.computedData.map(d => d[0].groupLabel)
378
+ })
379
+ )
380
+
381
+ const scaleRangeGroupLabels$ = combineLatest({
382
+ groupScaleDomain: groupScaleDomain$,
383
+ groupLabels: groupLabels$
384
+ }).pipe(
385
+ switchMap(async d => d),
386
+ map(data => {
387
+ return data.groupLabels
388
+ .filter((d, i) => {
389
+ return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
390
+ })
391
+ })
392
+ )
393
+
394
+ const reverse$ = fullDataFormatter$.pipe(
395
+ map(d => {
396
+ return d.grid.valueAxis.position === 'right' || d.grid.valueAxis.position === 'bottom'
397
+ ? true
398
+ : false
399
+ })
400
+ )
401
+
402
+ // 比例尺座標對應非連續資料索引
403
+ const xIndexScale$ = combineLatest({
404
+ reverse: reverse$,
405
+ gridAxesSize: gridAxesSize$,
406
+ scaleRangeGroupLabels: scaleRangeGroupLabels$,
407
+ fullDataFormatter: fullDataFormatter$
408
+ }).pipe(
409
+ switchMap(async d => d),
410
+ map(data => {
411
+ return createAxisQuantizeScale({
412
+ axisLabels: data.scaleRangeGroupLabels,
413
+ axisWidth: data.gridAxesSize.width,
414
+ padding: data.fullDataFormatter.grid.groupAxis.scalePadding,
415
+ reverse: data.reverse
416
+ })
417
+ })
418
+ )
419
+
420
+ const columnAmount$ = gridContainerPosition$.pipe(
421
+ map(gridContainerPosition => {
422
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
423
+ return current.columnIndex > acc ? current.columnIndex : acc
424
+ }, 0)
425
+ return maxColumnIndex + 1
426
+ }),
427
+ distinctUntilChanged()
428
+ )
429
+
430
+ const rowAmount$ = gridContainerPosition$.pipe(
431
+ map(gridContainerPosition => {
432
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
433
+ return current.rowIndex > acc ? current.rowIndex : acc
434
+ }, 0)
435
+ return maxRowIndex + 1
436
+ }),
437
+ distinctUntilChanged()
438
+ )
439
+
440
+ const axisValue$ = combineLatest({
441
+ fullDataFormatter: fullDataFormatter$,
442
+ fullChartParams: fullChartParams$,
443
+ rootMousemove: rootMousemove$,
444
+ columnAmount: columnAmount$,
445
+ rowAmount: rowAmount$,
446
+ layout: layout$
447
+ }).pipe(
448
+ switchMap(async d => d),
449
+ map(data => {
450
+ // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
451
+ const eventData = {
452
+ offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
453
+ offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
454
+ }
455
+ return data.fullDataFormatter.grid.groupAxis.position === 'bottom'
456
+ || data.fullDataFormatter.grid.groupAxis.position === 'top'
457
+ ? eventData.offsetX - data.fullChartParams.padding.left
458
+ : eventData.offsetY - data.fullChartParams.padding.top
459
+ })
460
+ )
461
+
462
+ const groupIndex$ = combineLatest({
463
+ xIndexScale: xIndexScale$,
464
+ axisValue: axisValue$,
465
+ groupScaleDomain: groupScaleDomain$
466
+ }).pipe(
467
+ switchMap(async d => d),
468
+ map(data => {
469
+ const xIndex = data.xIndexScale(data.axisValue)
470
+ const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
471
+ return xIndex + currentxIndexStart
472
+ })
473
+ )
474
+
475
+ const groupLabel$ = combineLatest({
476
+ groupIndex: groupIndex$,
477
+ groupLabels: groupLabels$
478
+ }).pipe(
479
+ switchMap(async d => d),
480
+ map(data => {
481
+ return data.groupLabels[data.groupIndex] ?? ''
482
+ })
483
+ )
484
+
485
+ return combineLatest({
486
+ groupIndex: groupIndex$,
487
+ groupLabel: groupLabel$
488
+ }).pipe(
489
+ switchMap(async d => d),
490
+ map(data => {
491
+ return {
492
+ groupIndex: data.groupIndex,
493
+ groupLabel: data.groupLabel
494
+ }
495
+ })
496
+ )
497
+ }
498
+
499
+ // const gridContainerEventData$ = ({ eventData$, gridContainerPosition$, layout$ }: {
500
+ // eventData$: Observable<any>
501
+ // gridContainerPosition$: Observable<GridContainerPosition[]>
502
+ // layout$: Observable<Layout>
503
+ // }): Observable<{
504
+ // offsetX: number;
505
+ // offsetY: number;
506
+ // }> => {
507
+ // const columnAmount$ = gridContainerPosition$.pipe(
508
+ // map(gridContainerPosition => {
509
+ // const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
510
+ // return current.columnIndex > acc ? current.columnIndex : acc
511
+ // }, 0)
512
+ // return maxColumnIndex + 1
513
+ // }),
514
+ // distinctUntilChanged()
515
+ // )
516
+
517
+ // const rowAmount$ = gridContainerPosition$.pipe(
518
+ // map(gridContainerPosition => {
519
+ // const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
520
+ // return current.rowIndex > acc ? current.rowIndex : acc
521
+ // }, 0)
522
+ // return maxRowIndex + 1
523
+ // }),
524
+ // distinctUntilChanged()
525
+ // )
526
+
527
+ // return combineLatest({
528
+ // eventData: eventData$,
529
+ // gridContainerPosition: gridContainerPosition$,
530
+ // layout: layout$,
531
+ // columnAmount: columnAmount$,
532
+ // rowAmount: rowAmount$
533
+ // }).pipe(
534
+ // switchMap(async d => d),
535
+ // map(data => {
536
+ // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
537
+ // const eventData = {
538
+ // offsetX: data.eventData.offsetX * data.columnAmount % data.layout.rootWidth,
539
+ // offsetY: data.eventData.offsetY * data.rowAmount % data.layout.rootHeight
540
+ // }
541
+ // return eventData
542
+ // })
543
+ // )
544
544
  // }