@orbcharts/plugins-basic 3.0.0-alpha.29 → 3.0.0-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/orbcharts-plugins-basic.es.js +15826 -15642
  2. package/dist/orbcharts-plugins-basic.umd.js +8 -8
  3. package/dist/src/base/BaseBarStack.d.ts +29 -0
  4. package/dist/src/base/BaseBars.d.ts +29 -0
  5. package/dist/src/base/BaseBarsTriangle.d.ts +28 -0
  6. package/dist/src/base/BaseLegend.d.ts +12 -3
  7. package/dist/src/base/BaseLines.d.ts +27 -0
  8. package/dist/src/base/types.d.ts +2 -2
  9. package/dist/src/grid/plugins/BarStack.d.ts +1 -3
  10. package/dist/src/grid/plugins/Bars.d.ts +1 -3
  11. package/dist/src/grid/plugins/BarsTriangle.d.ts +1 -3
  12. package/dist/src/grid/plugins/Lines.d.ts +1 -3
  13. package/dist/src/index.d.ts +1 -0
  14. package/dist/src/multiGrid/defaults.d.ts +3 -0
  15. package/dist/src/multiGrid/index.d.ts +3 -0
  16. package/dist/src/multiGrid/plugins/BarsAndLines.d.ts +1 -0
  17. package/dist/src/multiGrid/types.d.ts +7 -0
  18. package/package.json +2 -2
  19. package/src/base/BaseBarStack.ts +699 -0
  20. package/src/base/BaseBars.ts +639 -0
  21. package/src/base/BaseBarsTriangle.ts +626 -0
  22. package/src/base/BaseLegend.ts +9 -7
  23. package/src/base/BaseLines.ts +566 -0
  24. package/src/base/types.ts +2 -2
  25. package/src/grid/plugins/BarStack.ts +16 -643
  26. package/src/grid/plugins/Bars.ts +15 -586
  27. package/src/grid/plugins/BarsTriangle.ts +14 -577
  28. package/src/grid/plugins/Lines.ts +14 -508
  29. package/src/index.ts +1 -0
  30. package/src/multiGrid/defaults.ts +14 -0
  31. package/src/multiGrid/index.ts +3 -0
  32. package/src/multiGrid/plugins/BarStackAndLines.ts +0 -0
  33. package/src/multiGrid/plugins/BarsAndLines.ts +110 -0
  34. package/src/multiGrid/plugins/BarsTriangleAndLines.ts +0 -0
  35. package/src/multiGrid/plugins/DivergingValueAxes.ts +0 -0
  36. package/src/multiGrid/plugins/FirstGroupScaleAxis.ts +0 -0
  37. package/src/multiGrid/plugins/MultiGridLegend.ts +0 -0
  38. package/src/multiGrid/plugins/TwoValueScaleAxes.ts +0 -0
  39. package/src/multiGrid/types.ts +8 -0
  40. /package/dist/src/multiGrid/plugins/{DivergingAxes.d.ts → BarStackAndLines.d.ts} +0 -0
  41. /package/dist/src/multiGrid/plugins/{TwoScaleAxes.d.ts → BarsTriangleAndLines.d.ts} +0 -0
  42. /package/dist/src/multiGrid/plugins/{TwoScales.d.ts → DivergingValueAxes.d.ts} +0 -0
  43. /package/{src/multiGrid/plugins/DivergingAxes.ts → dist/src/multiGrid/plugins/FirstGroupScaleAxis.d.ts} +0 -0
  44. /package/{src/multiGrid/plugins/TwoScaleAxes.ts → dist/src/multiGrid/plugins/MultiGridLegend.d.ts} +0 -0
  45. /package/{src/multiGrid/plugins/TwoScales.ts → dist/src/multiGrid/plugins/TwoValueScaleAxes.d.ts} +0 -0
