@orbcharts/plugins-basic 3.0.0-alpha.59 → 3.0.0-alpha.61

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. package/LICENSE +200 -200
  2. package/package.json +42 -43
  3. package/src/base/BaseBarStack.ts +778 -778
  4. package/src/base/BaseBars.ts +764 -764
  5. package/src/base/BaseBarsTriangle.ts +672 -672
  6. package/src/base/BaseDots.ts +513 -513
  7. package/src/base/BaseGroupAxis.ts +558 -558
  8. package/src/base/BaseLegend.ts +641 -641
  9. package/src/base/BaseLineAreas.ts +628 -628
  10. package/src/base/BaseLines.ts +704 -704
  11. package/src/base/BaseValueAxis.ts +478 -478
  12. package/src/base/types.ts +2 -2
  13. package/src/grid/defaults.ts +128 -128
  14. package/src/grid/gridObservables.ts +541 -541
  15. package/src/grid/index.ts +15 -15
  16. package/src/grid/plugins/BarStack.ts +43 -43
  17. package/src/grid/plugins/Bars.ts +44 -44
  18. package/src/grid/plugins/BarsPN.ts +41 -41
  19. package/src/grid/plugins/BarsTriangle.ts +42 -42
  20. package/src/grid/plugins/Dots.ts +37 -37
  21. package/src/grid/plugins/GridLegend.ts +59 -59
  22. package/src/grid/plugins/GroupAux.ts +976 -976
  23. package/src/grid/plugins/GroupAxis.ts +35 -35
  24. package/src/grid/plugins/LineAreas.ts +40 -40
  25. package/src/grid/plugins/Lines.ts +40 -40
  26. package/src/grid/plugins/ScalingArea.ts +173 -173
  27. package/src/grid/plugins/ValueAxis.ts +36 -36
  28. package/src/grid/plugins/ValueStackAxis.ts +38 -38
  29. package/src/grid/types.ts +123 -123
  30. package/src/index.ts +9 -9
  31. package/src/multiGrid/defaults.ts +158 -158
  32. package/src/multiGrid/index.ts +13 -13
  33. package/src/multiGrid/multiGridObservables.ts +49 -49
  34. package/src/multiGrid/plugins/MultiBarStack.ts +78 -78
  35. package/src/multiGrid/plugins/MultiBars.ts +77 -77
  36. package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -77
  37. package/src/multiGrid/plugins/MultiDots.ts +65 -65
  38. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
  39. package/src/multiGrid/plugins/MultiGroupAxis.ts +69 -69
  40. package/src/multiGrid/plugins/MultiLineAreas.ts +77 -77
  41. package/src/multiGrid/plugins/MultiLines.ts +77 -77
  42. package/src/multiGrid/plugins/MultiValueAxis.ts +69 -69
  43. package/src/multiGrid/plugins/MultiValueStackAxis.ts +69 -69
  44. package/src/multiGrid/plugins/OverlappingValueAxes.ts +167 -167
  45. package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +168 -168
  46. package/src/multiGrid/types.ts +72 -72
  47. package/src/noneData/defaults.ts +102 -102
  48. package/src/noneData/index.ts +3 -3
  49. package/src/noneData/plugins/Container.ts +10 -10
  50. package/src/noneData/plugins/Tooltip.ts +310 -310
  51. package/src/noneData/types.ts +26 -26
  52. package/src/series/defaults.ts +144 -144
  53. package/src/series/index.ts +9 -9
  54. package/src/series/plugins/Bubbles.ts +545 -545
  55. package/src/series/plugins/Pie.ts +576 -576
  56. package/src/series/plugins/PieEventTexts.ts +262 -262
  57. package/src/series/plugins/PieLabels.ts +304 -304
  58. package/src/series/plugins/Rose.ts +472 -472
  59. package/src/series/plugins/RoseLabels.ts +362 -362
  60. package/src/series/plugins/SeriesLegend.ts +59 -59
  61. package/src/series/seriesObservables.ts +145 -145
  62. package/src/series/seriesUtils.ts +51 -51
  63. package/src/series/types.ts +83 -83
  64. package/src/tree/defaults.ts +23 -23
  65. package/src/tree/index.ts +3 -3
  66. package/src/tree/plugins/TreeLegend.ts +59 -59
  67. package/src/tree/plugins/TreeMap.ts +305 -305
  68. package/src/tree/types.ts +23 -23
  69. package/src/utils/commonUtils.ts +21 -21
  70. package/src/utils/d3Graphics.ts +124 -124
  71. package/src/utils/d3Utils.ts +73 -73
  72. package/src/utils/observables.ts +14 -14
  73. package/src/utils/orbchartsUtils.ts +100 -100
  74. package/tsconfig.base.json +13 -13
  75. package/tsconfig.json +2 -7
  76. package/{vite.config.mjs → vite.config.js} +22 -40
  77. package/tsconfig.prod.json +0 -3
  78. /package/dist/{vite.config.d.mts → vite.config.d.ts} +0 -0