@@ -0,0 +1,699 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ switchMap,
6
+ takeUntil,
7
+ distinctUntilChanged,
8
+ Observable,
9
+ Subject } from 'rxjs'
10
+ import type { BasePluginFn } from './types'
11
+ import type {
12
+ ComputedDatumGrid,
13
+ ComputedDataGrid,
14
+ DataFormatterGrid,
15
+ EventGrid,
16
+ ChartParams,
17
+ Layout,
18
+ TransformData } from '@orbcharts/core'
19
+ import { getD3TransitionEase } from '../utils/d3Utils'
20
+ import { getClassName, getUniID } from '../utils/orbchartsUtils'
21
+
22
+ export interface BaseBarStackParams {
23
+ barWidth: number
24
+ barGroupPadding: number
25
+ barRadius: number | boolean
26
+ }
27
+
28
+ interface BaseBarStackContext {
29
+ selection: d3.Selection<any, unknown, any, unknown>
30
+ computedData$: Observable<ComputedDataGrid>
31
+ visibleComputedData$: Observable<ComputedDatumGrid[][]>
32
+ SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
33
+ GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
34
+ fullParams$: Observable<BaseBarStackParams>
35
+ fullDataFormatter$: Observable<DataFormatterGrid>
36
+ fullChartParams$: Observable<ChartParams>
37
+ gridAxesTransform$: Observable<TransformData>
38
+ gridGraphicTransform$: Observable<TransformData>
39
+ gridAxesSize$: Observable<{
40
+ width: number;
41
+ height: number;
42
+ }>
43
+ gridHighlight$: Observable<string[]>
44
+ event$: Subject<EventGrid>
45
+ }
46
+
47
+
48
+ interface GraphicDatum extends ComputedDatumGrid {
49
+ _barStartY: number // bar的起點y座標
50
+ _barHeight: number // bar的高度
51
+ }
52
+
53
+ interface RenderBarParams {
54
+ selection: d3.Selection<SVGGElement, unknown, any, any>
55
+ data: GraphicDatum[][]
56
+ zeroY: number
57
+ groupLabels: string[]
58
+ // barScale: d3.ScalePoint<string>
59
+ params: BaseBarStackParams
60
+ chartParams: ChartParams
61
+ barWidth: number
62
+ transformedBarRadius: [number, number]
63
+ delayGroup: number
64
+ transitionItem: number
65
+ }
66
+
67
+ type ClipPathDatum = {
68
+ id: string;
69
+ // x: number;
70
+ // y: number;
71
+ width: number;
72
+ height: number;
73
+ }
74
+
75
+ const pluginName = 'BarStack'
76
+ const gClassName = getClassName(pluginName, 'g')
77
+ const gContentClassName = getClassName(pluginName, 'g-content')
78
+ // group的delay在動畫中的佔比(剩餘部份的時間為圖形本身的動畫時間,因為delay時間和最後一個group的動畫時間加總為1)
79
+ const groupDelayProportionOfDuration = 0.3
80
+
81
+ function calcBarWidth ({ axisWidth, groupAmount, barGroupPadding = 0 }: {
82
+ axisWidth: number
83
+ groupAmount: number
84
+ barGroupPadding: number
85
+ }) {
86
+ const eachGroupWidth = axisWidth / (groupAmount - 1)
87
+ const width = eachGroupWidth - barGroupPadding
88
+ return width > 1 ? width : 1
89
+
90
+ }
91
+
92
+ // function makeBarScale (barWidth: number, seriesLabels: string[], params: BarStackParams) {
93
+ // const barHalfWidth = barWidth! / 2
94
+ // const barGroupWidth = barWidth * seriesLabels.length + params.barPadding! * seriesLabels.length
95
+ // return d3.scalePoint()
96
+ // .domain(seriesLabels)
97
+ // .range([-barGroupWidth / 2 + barHalfWidth, barGroupWidth / 2 - barHalfWidth])
98
+ // }
99
+
100
+ function calcDelayGroup (barGroupAmount: number, totalDuration: number) {
101
+ if (barGroupAmount <= 1) {
102
+ // 一筆內計算會出錯所以不算
103
+ return 0
104
+ }
105
+ return totalDuration / (barGroupAmount - 1) * groupDelayProportionOfDuration // 依group數量計算
106
+ }
107
+
108
+ function calctransitionItem (barGroupAmount: number, totalDuration: number) {
109
+ if (barGroupAmount <= 1) {
110
+ // 一筆內不會有delay
111
+ return totalDuration
112
+ }
113
+ return totalDuration * (1 - groupDelayProportionOfDuration) // delay後剩餘的時間
114
+ }
115
+
116
+ function renderRectBars ({ selection, data, zeroY, groupLabels, params, chartParams, barWidth, transformedBarRadius, delayGroup, transitionItem }: RenderBarParams) {
117
+
118
+ const barHalfWidth = barWidth! / 2
119
+
120
+ const barGroup = selection
121
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${gClassName}`)
122
+ .data(data, (d, i) => groupLabels[i])
123
+ .join(
124
+ enter => {
125
+ return enter
126
+ .append('g')
127
+ .classed(gClassName, true)
128
+ .attr('cursor', 'pointer')
129
+ },
130
+ update => update,
131
+ exit => exit.remove()
132
+ )
133
+ .attr('transform', (d, i) => `translate(${d[0] ? d[0].axisX : 0}, ${0})`)
134
+ .each((d, i, g) => {
135
+ const bars = d3.select(g[i])
136
+ .selectAll<SVGGElement, ComputedDatumGrid>('g')
137
+ .data(d, _d => _d.id)
138
+ .join(
139
+ enter => {
140
+ return enter
141
+ .append('g')
142
+ .classed(gContentClassName, true)
143
+ },
144
+ update => update,
145
+ exit => exit.remove()
146
+ )
147
+ .each((_d, _i, _g) => {
148
+ const rect = d3.select(_g[_i])
149
+ .selectAll<SVGRectElement, ComputedDatumGrid>('rect')
150
+ .data([_d], _d => _d.id)
151
+ .join(
152
+ enter => {
153
+ return enter
154
+ .append('rect')
155
+ .attr('y', d => zeroY)
156
+ .attr('height', d => 0)
157
+ },
158
+ update => update,
159
+ exit => exit.remove()
160
+ )
161
+ .attr('rx', transformedBarRadius[0])
162
+ .attr('ry', transformedBarRadius[1])
163
+ .attr('fill', d => d.color)
164
+ .attr('transform', `translate(${-barHalfWidth}, 0)`)
165
+ .attr('x', d => 0)
166
+ .attr('width', barWidth!)
167
+ .transition()
168
+ .duration(transitionItem)
169
+ .ease(getD3TransitionEase(chartParams.transitionEase))
170
+ .delay((d, i) => d.groupIndex * delayGroup)
171
+ .attr('y', d => d._barStartY)
172
+ .attr('height', d => Math.abs(d._barHeight))
173
+ })
174
+
175
+ })
176
+
177
+ const graphicBarSelection: d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown> = barGroup.selectAll(`g.${gContentClassName}`)
178
+
179
+
180
+ return graphicBarSelection
181
+ }
182
+
183
+ function renderClipPath ({ defsSelection, clipPathData }: {
184
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
185
+ clipPathData: ClipPathDatum[]
186
+ }) {
187
+ const clipPath = defsSelection
188
+ .selectAll<SVGClipPathElement, Layout>('clipPath')
189
+ .data(clipPathData)
190
+ .join(
191
+ enter => {
192
+ return enter
193
+ .append('clipPath')
194
+ },
195
+ update => update,
196
+ exit => exit.remove()
197
+ )
198
+ .attr('id', d => d.id)
199
+ .each((d, i, g) => {
200
+ const rect = d3.select(g[i])
201
+ .selectAll<SVGRectElement, typeof d>('rect')
202
+ .data([d])
203
+ .join(
204
+ enter => {
205
+ return enter
206
+ .append('rect')
207
+ },
208
+ update => update,
209
+ exit => exit.remove()
210
+ )
211
+ .attr('x', 0)
212
+ .attr('y', 0)
213
+ .attr('width', _d => _d.width)
214
+ .attr('height', _d => _d.height)
215
+ })
216
+ }
217
+
218
+ function highlight ({ selection, ids, fullChartParams }: {
219
+ selection: d3.Selection<any, ComputedDatumGrid, any, any>
220
+ ids: string[]
221
+ fullChartParams: ChartParams
222
+ }) {
223
+ selection.interrupt('highlight')
224
+
225
+ if (!ids.length) {
226
+ // remove highlight
227
+ selection
228
+ .transition('highlight')
229
+ .duration(200)
230
+ .style('opacity', 1)
231
+ return
232
+ }
233
+
234
+ selection
235
+ .each((d, i, n) => {
236
+ if (ids.includes(d.id)) {
237
+ d3.select(n[i])
238
+ .style('opacity', 1)
239
+ } else {
240
+ d3.select(n[i])
241
+ .style('opacity', fullChartParams.styles.unhighlightedOpacity)
242
+ }
243
+ })
244
+ }
245
+
246
+
247
+ export const createBaseBarStack: BasePluginFn<BaseBarStackContext> = (pluginName: string, {
248
+ selection,
249
+ computedData$,
250
+ visibleComputedData$,
251
+ SeriesDataMap$,
252
+ GroupDataMap$,
253
+ fullParams$,
254
+ fullDataFormatter$,
255
+ fullChartParams$,
256
+ gridAxesTransform$,
257
+ gridGraphicTransform$,
258
+ gridAxesSize$,
259
+ gridHighlight$,
260
+ event$
261
+ }) => {
262
+
263
+ const destroy$ = new Subject()
264
+
265
+ const clipPathID = getUniID(pluginName, 'clipPath-box')
266
+
267
+ const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
268
+ .append('g')
269
+ .attr('clip-path', `url(#${clipPathID})`)
270
+ const defsSelection: d3.Selection<SVGDefsElement, ComputedDatumGrid, any, any> = axisSelection.append('defs')
271
+ const graphicGSelection: d3.Selection<SVGGElement, any, any, any> = axisSelection.append('g')
272
+ const barSelection$: Subject<d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown>> = new Subject()
273
+
274
+ gridAxesTransform$
275
+ .pipe(
276
+ takeUntil(destroy$),
277
+ map(d => d.value),
278
+ distinctUntilChanged()
279
+ ).subscribe(d => {
280
+ axisSelection
281
+ .style('transform', d)
282
+ })
283
+
284
+ gridGraphicTransform$
285
+ .pipe(
286
+ takeUntil(destroy$),
287
+ switchMap(async d => d.value),
288
+ distinctUntilChanged()
289
+ ).subscribe(d => {
290
+ graphicGSelection
291
+ .transition()
292
+ .duration(50)
293
+ .style('transform', d)
294
+ })
295
+
296
+ // const axisSize$ = gridAxisSizeObservable({
297
+ // dataFormatter$,
298
+ // layout$
299
+ // })
300
+
301
+ // const visibleComputedData$ = computedData$.pipe(
302
+ // takeUntil(destroy$),
303
+ // map(data => {
304
+ // const visibleComputedData = data
305
+ // .map(d => {
306
+ // return d.filter(_d => {
307
+ // return _d.visible == true
308
+ // })
309
+ // })
310
+ // .filter(d => d.length)
311
+ // // console.log('visibleComputedData', visibleComputedData)
312
+ // return visibleComputedData
313
+ // })
314
+ // )
315
+
316
+ const zeroY$ = visibleComputedData$.pipe(
317
+ map(d => d[0] && d[0][0]
318
+ ? d[0][0].axisY - d[0][0].axisYFromZero
319
+ : 0),
320
+ distinctUntilChanged()
321
+ )
322
+
323
+ const barWidth$ = new Observable<number>(subscriber => {
324
+ combineLatest({
325
+ computedData: computedData$,
326
+ // visibleComputedData: visibleComputedData$,
327
+ params: fullParams$,
328
+ axisSize: gridAxesSize$
329
+ }).pipe(
330
+ switchMap(async d => d)
331
+ ).subscribe(data => {
332
+ const barWidth = data.params.barWidth
333
+ ? data.params.barWidth
334
+ : calcBarWidth({
335
+ axisWidth: data.axisSize.width,
336
+ groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
337
+ barGroupPadding: data.params.barGroupPadding
338
+ })
339
+ subscriber.next(barWidth)
340
+ })
341
+ }).pipe(
342
+ takeUntil(destroy$),
343
+ distinctUntilChanged()
344
+ )
345
+
346
+ // 圓角的值 [rx, ry]
347
+ const transformedBarRadius$: Observable<[number, number]> = combineLatest({
348
+ gridGraphicTransform: gridGraphicTransform$,
349
+ barWidth: barWidth$,
350
+ params: fullParams$
351
+ }).pipe(
352
+ takeUntil(destroy$),
353
+ switchMap(async data => data),
354
+ map(data => {
355
+ const barHalfWidth = data.barWidth! / 2
356
+ const radius = data.params.barRadius === true ? barHalfWidth
357
+ : data.params.barRadius === false ? 0
358
+ : typeof data.params.barRadius == 'number' ? data.params.barRadius
359
+ : 0
360
+ const transformedRx = radius == 0
361
+ ? 0
362
+ : radius / data.gridGraphicTransform.scale[0] // 反向外層scale的變型
363
+ const transformedRy = radius == 0
364
+ ? 0
365
+ : radius / data.gridGraphicTransform.scale[1]
366
+ return [transformedRx, transformedRy]
367
+ })
368
+ )
369
+
370
+ // const seriesLabels$ = visibleComputedData$.pipe(
371
+ // takeUntil(destroy$),
372
+ // map(data => {
373
+ // const SeriesLabelSet: Set<string> = new Set()
374
+ // data.forEach(d => {
375
+ // d.forEach(_d => {
376
+ // SeriesLabelSet.add(_d.seriesLabel)
377
+ // })
378
+ // })
379
+ // return Array.from(SeriesLabelSet)
380
+ // })
381
+ // )
382
+
383
+ const groupLabels$ = visibleComputedData$.pipe(
384
+ takeUntil(destroy$),
385
+ map(data => {
386
+ const GroupLabelSet: Set<string> = new Set()
387
+ data.forEach(d => {
388
+ d.forEach(_d => {
389
+ GroupLabelSet.add(_d.groupLabel)
390
+ })
391
+ })
392
+ return Array.from(GroupLabelSet)
393
+ })
394
+ )
395
+
396
+ // const barScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
397
+ // combineLatest({
398
+ // seriesLabels: seriesLabels$,
399
+ // barWidth: barWidth$,
400
+ // params: fullParams$,
401
+ // }).pipe(
402
+ // takeUntil(destroy$),
403
+ // switchMap(async d => d)
404
+ // ).subscribe(data => {
405
+ // const barScale = makeBarScale(data.barWidth, data.seriesLabels, data.params)
406
+ // subscriber.next(barScale)
407
+ // })
408
+ // })
409
+
410
+ const transitionDuration$ = fullChartParams$.pipe(
411
+ takeUntil(destroy$),
412
+ map(d => d.transitionDuration),
413
+ distinctUntilChanged()
414
+ )
415
+
416
+ const delayGroup$ = new Observable<number>(subscriber => {
417
+ combineLatest({
418
+ groupLabels: groupLabels$,
419
+ transitionDuration: transitionDuration$,
420
+ }).pipe(
421
+ switchMap(async d => d)
422
+ ).subscribe(data => {
423
+ const delay = calcDelayGroup(data.groupLabels.length, data.transitionDuration)
424
+ subscriber.next(delay)
425
+ })
426
+ }).pipe(
427
+ takeUntil(destroy$),
428
+ distinctUntilChanged()
429
+ )
430
+
431
+ const transitionItem$ = new Observable<number>(subscriber => {
432
+ combineLatest({
433
+ groupLabels: groupLabels$,
434
+ transitionDuration: transitionDuration$
435
+ }).pipe(
436
+ switchMap(async d => d)
437
+ ).subscribe(data => {
438
+ const transition = calctransitionItem(data.groupLabels.length, data.transitionDuration)
439
+ subscriber.next(transition)
440
+ })
441
+ }).pipe(
442
+ takeUntil(destroy$),
443
+ distinctUntilChanged()
444
+ )
445
+
446
+ const transposedVisibleData$: Observable<ComputedDataGrid> = visibleComputedData$.pipe(
447
+ takeUntil(destroy$),
448
+ map(data => {
449
+ console.log('visibleComputedData', data)
450
+ // 取得原始陣列的維度
451
+ const rows = data.length;
452
+ const cols = data.reduce((prev, current) => {
453
+ return Math.max(prev, current.length)
454
+ }, 0)
455
+
456
+ // 初始化轉換後的陣列
457
+ const transposedArray = new Array(cols).fill(null).map(() => new Array(rows).fill(null))
458
+
459
+ // 遍歷原始陣列,進行轉換
460
+ for (let i = 0; i < rows; i++) {
461
+ for (let j = 0; j < cols; j++) {
462
+ transposedArray[j][i] = data[i][j]
463
+ }
464
+ }
465
+ return transposedArray
466
+ })
467
+ )
468
+
469
+ const yRatio$ = combineLatest({
470
+ transposedVisibleData: transposedVisibleData$,
471
+ dataFormatter: fullDataFormatter$,
472
+ }).pipe(
473
+ takeUntil(destroy$),
474
+ switchMap(async d => d),
475
+ map(data => {
476
+ const groupMin = 0
477
+ const groupMax = data.transposedVisibleData.length - 1
478
+ const groupScaleDomainMin = data.dataFormatter.groupAxis.scaleDomain[0] === 'auto'
479
+ ? groupMin - data.dataFormatter.groupAxis.scalePadding
480
+ : data.dataFormatter.groupAxis.scaleDomain[0] as number - data.dataFormatter.groupAxis.scalePadding
481
+ const groupScaleDomainMax = data.dataFormatter.groupAxis.scaleDomain[1] === 'auto'
482
+ ? groupMax + data.dataFormatter.groupAxis.scalePadding
483
+ : data.dataFormatter.groupAxis.scaleDomain[1] as number + data.dataFormatter.groupAxis.scalePadding
484
+
485
+ const filteredData = data.transposedVisibleData
486
+ .map(d => {
487
+ return d.filter((_d, i) => {
488
+ return _d.groupIndex >= groupScaleDomainMin && _d.groupIndex <= groupScaleDomainMax
489
+ })
490
+ })
491
+ // console.log('filteredData', filteredData)
492
+
493
+ if (!filteredData.flat().length) {
494
+ return 1
495
+ } else {
496
+ const yArr = filteredData.flat().map(d => d.axisYFromZero)
497
+ const barMaxY = Math.max(...yArr)
498
+ const stackYArr = filteredData.map(d => d.reduce((prev, current) => prev + current.axisYFromZero, 0))
499
+ const barStackMaxY = Math.max(...stackYArr)
500
+
501
+ return barMaxY / barStackMaxY
502
+ }
503
+ })
504
+ )
505
+
506
+ const graphicData$ = combineLatest({
507
+ transposedVisibleData: transposedVisibleData$,
508
+ yRatio: yRatio$,
509
+ zeroY: zeroY$
510
+ }).pipe(
511
+ takeUntil(destroy$),
512
+ map(data => {
513
+ console.log(data.transposedVisibleData)
514
+ return data.transposedVisibleData.map(d => {
515
+ let accY = data.zeroY
516
+ return d.map(_d => {
517
+ const _barStartY = accY
518
+ const _barHeight = _d.axisYFromZero * data.yRatio
519
+ accY = accY + _barHeight
520
+ return <GraphicDatum>{
521
+ ..._d,
522
+ _barStartY,
523
+ _barHeight
524
+ }
525
+ })
526
+ })
527
+ })
528
+ )
529
+
530
+ gridAxesSize$.pipe(
531
+ takeUntil(destroy$)
532
+ ).subscribe(data => {
533
+ const clipPathData = [{
534
+ id: clipPathID,
535
+ width: data.width,
536
+ height: data.height
537
+ }]
538
+ renderClipPath({
539
+ defsSelection,
540
+ clipPathData
541
+ })
542
+ })
543
+
544
+ // const SeriesDataMap$ = visibleComputedData$.pipe(
545
+ // map(d => makeGridSeriesDataMap(d))
546
+ // )
547
+
548
+ // const GroupDataMap$ = visibleComputedData$.pipe(
549
+ // map(d => makeGridGroupDataMap(d))
550
+ // )
551
+
552
+ const highlightTarget$ = fullChartParams$.pipe(
553
+ takeUntil(destroy$),
554
+ map(d => d.highlightTarget),
555
+ distinctUntilChanged()
556
+ )
557
+
558
+ combineLatest({
559
+ // renderBarsFn: renderBarsFn$,
560
+ graphicData: graphicData$,
561
+ zeroY: zeroY$,
562
+ groupLabels: groupLabels$,
563
+ // barScale: barScale$,
564
+ params: fullParams$,
565
+ chartParams: fullChartParams$,
566
+ highlightTarget: highlightTarget$,
567
+ barWidth: barWidth$,
568
+ transformedBarRadius: transformedBarRadius$,
569
+ delayGroup: delayGroup$,
570
+ transitionItem: transitionItem$,
571
+ SeriesDataMap: SeriesDataMap$,
572
+ GroupDataMap: GroupDataMap$
573
+ }).pipe(
574
+ takeUntil(destroy$),
575
+ // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
576
+ switchMap(async (d) => d),
577
+ ).subscribe(data => {
578
+ const barSelection = renderRectBars({
579
+ selection: graphicGSelection,
580
+ data: data.graphicData,
581
+ zeroY: data.zeroY,
582
+ groupLabels: data.groupLabels,
583
+ // barScale: data.barScale,
584
+ params: data.params,
585
+ chartParams: data.chartParams,
586
+ barWidth: data.barWidth,
587
+ transformedBarRadius: data.transformedBarRadius,
588
+ delayGroup: data.delayGroup,
589
+ transitionItem: data.transitionItem
590
+ })
591
+
592
+ barSelection!
593
+ .on('mouseover', (event, datum) => {
594
+ event.stopPropagation()
595
+
596
+ event$.next({
597
+ type: 'grid',
598
+ eventName: 'mouseover',
599
+ pluginName,
600
+ highlightTarget: data.highlightTarget,
601
+ datum,
602
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
603
+ seriesIndex: datum.seriesIndex,
604
+ seriesLabel: datum.seriesLabel,
605
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
606
+ groupIndex: datum.groupIndex,
607
+ groupLabel: datum.groupLabel,
608
+ event,
609
+ data: data.graphicData
610
+ })
611
+ })
612
+ .on('mousemove', (event, datum) => {
613
+ event.stopPropagation()
614
+
615
+ event$.next({
616
+ type: 'grid',
617
+ eventName: 'mousemove',
618
+ pluginName,
619
+ highlightTarget: data.highlightTarget,
620
+ datum,
621
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
622
+ seriesIndex: datum.seriesIndex,
623
+ seriesLabel: datum.seriesLabel,
624
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
625
+ groupIndex: datum.groupIndex,
626
+ groupLabel: datum.groupLabel,
627
+ event,
628
+ data: data.graphicData
629
+ })
630
+ })
631
+ .on('mouseout', (event, datum) => {
632
+ event.stopPropagation()
633
+
634
+ event$.next({
635
+ type: 'grid',
636
+ eventName: 'mouseout',
637
+ pluginName,
638
+ highlightTarget: data.highlightTarget,
639
+ datum,
640
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
641
+ seriesIndex: datum.seriesIndex,
642
+ seriesLabel: datum.seriesLabel,
643
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
644
+ groupIndex: datum.groupIndex,
645
+ groupLabel: datum.groupLabel,
646
+ event,
647
+ data: data.graphicData
648
+ })
649
+ })
650
+ .on('click', (event, datum) => {
651
+ event.stopPropagation()
652
+
653
+ event$.next({
654
+ type: 'grid',
655
+ eventName: 'click',
656
+ pluginName,
657
+ highlightTarget: data.highlightTarget,
658
+ datum,
659
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
660
+ seriesIndex: datum.seriesIndex,
661
+ seriesLabel: datum.seriesLabel,
662
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
663
+ groupIndex: datum.groupIndex,
664
+ groupLabel: datum.groupLabel,
665
+ event,
666
+ data: data.graphicData
667
+ })
668
+ })
669
+
670
+ barSelection$.next(barSelection!)
671
+ })
672
+
673
+ // const datumList$ = computedData$.pipe(
674
+ // takeUntil(destroy$),
675
+ // map(d => d.flat())
676
+ // )
677
+ // const highlight$ = highlightObservable({ datumList$, chartParams$, event$: store.event$ })
678
+ const highlightSubscription = gridHighlight$.subscribe()
679
+
680
+ combineLatest({
681
+ barSelection: barSelection$,
682
+ highlight: gridHighlight$,
683
+ fullChartParams: fullChartParams$
684
+ }).pipe(
685
+ takeUntil(destroy$),
686
+ switchMap(async d => d)
687
+ ).subscribe(data => {
688
+ highlight({
689
+ selection: data.barSelection,
690
+ ids: data.highlight,
691
+ fullChartParams: data.fullChartParams
692
+ })
693
+ })
694
+
695
+ return () => {
696
+ destroy$.next(undefined)
697
+ highlightSubscription.unsubscribe()
698
+ }
699
+ }