@@ -1,542 +1,542 @@
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 groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
216
- ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
217
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
218
-
219
- return [groupScaleDomainMin, groupScaleDomainMax]
220
- }),
221
- shareReplay(1)
222
- )
223
-
224
- const groupLabels$ = combineLatest({
225
- fullDataFormatter: fullDataFormatter$,
226
- computedData: computedData$
227
- }).pipe(
228
- switchMap(async d => d),
229
- map(data => {
230
- return data.fullDataFormatter.grid.seriesDirection === 'row'
231
- ? (data.computedData[0] ?? []).map(d => d.groupLabel)
232
- : data.computedData.map(d => d[0].groupLabel)
233
- })
234
- )
235
-
236
- // 顯示範圍內的group labels
237
- const scaleRangeGroupLabels$ = combineLatest({
238
- groupScaleDomain: groupScaleDomain$,
239
- groupLabels: groupLabels$
240
- }).pipe(
241
- switchMap(async d => d),
242
- map(data => {
243
- return data.groupLabels
244
- .filter((d, i) => {
245
- return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
246
- })
247
- })
248
- )
249
-
250
- const columnAmount$ = gridContainerPosition$.pipe(
251
- map(gridContainerPosition => {
252
- const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
253
- return current.columnIndex > acc ? current.columnIndex : acc
254
- }, 0)
255
- return maxColumnIndex + 1
256
- }),
257
- distinctUntilChanged()
258
- )
259
-
260
- const rowAmount$ = gridContainerPosition$.pipe(
261
- map(gridContainerPosition => {
262
- const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
263
- return current.rowIndex > acc ? current.rowIndex : acc
264
- }, 0)
265
- return maxRowIndex + 1
266
- }),
267
- distinctUntilChanged()
268
- )
269
-
270
- return new Observable<(event: any) => { groupIndex: number; groupLabel: string }>(subscriber => {
271
- combineLatest({
272
- dataFormatter: fullDataFormatter$,
273
- axisSize: gridAxesSize$,
274
- fullChartParams: fullChartParams$,
275
- scaleRangeGroupLabels: scaleRangeGroupLabels$,
276
- groupScaleDomain: groupScaleDomain$,
277
- columnAmount: columnAmount$,
278
- rowAmount: rowAmount$,
279
- layout: layout$
280
- }).pipe(
281
- takeUntil(destroy$),
282
- switchMap(async (d) => d),
283
- ).subscribe(data => {
284
-
285
- const reverse = data.dataFormatter.grid.valueAxis.position === 'right'
286
- || data.dataFormatter.grid.valueAxis.position === 'bottom'
287
- ? true : false
288
-
289
- // 比例尺座標對應非連續資料索引
290
- const xIndexScale = createAxisQuantizeScale({
291
- axisLabels: data.scaleRangeGroupLabels,
292
- axisWidth: data.axisSize.width,
293
- padding: data.dataFormatter.grid.groupAxis.scalePadding,
294
- reverse
295
- })
296
-
297
- // 依比例尺位置計算座標
298
- const axisValuePredicate = (event: any) => {
299
- return data.dataFormatter.grid.groupAxis.position === 'bottom'
300
- || data.dataFormatter.grid.groupAxis.position === 'top'
301
- ? event.offsetX - data.fullChartParams.padding.left
302
- : event.offsetY - data.fullChartParams.padding.top
303
- }
304
-
305
- // 比例尺座標取得groupData的function
306
- const createEventGroupData: (event: any) => { groupIndex: number; groupLabel: string } = (event: any) => {
307
- // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
308
- const eventData = {
309
- offsetX: event.offsetX * data.columnAmount % data.layout.rootWidth,
310
- offsetY: event.offsetY * data.rowAmount % data.layout.rootHeight
311
- }
312
- // console.log('data.columnAmount', data.columnAmount, 'data.rowAmount', data.rowAmount, 'data.layout.rootWidth', data.layout.rootWidth, 'data.layout.rootHeight', data.layout.rootHeight)
313
- const axisValue = axisValuePredicate(eventData)
314
- const xIndex = xIndexScale(axisValue)
315
- const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
316
- const groupIndex = xIndex + currentxIndexStart
317
- return {
318
- groupIndex,
319
- groupLabel: data.scaleRangeGroupLabels[groupIndex] ?? ''
320
- }
321
- }
322
-
323
- subscriber.next(createEventGroupData)
324
-
325
- return function unsubscribe () {
326
- destroy$.next(undefined)
327
- }
328
- })
329
- })
330
- }
331
-
332
- export const gridGroupPosition = ({ rootSelection, fullDataFormatter$, gridAxesSize$, computedData$, fullChartParams$, gridContainerPosition$, layout$ }: {
333
- rootSelection: d3.Selection<any, unknown, any, unknown>
334
- fullDataFormatter$: Observable<DataFormatterGrid>
335
- gridAxesSize$: Observable<{
336
- width: number;
337
- height: number;
338
- }>
339
- computedData$: Observable<ComputedDataGrid>
340
- fullChartParams$: Observable<ChartParams>
341
- gridContainerPosition$: Observable<GridContainerPosition[]>
342
- layout$: Observable<Layout>
343
- }) => {
344
- const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove')
345
-
346
- const groupScaleDomain$ = combineLatest({
347
- fullDataFormatter: fullDataFormatter$,
348
- gridAxesSize: gridAxesSize$,
349
- computedData: computedData$
350
- }).pipe(
351
- switchMap(async (d) => d),
352
- map(data => {
353
- const groupMin = 0
354
- const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
355
- const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
356
- ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
357
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
358
- const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
359
- ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
360
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
361
-
362
- return [groupScaleDomainMin, groupScaleDomainMax]
363
- }),
364
- shareReplay(1)
365
- )
366
-
367
- const groupLabels$ = combineLatest({
368
- fullDataFormatter: fullDataFormatter$,
369
- computedData: computedData$
370
- }).pipe(
371
- switchMap(async d => d),
372
- map(data => {
373
- return data.fullDataFormatter.grid.seriesDirection === 'row'
374
- ? (data.computedData[0] ?? []).map(d => d.groupLabel)
375
- : data.computedData.map(d => d[0].groupLabel)
376
- })
377
- )
378
-
379
- const scaleRangeGroupLabels$ = combineLatest({
380
- groupScaleDomain: groupScaleDomain$,
381
- groupLabels: groupLabels$
382
- }).pipe(
383
- switchMap(async d => d),
384
- map(data => {
385
- return data.groupLabels
386
- .filter((d, i) => {
387
- return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
388
- })
389
- })
390
- )
391
-
392
- const reverse$ = fullDataFormatter$.pipe(
393
- map(d => {
394
- return d.grid.valueAxis.position === 'right' || d.grid.valueAxis.position === 'bottom'
395
- ? true
396
- : false
397
- })
398
- )
399
-
400
- // 比例尺座標對應非連續資料索引
401
- const xIndexScale$ = combineLatest({
402
- reverse: reverse$,
403
- gridAxesSize: gridAxesSize$,
404
- scaleRangeGroupLabels: scaleRangeGroupLabels$,
405
- fullDataFormatter: fullDataFormatter$
406
- }).pipe(
407
- switchMap(async d => d),
408
- map(data => {
409
- return createAxisQuantizeScale({
410
- axisLabels: data.scaleRangeGroupLabels,
411
- axisWidth: data.gridAxesSize.width,
412
- padding: data.fullDataFormatter.grid.groupAxis.scalePadding,
413
- reverse: data.reverse
414
- })
415
- })
416
- )
417
-
418
- const columnAmount$ = gridContainerPosition$.pipe(
419
- map(gridContainerPosition => {
420
- const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
421
- return current.columnIndex > acc ? current.columnIndex : acc
422
- }, 0)
423
- return maxColumnIndex + 1
424
- }),
425
- distinctUntilChanged()
426
- )
427
-
428
- const rowAmount$ = gridContainerPosition$.pipe(
429
- map(gridContainerPosition => {
430
- const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
431
- return current.rowIndex > acc ? current.rowIndex : acc
432
- }, 0)
433
- return maxRowIndex + 1
434
- }),
435
- distinctUntilChanged()
436
- )
437
-
438
- const axisValue$ = combineLatest({
439
- fullDataFormatter: fullDataFormatter$,
440
- fullChartParams: fullChartParams$,
441
- rootMousemove: rootMousemove$,
442
- columnAmount: columnAmount$,
443
- rowAmount: rowAmount$,
444
- layout: layout$
445
- }).pipe(
446
- switchMap(async d => d),
447
- map(data => {
448
- // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
449
- const eventData = {
450
- offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
451
- offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
452
- }
453
- return data.fullDataFormatter.grid.groupAxis.position === 'bottom'
454
- || data.fullDataFormatter.grid.groupAxis.position === 'top'
455
- ? eventData.offsetX - data.fullChartParams.padding.left
456
- : eventData.offsetY - data.fullChartParams.padding.top
457
- })
458
- )
459
-
460
- const groupIndex$ = combineLatest({
461
- xIndexScale: xIndexScale$,
462
- axisValue: axisValue$,
463
- groupScaleDomain: groupScaleDomain$
464
- }).pipe(
465
- switchMap(async d => d),
466
- map(data => {
467
- const xIndex = data.xIndexScale(data.axisValue)
468
- const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
469
- return xIndex + currentxIndexStart
470
- })
471
- )
472
-
473
- const groupLabel$ = combineLatest({
474
- groupIndex: groupIndex$,
475
- groupLabels: groupLabels$
476
- }).pipe(
477
- switchMap(async d => d),
478
- map(data => {
479
- return data.groupLabels[data.groupIndex] ?? ''
480
- })
481
- )
482
-
483
- return combineLatest({
484
- groupIndex: groupIndex$,
485
- groupLabel: groupLabel$
486
- }).pipe(
487
- switchMap(async d => d),
488
- map(data => {
489
- return {
490
- groupIndex: data.groupIndex,
491
- groupLabel: data.groupLabel
492
- }
493
- })
494
- )
495
- }
496
-
497
- // const gridContainerEventData$ = ({ eventData$, gridContainerPosition$, layout$ }: {
498
- // eventData$: Observable<any>
499
- // gridContainerPosition$: Observable<GridContainerPosition[]>
500
- // layout$: Observable<Layout>
501
- // }): Observable<{
502
- // offsetX: number;
503
- // offsetY: number;
504
- // }> => {
505
- // const columnAmount$ = gridContainerPosition$.pipe(
506
- // map(gridContainerPosition => {
507
- // const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
508
- // return current.columnIndex > acc ? current.columnIndex : acc
509
- // }, 0)
510
- // return maxColumnIndex + 1
511
- // }),
512
- // distinctUntilChanged()
513
- // )
514
-
515
- // const rowAmount$ = gridContainerPosition$.pipe(
516
- // map(gridContainerPosition => {
517
- // const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
518
- // return current.rowIndex > acc ? current.rowIndex : acc
519
- // }, 0)
520
- // return maxRowIndex + 1
521
- // }),
522
- // distinctUntilChanged()
523
- // )
524
-
525
- // return combineLatest({
526
- // eventData: eventData$,
527
- // gridContainerPosition: gridContainerPosition$,
528
- // layout: layout$,
529
- // columnAmount: columnAmount$,
530
- // rowAmount: rowAmount$
531
- // }).pipe(
532
- // switchMap(async d => d),
533
- // map(data => {
534
- // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
535
- // const eventData = {
536
- // offsetX: data.eventData.offsetX * data.columnAmount % data.layout.rootWidth,
537
- // offsetY: data.eventData.offsetY * data.rowAmount % data.layout.rootHeight
538
- // }
539
- // return eventData
540
- // })
541
- // )
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 groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
216
+ ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
217
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
218
+
219
+ return [groupScaleDomainMin, groupScaleDomainMax]
220
+ }),
221
+ shareReplay(1)
222
+ )
223
+
224
+ const groupLabels$ = combineLatest({
225
+ fullDataFormatter: fullDataFormatter$,
226
+ computedData: computedData$
227
+ }).pipe(
228
+ switchMap(async d => d),
229
+ map(data => {
230
+ return data.fullDataFormatter.grid.seriesDirection === 'row'
231
+ ? (data.computedData[0] ?? []).map(d => d.groupLabel)
232
+ : data.computedData.map(d => d[0].groupLabel)
233
+ })
234
+ )
235
+
236
+ // 顯示範圍內的group labels
237
+ const scaleRangeGroupLabels$ = combineLatest({
238
+ groupScaleDomain: groupScaleDomain$,
239
+ groupLabels: groupLabels$
240
+ }).pipe(
241
+ switchMap(async d => d),
242
+ map(data => {
243
+ return data.groupLabels
244
+ .filter((d, i) => {
245
+ return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
246
+ })
247
+ })
248
+ )
249
+
250
+ const columnAmount$ = gridContainerPosition$.pipe(
251
+ map(gridContainerPosition => {
252
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
253
+ return current.columnIndex > acc ? current.columnIndex : acc
254
+ }, 0)
255
+ return maxColumnIndex + 1
256
+ }),
257
+ distinctUntilChanged()
258
+ )
259
+
260
+ const rowAmount$ = gridContainerPosition$.pipe(
261
+ map(gridContainerPosition => {
262
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
263
+ return current.rowIndex > acc ? current.rowIndex : acc
264
+ }, 0)
265
+ return maxRowIndex + 1
266
+ }),
267
+ distinctUntilChanged()
268
+ )
269
+
270
+ return new Observable<(event: any) => { groupIndex: number; groupLabel: string }>(subscriber => {
271
+ combineLatest({
272
+ dataFormatter: fullDataFormatter$,
273
+ axisSize: gridAxesSize$,
274
+ fullChartParams: fullChartParams$,
275
+ scaleRangeGroupLabels: scaleRangeGroupLabels$,
276
+ groupScaleDomain: groupScaleDomain$,
277
+ columnAmount: columnAmount$,
278
+ rowAmount: rowAmount$,
279
+ layout: layout$
280
+ }).pipe(
281
+ takeUntil(destroy$),
282
+ switchMap(async (d) => d),
283
+ ).subscribe(data => {
284
+
285
+ const reverse = data.dataFormatter.grid.valueAxis.position === 'right'
286
+ || data.dataFormatter.grid.valueAxis.position === 'bottom'
287
+ ? true : false
288
+
289
+ // 比例尺座標對應非連續資料索引
290
+ const xIndexScale = createAxisQuantizeScale({
291
+ axisLabels: data.scaleRangeGroupLabels,
292
+ axisWidth: data.axisSize.width,
293
+ padding: data.dataFormatter.grid.groupAxis.scalePadding,
294
+ reverse
295
+ })
296
+
297
+ // 依比例尺位置計算座標
298
+ const axisValuePredicate = (event: any) => {
299
+ return data.dataFormatter.grid.groupAxis.position === 'bottom'
300
+ || data.dataFormatter.grid.groupAxis.position === 'top'
301
+ ? event.offsetX - data.fullChartParams.padding.left
302
+ : event.offsetY - data.fullChartParams.padding.top
303
+ }
304
+
305
+ // 比例尺座標取得groupData的function
306
+ const createEventGroupData: (event: any) => { groupIndex: number; groupLabel: string } = (event: any) => {
307
+ // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
308
+ const eventData = {
309
+ offsetX: event.offsetX * data.columnAmount % data.layout.rootWidth,
310
+ offsetY: event.offsetY * data.rowAmount % data.layout.rootHeight
311
+ }
312
+ // console.log('data.columnAmount', data.columnAmount, 'data.rowAmount', data.rowAmount, 'data.layout.rootWidth', data.layout.rootWidth, 'data.layout.rootHeight', data.layout.rootHeight)
313
+ const axisValue = axisValuePredicate(eventData)
314
+ const xIndex = xIndexScale(axisValue)
315
+ const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
316
+ const groupIndex = xIndex + currentxIndexStart
317
+ return {
318
+ groupIndex,
319
+ groupLabel: data.scaleRangeGroupLabels[groupIndex] ?? ''
320
+ }
321
+ }
322
+
323
+ subscriber.next(createEventGroupData)
324
+
325
+ return function unsubscribe () {
326
+ destroy$.next(undefined)
327
+ }
328
+ })
329
+ })
330
+ }
331
+
332
+ export const gridGroupPosition = ({ rootSelection, fullDataFormatter$, gridAxesSize$, computedData$, fullChartParams$, gridContainerPosition$, layout$ }: {
333
+ rootSelection: d3.Selection<any, unknown, any, unknown>
334
+ fullDataFormatter$: Observable<DataFormatterGrid>
335
+ gridAxesSize$: Observable<{
336
+ width: number;
337
+ height: number;
338
+ }>
339
+ computedData$: Observable<ComputedDataGrid>
340
+ fullChartParams$: Observable<ChartParams>
341
+ gridContainerPosition$: Observable<GridContainerPosition[]>
342
+ layout$: Observable<Layout>
343
+ }) => {
344
+ const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove')
345
+
346
+ const groupScaleDomain$ = combineLatest({
347
+ fullDataFormatter: fullDataFormatter$,
348
+ gridAxesSize: gridAxesSize$,
349
+ computedData: computedData$
350
+ }).pipe(
351
+ switchMap(async (d) => d),
352
+ map(data => {
353
+ const groupMin = 0
354
+ const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
355
+ const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
356
+ ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
357
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
358
+ const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
359
+ ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
360
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
361
+
362
+ return [groupScaleDomainMin, groupScaleDomainMax]
363
+ }),
364
+ shareReplay(1)
365
+ )
366
+
367
+ const groupLabels$ = combineLatest({
368
+ fullDataFormatter: fullDataFormatter$,
369
+ computedData: computedData$
370
+ }).pipe(
371
+ switchMap(async d => d),
372
+ map(data => {
373
+ return data.fullDataFormatter.grid.seriesDirection === 'row'
374
+ ? (data.computedData[0] ?? []).map(d => d.groupLabel)
375
+ : data.computedData.map(d => d[0].groupLabel)
376
+ })
377
+ )
378
+
379
+ const scaleRangeGroupLabels$ = combineLatest({
380
+ groupScaleDomain: groupScaleDomain$,
381
+ groupLabels: groupLabels$
382
+ }).pipe(
383
+ switchMap(async d => d),
384
+ map(data => {
385
+ return data.groupLabels
386
+ .filter((d, i) => {
387
+ return i >= data.groupScaleDomain[0] && i <= data.groupScaleDomain[1]
388
+ })
389
+ })
390
+ )
391
+
392
+ const reverse$ = fullDataFormatter$.pipe(
393
+ map(d => {
394
+ return d.grid.valueAxis.position === 'right' || d.grid.valueAxis.position === 'bottom'
395
+ ? true
396
+ : false
397
+ })
398
+ )
399
+
400
+ // 比例尺座標對應非連續資料索引
401
+ const xIndexScale$ = combineLatest({
402
+ reverse: reverse$,
403
+ gridAxesSize: gridAxesSize$,
404
+ scaleRangeGroupLabels: scaleRangeGroupLabels$,
405
+ fullDataFormatter: fullDataFormatter$
406
+ }).pipe(
407
+ switchMap(async d => d),
408
+ map(data => {
409
+ return createAxisQuantizeScale({
410
+ axisLabels: data.scaleRangeGroupLabels,
411
+ axisWidth: data.gridAxesSize.width,
412
+ padding: data.fullDataFormatter.grid.groupAxis.scalePadding,
413
+ reverse: data.reverse
414
+ })
415
+ })
416
+ )
417
+
418
+ const columnAmount$ = gridContainerPosition$.pipe(
419
+ map(gridContainerPosition => {
420
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
421
+ return current.columnIndex > acc ? current.columnIndex : acc
422
+ }, 0)
423
+ return maxColumnIndex + 1
424
+ }),
425
+ distinctUntilChanged()
426
+ )
427
+
428
+ const rowAmount$ = gridContainerPosition$.pipe(
429
+ map(gridContainerPosition => {
430
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
431
+ return current.rowIndex > acc ? current.rowIndex : acc
432
+ }, 0)
433
+ return maxRowIndex + 1
434
+ }),
435
+ distinctUntilChanged()
436
+ )
437
+
438
+ const axisValue$ = combineLatest({
439
+ fullDataFormatter: fullDataFormatter$,
440
+ fullChartParams: fullChartParams$,
441
+ rootMousemove: rootMousemove$,
442
+ columnAmount: columnAmount$,
443
+ rowAmount: rowAmount$,
444
+ layout: layout$
445
+ }).pipe(
446
+ switchMap(async d => d),
447
+ map(data => {
448
+ // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
449
+ const eventData = {
450
+ offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
451
+ offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
452
+ }
453
+ return data.fullDataFormatter.grid.groupAxis.position === 'bottom'
454
+ || data.fullDataFormatter.grid.groupAxis.position === 'top'
455
+ ? eventData.offsetX - data.fullChartParams.padding.left
456
+ : eventData.offsetY - data.fullChartParams.padding.top
457
+ })
458
+ )
459
+
460
+ const groupIndex$ = combineLatest({
461
+ xIndexScale: xIndexScale$,
462
+ axisValue: axisValue$,
463
+ groupScaleDomain: groupScaleDomain$
464
+ }).pipe(
465
+ switchMap(async d => d),
466
+ map(data => {
467
+ const xIndex = data.xIndexScale(data.axisValue)
468
+ const currentxIndexStart = Math.ceil(data.groupScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
469
+ return xIndex + currentxIndexStart
470
+ })
471
+ )
472
+
473
+ const groupLabel$ = combineLatest({
474
+ groupIndex: groupIndex$,
475
+ groupLabels: groupLabels$
476
+ }).pipe(
477
+ switchMap(async d => d),
478
+ map(data => {
479
+ return data.groupLabels[data.groupIndex] ?? ''
480
+ })
481
+ )
482
+
483
+ return combineLatest({
484
+ groupIndex: groupIndex$,
485
+ groupLabel: groupLabel$
486
+ }).pipe(
487
+ switchMap(async d => d),
488
+ map(data => {
489
+ return {
490
+ groupIndex: data.groupIndex,
491
+ groupLabel: data.groupLabel
492
+ }
493
+ })
494
+ )
495
+ }
496
+
497
+ // const gridContainerEventData$ = ({ eventData$, gridContainerPosition$, layout$ }: {
498
+ // eventData$: Observable<any>
499
+ // gridContainerPosition$: Observable<GridContainerPosition[]>
500
+ // layout$: Observable<Layout>
501
+ // }): Observable<{
502
+ // offsetX: number;
503
+ // offsetY: number;
504
+ // }> => {
505
+ // const columnAmount$ = gridContainerPosition$.pipe(
506
+ // map(gridContainerPosition => {
507
+ // const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
508
+ // return current.columnIndex > acc ? current.columnIndex : acc
509
+ // }, 0)
510
+ // return maxColumnIndex + 1
511
+ // }),
512
+ // distinctUntilChanged()
513
+ // )
514
+
515
+ // const rowAmount$ = gridContainerPosition$.pipe(
516
+ // map(gridContainerPosition => {
517
+ // const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
518
+ // return current.rowIndex > acc ? current.rowIndex : acc
519
+ // }, 0)
520
+ // return maxRowIndex + 1
521
+ // }),
522
+ // distinctUntilChanged()
523
+ // )
524
+
525
+ // return combineLatest({
526
+ // eventData: eventData$,
527
+ // gridContainerPosition: gridContainerPosition$,
528
+ // layout: layout$,
529
+ // columnAmount: columnAmount$,
530
+ // rowAmount: rowAmount$
531
+ // }).pipe(
532
+ // switchMap(async d => d),
533
+ // map(data => {
534
+ // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
535
+ // const eventData = {
536
+ // offsetX: data.eventData.offsetX * data.columnAmount % data.layout.rootWidth,
537
+ // offsetY: data.eventData.offsetY * data.rowAmount % data.layout.rootHeight
538
+ // }
539
+ // return eventData
540
+ // })
541
+ // )
542
542
  // }