@orbcharts/plugins-basic 3.0.0-alpha.41 → 3.0.0-alpha.43

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +5477 -5426
  3. package/dist/orbcharts-plugins-basic.umd.js +8 -8
  4. package/dist/src/base/BaseBarStack.d.ts +1 -1
  5. package/dist/src/base/BaseBars.d.ts +1 -1
  6. package/dist/src/base/BaseBarsTriangle.d.ts +1 -1
  7. package/dist/src/base/BaseDots.d.ts +1 -1
  8. package/dist/src/base/BaseLineAreas.d.ts +1 -1
  9. package/dist/src/base/BaseLines.d.ts +1 -1
  10. package/dist/src/multiGrid/defaults.d.ts +2 -1
  11. package/dist/src/multiGrid/index.d.ts +1 -0
  12. package/dist/src/multiGrid/plugins/MultiLineAreas.d.ts +1 -0
  13. package/dist/src/multiGrid/types.d.ts +4 -4
  14. package/package.json +42 -42
  15. package/src/base/BaseBarStack.ts +881 -879
  16. package/src/base/BaseBars.ts +750 -748
  17. package/src/base/BaseBarsTriangle.ts +659 -657
  18. package/src/base/BaseDots.ts +639 -637
  19. package/src/base/BaseGroupAxis.ts +496 -496
  20. package/src/base/BaseLegend.ts +636 -636
  21. package/src/base/BaseLineAreas.ts +621 -624
  22. package/src/base/BaseLines.ts +692 -695
  23. package/src/base/BaseValueAxis.ts +479 -479
  24. package/src/base/types.ts +2 -2
  25. package/src/grid/defaults.ts +121 -121
  26. package/src/grid/gridObservables.ts +263 -263
  27. package/src/grid/index.ts +15 -15
  28. package/src/grid/plugins/BarStack.ts +37 -37
  29. package/src/grid/plugins/Bars.ts +37 -37
  30. package/src/grid/plugins/BarsDiverging.ts +39 -39
  31. package/src/grid/plugins/BarsTriangle.ts +34 -34
  32. package/src/grid/plugins/Dots.ts +35 -35
  33. package/src/grid/plugins/GridLegend.ts +58 -58
  34. package/src/grid/plugins/GroupAux.ts +643 -643
  35. package/src/grid/plugins/GroupAxis.ts +30 -30
  36. package/src/grid/plugins/LineAreas.ts +36 -36
  37. package/src/grid/plugins/Lines.ts +35 -35
  38. package/src/grid/plugins/ScalingArea.ts +174 -174
  39. package/src/grid/plugins/ValueAxis.ts +31 -31
  40. package/src/grid/plugins/ValueStackAxis.ts +70 -70
  41. package/src/grid/types.ts +120 -120
  42. package/src/index.ts +9 -9
  43. package/src/multiGrid/defaults.ts +147 -140
  44. package/src/multiGrid/index.ts +11 -10
  45. package/src/multiGrid/multiGridObservables.ts +289 -278
  46. package/src/multiGrid/plugins/MultiBarStack.ts +60 -60
  47. package/src/multiGrid/plugins/MultiBars.ts +59 -59
  48. package/src/multiGrid/plugins/MultiBarsTriangle.ts +58 -58
  49. package/src/multiGrid/plugins/MultiDots.ts +58 -58
  50. package/src/multiGrid/plugins/MultiGridLegend.ts +88 -88
  51. package/src/multiGrid/plugins/MultiGroupAxis.ts +53 -53
  52. package/src/multiGrid/plugins/MultiLineAreas.ts +59 -0
  53. package/src/multiGrid/plugins/MultiLines.ts +58 -58
  54. package/src/multiGrid/plugins/MultiValueAxis.ts +53 -53
  55. package/src/multiGrid/plugins/OverlappingValueAxes.ts +164 -165
  56. package/src/multiGrid/types.ts +67 -67
  57. package/src/noneData/defaults.ts +61 -61
  58. package/src/noneData/index.ts +3 -3
  59. package/src/noneData/plugins/Container.ts +10 -10
  60. package/src/noneData/plugins/Tooltip.ts +304 -304
  61. package/src/noneData/types.ts +26 -26
  62. package/src/series/defaults.ts +99 -99
  63. package/src/series/index.ts +6 -6
  64. package/src/series/plugins/Bubbles.ts +551 -549
  65. package/src/series/plugins/Pie.ts +600 -598
  66. package/src/series/plugins/PieEventTexts.ts +194 -194
  67. package/src/series/plugins/PieLabels.ts +288 -285
  68. package/src/series/plugins/SeriesLegend.ts +58 -58
  69. package/src/series/seriesUtils.ts +50 -50
  70. package/src/series/types.ts +67 -67
  71. package/src/tree/defaults.ts +22 -22
  72. package/src/tree/index.ts +3 -3
  73. package/src/tree/plugins/TreeLegend.ts +58 -58
  74. package/src/tree/plugins/TreeMap.ts +302 -300
  75. package/src/tree/types.ts +23 -23
  76. package/src/utils/commonUtils.ts +21 -21
  77. package/src/utils/d3Graphics.ts +124 -124
  78. package/src/utils/d3Utils.ts +73 -73
  79. package/src/utils/observables.ts +14 -14
  80. package/src/utils/orbchartsUtils.ts +100 -100
  81. package/tsconfig.dev.json +16 -16
  82. package/tsconfig.json +13 -13
  83. package/tsconfig.prod.json +13 -13
  84. package/vite.config.js +49 -49
@@ -1,625 +1,622 @@
1
- import * as d3 from 'd3'
2
- import {
3
- combineLatest,
4
- map,
5
- filter,
6
- switchMap,
7
- takeUntil,
8
- distinctUntilChanged,
9
- Observable,
10
- Subject } from 'rxjs'
11
- import type { BasePluginFn } from './types'
12
- import type {
13
- ComputedDatumGrid,
14
- ComputedDataGrid,
15
- DataFormatterGrid,
16
- EventGrid,
17
- ContainerPosition,
18
- ChartParams,
19
- Layout,
20
- TransformData } from '@orbcharts/core'
21
- import { DATA_FORMATTER_VALUE_AXIS } from '@orbcharts/core/src/defaults'
22
- import { createAxisLinearScale } from '@orbcharts/core'
23
- import { getD3TransitionEase } from '../utils/d3Utils'
24
- import { getClassName, getUniID, getMinAndMaxValue } from '../utils/orbchartsUtils'
25
- import { gridGroupPositionFnObservable } from '../grid/gridObservables'
26
- import { gridSelectionsObservable } from '../grid/gridObservables'
27
-
28
- export interface BaseLineAreasParams {
29
- lineCurve: string
30
- // lineWidth: number
31
- linearGradientOpacity: [number, number]
32
- }
33
-
34
- interface BaseLineAreasContext {
35
- selection: d3.Selection<any, unknown, any, unknown>
36
- computedData$: Observable<ComputedDataGrid>
37
- existSeriesLabels$: Observable<string[]>
38
- SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
39
- GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
40
- fullDataFormatter$: Observable<DataFormatterGrid>
41
- fullParams$: Observable<BaseLineAreasParams>
42
- fullChartParams$: Observable<ChartParams>
43
- gridAxesTransform$: Observable<TransformData>
44
- gridGraphicTransform$: Observable<TransformData>
45
- gridAxesSize$: Observable<{
46
- width: number;
47
- height: number;
48
- }>
49
- gridHighlight$: Observable<string[]>
50
- gridContainer$: Observable<ContainerPosition[]>
51
- layout$: Observable<Layout>
52
- event$: Subject<EventGrid>
53
- }
54
-
55
- type ClipPathDatum = {
56
- id: string;
57
- // x: number;
58
- // y: number;
59
- width: number;
60
- height: number;
61
- }
62
-
63
- // const pluginName = 'Lines'
64
- // const pathClassName = getClassName(pluginName, 'path')
65
-
66
-
67
- function createAreaPath (lineCurve: string = 'curveLinear', valueAxisStart: number): d3.Line<ComputedDatumGrid> {
68
- return d3.area<ComputedDatumGrid>()
69
- .x((d) => d.axisX)
70
- .y0(d => valueAxisStart)
71
- .y1((d) => d.axisY)
72
- .curve((d3 as any)[lineCurve])
73
-
74
- }
75
-
76
- // 依無值的資料分段
77
- function makeSegmentData (data: ComputedDatumGrid[]): ComputedDatumGrid[][] {
78
- let segmentData: ComputedDatumGrid[][] = [[]]
79
-
80
- let currentIndex = 0
81
- for (let i in data) {
82
- if (data[i].visible == false || data[i].value === undefined || data[i].value === null) {
83
- // 換下一段的 index
84
- if (segmentData[currentIndex].length) {
85
- currentIndex ++
86
- segmentData[currentIndex] = []
87
- }
88
- continue
89
- }
90
- segmentData[currentIndex].push(data[i])
91
- }
92
-
93
- return segmentData
94
- }
95
-
96
-
97
- function renderLineAreas ({ selection, pathClassName, segmentData, areaPath, linearGradientIds, params }: {
98
- selection: d3.Selection<SVGGElement, unknown, any, unknown>
99
- pathClassName: string
100
- segmentData: ComputedDatumGrid[][]
101
- areaPath: d3.Line<ComputedDatumGrid>
102
- linearGradientIds: string[]
103
- params: BaseLineAreasParams
104
- }): d3.Selection<SVGPathElement, ComputedDatumGrid[], any, any> {
105
- // if (!data[0]) {
106
- // return undefined
107
- // }
108
-
109
- const lineAreas = selection
110
- .selectAll<SVGPathElement, ComputedDatumGrid[]>('path')
111
- .data(segmentData, (d, i) => d.length ? `${d[0].id}_${d[d.length - 1].id}` : i) // 以線段起迄id結合為線段id
112
- .join(
113
- enter => {
114
- return enter
115
- .append<SVGPathElement>('path')
116
- .classed(pathClassName, true)
117
- .attr("fill","none")
118
- // .attr('pointer-events', 'visibleStroke') // 只對線條產生事件
119
- .style('vector-effect', 'non-scaling-stroke')
120
- .style('cursor', 'pointer')
121
- },
122
- update => update,
123
- exit => exit.remove()
124
- )
125
- // .attr("stroke-width", params.lineWidth)
126
- // .attr("stroke", (d, i) => d[0] && d[0].color)
127
- .attr("fill", (d, i) => d[0] ? `url(#${linearGradientIds[d[0].seriesIndex]})` : '')
128
- .attr("d", (d) => {
129
- return areaPath(d)
130
- })
131
-
132
- return lineAreas
133
- }
134
-
135
- function highlightLineAreas ({ selection, seriesLabel, fullChartParams }: {
136
- selection: d3.Selection<any, string, any, any>
137
- seriesLabel: string | null
138
- fullChartParams: ChartParams
139
- }) {
140
- selection.interrupt('highlight')
141
- if (!seriesLabel) {
142
- // remove highlight
143
- selection
144
- .transition('highlight')
145
- .duration(200)
146
- .style('opacity', 1)
147
- return
148
- }
149
-
150
- selection
151
- .each((currentSeriesLabel, i, n) => {
152
- // const currentSeriesLabel = d[0] ? d[0].seriesLabel : ''
153
-
154
- if (currentSeriesLabel === seriesLabel) {
155
- d3.select(n[i])
156
- .style('opacity', 1)
157
- } else {
158
- d3.select(n[i])
159
- .style('opacity', fullChartParams.styles.unhighlightedOpacity)
160
- }
161
- })
162
- }
163
-
164
- function renderLinearGradient ({ defsSelection, computedData, linearGradientIds, params }: {
165
- defsSelection: d3.Selection<SVGDefsElement, any, any, any>
166
- computedData: ComputedDataGrid
167
- linearGradientIds: string[]
168
- params: BaseLineAreasParams
169
- }) {
170
- defsSelection!
171
- .selectAll<SVGLinearGradientElement, ComputedDatumGrid>('linearGradient')
172
- .data(computedData ?? [])
173
- .join(
174
- enter => {
175
- return enter
176
- .append('linearGradient')
177
- .attr('x1', '0%')
178
- .attr('x2', '0%')
179
- .attr('y1', '100%')
180
- .attr('y2', '0%')
181
- .attr('spreadMethod', 'pad')
182
- },
183
- update => update,
184
- exit => exit.remove()
185
- )
186
- .attr('id', (d, i) => {
187
- return d[0] ? linearGradientIds[d[0].seriesIndex] : ''
188
- })
189
- .html((d, i) => {
190
- const color = d[0] ? d[0].color : ''
191
- return `
192
- <stop offset="0%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[0]}"/>
193
- <stop offset="100%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[1]}"/>
194
- `
195
- })
196
-
197
- }
198
-
199
- function renderClipPath ({ defsSelection, clipPathData, transitionDuration, transitionEase }: {
200
- defsSelection: d3.Selection<SVGDefsElement, any, any, any>
201
- clipPathData: ClipPathDatum[]
202
- transitionDuration: number
203
- transitionEase: string
204
- }) {
205
- const clipPath = defsSelection
206
- .selectAll<SVGClipPathElement, Layout>('clipPath')
207
- .data(clipPathData)
208
- .join(
209
- enter => {
210
- return enter
211
- .append('clipPath')
212
- },
213
- update => update,
214
- exit => exit.remove()
215
- )
216
- .attr('id', d => d.id)
217
- .each((d, i, g) => {
218
- const rect = d3.select(g[i])
219
- .selectAll<SVGRectElement, typeof d>('rect')
220
- .data([d])
221
- .join(
222
- enter => {
223
- const enterSelection = enter
224
- .append('rect')
225
- enterSelection
226
- .transition()
227
- .duration(transitionDuration)
228
- .ease(getD3TransitionEase(transitionEase))
229
- // .delay(100) // @Q@ 不知為何如果沒加 delay位置會有點跑掉
230
- .tween('tween', (_d, _i, _g) => {
231
- return (t) => {
232
- const transitionWidth = _d.width * t
233
-
234
- enterSelection
235
- .attr('x', 0)
236
- .attr('y', 0)
237
- .attr('width', _d => transitionWidth)
238
- .attr('height', _d => _d.height)
239
- }
240
- })
241
- return enterSelection
242
- },
243
- update => {
244
- return update
245
- .attr('x', 0)
246
- .attr('y', 0)
247
- .attr('width', _d => _d.width)
248
- .attr('height', _d => _d.height)
249
- },
250
- exit => exit.remove()
251
- )
252
- })
253
-
254
- }
255
-
256
- export const createBaseLineAreas: BasePluginFn<BaseLineAreasContext> = (pluginName: string, {
257
- selection,
258
- computedData$,
259
- existSeriesLabels$,
260
- SeriesDataMap$,
261
- GroupDataMap$,
262
- fullParams$,
263
- fullDataFormatter$,
264
- fullChartParams$,
265
- gridAxesTransform$,
266
- gridGraphicTransform$,
267
- gridAxesSize$,
268
- gridHighlight$,
269
- gridContainer$,
270
- layout$,
271
- event$
272
- }) => {
273
-
274
- const destroy$ = new Subject()
275
-
276
- const clipPathID = getUniID(pluginName, 'clipPath-box')
277
- const pathClassName = getClassName(pluginName, 'path')
278
-
279
- const {
280
- seriesSelection$,
281
- axesSelection$,
282
- defsSelection$,
283
- graphicGSelection$
284
- } = gridSelectionsObservable({
285
- selection,
286
- pluginName,
287
- clipPathID,
288
- existSeriesLabels$,
289
- gridContainer$,
290
- gridAxesTransform$,
291
- gridGraphicTransform$
292
- })
293
-
294
- // valueAxis 的起始座標
295
- const valueAxisStart$: Observable<number> = gridGraphicTransform$.pipe(
296
- takeUntil(destroy$),
297
- map(data => {
298
- // 抵消掉外層的變型
299
- return - data.translate[1] / data.scale[1]
300
- })
301
- )
302
-
303
- const areaPath$: Observable<d3.Line<ComputedDatumGrid>> = new Observable(subscriber => {
304
- const paramsSubscription = combineLatest({
305
- fullParams: fullParams$,
306
- valueAxisStart: valueAxisStart$
307
- }).pipe(
308
- takeUntil(destroy$)
309
- )
310
- .subscribe(d => {
311
- const areaPath = createAreaPath(d.fullParams.lineCurve, d.valueAxisStart)
312
- subscriber.next(areaPath)
313
- })
314
- return () => {
315
- paramsSubscription.unsubscribe()
316
- }
317
- })
318
-
319
- // 顯示範圍內的series labels
320
- const seriesLabels$: Observable<string[]> = new Observable(subscriber => {
321
- computedData$.pipe(
322
- takeUntil(destroy$),
323
- // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
324
- switchMap(async (d) => d),
325
- ).subscribe(data => {
326
- const labels = data[0] && data[0][0]
327
- ? data.map(d => d[0].seriesLabel)
328
- : []
329
- subscriber.next(labels)
330
- })
331
- })
332
-
333
- // const axisSize$ = gridAxisSizeObservable({
334
- // fullDataFormatter$,
335
- // computedLayout$
336
- // })
337
-
338
- const transitionDuration$ = fullChartParams$
339
- .pipe(
340
- map(d => d.transitionDuration),
341
- distinctUntilChanged()
342
- )
343
-
344
- const transitionEase$ = fullChartParams$
345
- .pipe(
346
- map(d => d.transitionEase),
347
- distinctUntilChanged()
348
- )
349
-
350
- const clipPathSubscription = combineLatest({
351
- defsSelection: defsSelection$,
352
- seriesLabels: seriesLabels$,
353
- axisSize: gridAxesSize$,
354
- transitionDuration: transitionDuration$,
355
- transitionEase: transitionEase$
356
- }).pipe(
357
- takeUntil(destroy$),
358
- // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
359
- switchMap(async (d) => d),
360
- ).subscribe(data => {
361
- // 外層的遮罩
362
- const clipPathBox = [{
363
- id: clipPathID,
364
- width: data.axisSize.width,
365
- height: data.axisSize.height
366
- }]
367
- // 各別線條的遮罩(各別動畫)
368
- const clipPathData = clipPathBox.concat(
369
- data.seriesLabels.map(d => {
370
- return {
371
- id: `orbcharts__clipPath_${d}`,
372
- width: data.axisSize.width,
373
- height: data.axisSize.height
374
- }
375
- })
376
- )
377
- renderClipPath({
378
- defsSelection: data.defsSelection,
379
- clipPathData,
380
- transitionDuration: data.transitionDuration,
381
- transitionEase: data.transitionEase
382
- })
383
- })
384
-
385
- // const SeriesDataMap$ = computedData$.pipe(
386
- // map(d => makeGridSeriesDataMap(d))
387
- // )
388
-
389
- // const GroupDataMap$ = computedData$.pipe(
390
- // map(d => makeGridGroupDataMap(d))
391
- // )
392
-
393
- const DataMap$ = computedData$.pipe(
394
- map(d => {
395
- const DataMap: Map<string, ComputedDatumGrid> = new Map()
396
- d.flat().forEach(_d => DataMap.set(_d.id, _d))
397
- return DataMap
398
- })
399
- )
400
-
401
- // 取得事件座標的group資料
402
- const gridGroupPositionFn$ = gridGroupPositionFnObservable({
403
- fullDataFormatter$,
404
- gridAxesSize$: gridAxesSize$,
405
- computedData$: computedData$,
406
- fullChartParams$: fullChartParams$
407
- })
408
-
409
- const highlightTarget$ = fullChartParams$.pipe(
410
- takeUntil(destroy$),
411
- map(d => d.highlightTarget),
412
- distinctUntilChanged()
413
- )
414
-
415
- const linearGradientIds$ = seriesLabels$.pipe(
416
- takeUntil(destroy$),
417
- map(d => d.map((d, i) => {
418
- return getUniID(pluginName, `lineargradient-${d}`)
419
- }))
420
- )
421
-
422
- const graphSubscription = combineLatest({
423
- graphicGSelection: graphicGSelection$,
424
- defsSelection: defsSelection$,
425
- seriesLabels: seriesLabels$,
426
- computedData: computedData$,
427
- linearGradientIds: linearGradientIds$,
428
- SeriesDataMap: SeriesDataMap$,
429
- GroupDataMap: GroupDataMap$,
430
- areaPath: areaPath$,
431
- params: fullParams$,
432
- highlightTarget: highlightTarget$,
433
- gridGroupPositionFn: gridGroupPositionFn$,
434
- }).pipe(
435
- takeUntil(destroy$),
436
- // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
437
- switchMap(async (d) => d),
438
- ).subscribe(data => {
439
-
440
- // const updateGraphic = data.graphicGSelection
441
- // .selectAll<SVGGElement, number>('g')
442
- // .data(data.seriesLabels, (d, i) => d)
443
- // const enterGraphic = updateGraphic.enter()
444
- // .append('g')
445
- // .classed(graphicClassName, true)
446
- // updateGraphic.exit().remove()
447
- // const graphicSelection = updateGraphic.merge(enterGraphic)
448
- // .attr('clip-path', (d, i) => `url(#orbcharts__clipPath_${d})`)
449
-
450
- // 繪圖
451
- data.graphicGSelection.each((d, i, all) => {
452
- // 將資料分段
453
- const segmentData = makeSegmentData(data.computedData[i] ?? [])
454
-
455
- const pathSelection = renderLineAreas({
456
- selection: d3.select(all[i]),
457
- pathClassName,
458
- areaPath: data.areaPath,
459
- segmentData: segmentData,
460
- linearGradientIds: data.linearGradientIds,
461
- params: data.params
462
- })
463
- renderLinearGradient({
464
- defsSelection: data.defsSelection,
465
- computedData: data.computedData,
466
- linearGradientIds: data.linearGradientIds,
467
- params: data.params
468
- })
469
-
470
- pathSelection
471
- .on('mouseover', (event, datum) => {
472
- event.stopPropagation()
473
-
474
- const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
475
- const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
476
- const groupData = data.GroupDataMap.get(groupLabel)!
477
- const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
478
- const _datum = targetDatum ?? datum[0]
479
-
480
- event$.next({
481
- type: 'grid',
482
- eventName: 'mouseover',
483
- pluginName,
484
- highlightTarget: data.highlightTarget,
485
- datum: _datum,
486
- gridIndex: _datum.gridIndex,
487
- series: data.SeriesDataMap.get(_datum.seriesLabel)!,
488
- seriesIndex: _datum.seriesIndex,
489
- seriesLabel: _datum.seriesLabel,
490
- groups: data.GroupDataMap.get(_datum.groupLabel)!,
491
- groupIndex: _datum.groupIndex,
492
- groupLabel: _datum.groupLabel,
493
- event,
494
- data: data.computedData
495
- })
496
- })
497
- .on('mousemove', (event, datum) => {
498
- event.stopPropagation()
499
-
500
- const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
501
- const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
502
- const groupData = data.GroupDataMap.get(groupLabel)!
503
- const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
504
- const _datum = targetDatum ?? datum[0]
505
-
506
- event$.next({
507
- type: 'grid',
508
- eventName: 'mousemove',
509
- pluginName,
510
- highlightTarget: data.highlightTarget,
511
- datum: _datum,
512
- gridIndex: _datum.gridIndex,
513
- series: data.SeriesDataMap.get(_datum.seriesLabel)!,
514
- seriesIndex: _datum.seriesIndex,
515
- seriesLabel: _datum.seriesLabel,
516
- groups: data.GroupDataMap.get(_datum.groupLabel)!,
517
- groupIndex: _datum.groupIndex,
518
- groupLabel: _datum.groupLabel,
519
- event,
520
- data: data.computedData
521
- })
522
- })
523
- .on('mouseout', (event, datum) => {
524
- event.stopPropagation()
525
-
526
- const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
527
- const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
528
- const groupData = data.GroupDataMap.get(groupLabel)!
529
- const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
530
- const _datum = targetDatum ?? datum[0]
531
-
532
- event$.next({
533
- type: 'grid',
534
- eventName: 'mouseout',
535
- pluginName,
536
- highlightTarget: data.highlightTarget,
537
- datum: _datum,
538
- gridIndex: _datum.gridIndex,
539
- series: data.SeriesDataMap.get(_datum.seriesLabel)!,
540
- seriesIndex: _datum.seriesIndex,
541
- seriesLabel: _datum.seriesLabel,
542
- groups: data.GroupDataMap.get(_datum.groupLabel)!,
543
- groupIndex: _datum.groupIndex,
544
- groupLabel: _datum.groupLabel,
545
- event,
546
- data: data.computedData
547
- })
548
- })
549
- .on('click', (event, datum) => {
550
- event.stopPropagation()
551
-
552
- const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
553
- const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
554
- const groupData = data.GroupDataMap.get(groupLabel)!
555
- const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
556
- const _datum = targetDatum ?? datum[0]
557
-
558
- event$.next({
559
- type: 'grid',
560
- eventName: 'click',
561
- pluginName,
562
- highlightTarget: data.highlightTarget,
563
- datum: _datum,
564
- gridIndex: _datum.gridIndex,
565
- series: data.SeriesDataMap.get(_datum.seriesLabel)!,
566
- seriesIndex: _datum.seriesIndex,
567
- seriesLabel: _datum.seriesLabel,
568
- groups: data.GroupDataMap.get(_datum.groupLabel)!,
569
- groupIndex: _datum.groupIndex,
570
- groupLabel: _datum.groupLabel,
571
- event,
572
- data: data.computedData
573
- })
574
- })
575
-
576
- })
577
-
578
-
579
-
580
- // graphicSelection$.next(graphicSelection)
581
-
582
-
583
- // pathSelection = renderLineAreas({
584
- // selection: graphicSelection,
585
- // areaPath: d.areaPath,
586
- // data: d.computedData
587
- // })
588
- })
589
-
590
- // const datumList$ = computedData$.pipe(
591
- // takeUntil(destroy$),
592
- // map(d => d.flat())
593
- // )
594
- // const highlight$ = highlightObservable({ datumList$, fullChartParams$, event$: store.event$ })
595
- // const highlightSubscription = gridHighlight$.subscribe()
596
-
597
- fullChartParams$.pipe(
598
- takeUntil(destroy$),
599
- filter(d => d.highlightTarget === 'series'),
600
- switchMap(d => combineLatest({
601
- graphicGSelection: graphicGSelection$,
602
- highlight: gridHighlight$,
603
- DataMap: DataMap$,
604
- fullChartParams: fullChartParams$
605
- }).pipe(
606
- takeUntil(destroy$),
607
- switchMap(async d => d)
608
- ))
609
- ).subscribe(data => {
610
- const datum = data.DataMap.get(data.highlight[0])
611
- // if (!datum) {
612
- // return
613
- // }
614
- highlightLineAreas({
615
- selection: data.graphicGSelection,
616
- seriesLabel: (datum && datum.seriesLabel) ? datum.seriesLabel : null,
617
- fullChartParams: data.fullChartParams
618
- })
619
- })
620
-
621
- return () => {
622
- destroy$.next(undefined)
623
- // highlightSubscription.unsubscribe()
624
- }
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ filter,
6
+ switchMap,
7
+ takeUntil,
8
+ distinctUntilChanged,
9
+ Observable,
10
+ Subject } from 'rxjs'
11
+ import type { BasePluginFn } from './types'
12
+ import type {
13
+ ComputedDatumGrid,
14
+ ComputedDataGrid,
15
+ DataFormatterGrid,
16
+ EventGrid,
17
+ ContainerPosition,
18
+ ChartParams,
19
+ Layout,
20
+ TransformData } from '@orbcharts/core'
21
+ import { DATA_FORMATTER_VALUE_AXIS } from '@orbcharts/core/src/defaults'
22
+ import { createAxisLinearScale } from '@orbcharts/core'
23
+ import { getD3TransitionEase } from '../utils/d3Utils'
24
+ import { getClassName, getUniID, getMinAndMaxValue } from '../utils/orbchartsUtils'
25
+ import { gridGroupPositionFnObservable } from '../grid/gridObservables'
26
+ import { gridSelectionsObservable } from '../grid/gridObservables'
27
+
28
+ export interface BaseLineAreasParams {
29
+ lineCurve: string
30
+ // lineWidth: number
31
+ linearGradientOpacity: [number, number]
32
+ }
33
+
34
+ interface BaseLineAreasContext {
35
+ selection: d3.Selection<any, unknown, any, unknown>
36
+ computedData$: Observable<ComputedDataGrid>
37
+ existSeriesLabels$: Observable<string[]>
38
+ SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
39
+ GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
40
+ fullDataFormatter$: Observable<DataFormatterGrid>
41
+ fullParams$: Observable<BaseLineAreasParams>
42
+ fullChartParams$: Observable<ChartParams>
43
+ gridAxesTransform$: Observable<TransformData>
44
+ gridGraphicTransform$: Observable<TransformData>
45
+ gridAxesSize$: Observable<{
46
+ width: number;
47
+ height: number;
48
+ }>
49
+ gridHighlight$: Observable<ComputedDatumGrid[]>
50
+ gridContainer$: Observable<ContainerPosition[]>
51
+ layout$: Observable<Layout>
52
+ event$: Subject<EventGrid>
53
+ }
54
+
55
+ type ClipPathDatum = {
56
+ id: string;
57
+ // x: number;
58
+ // y: number;
59
+ width: number;
60
+ height: number;
61
+ }
62
+
63
+ // const pluginName = 'Lines'
64
+ // const pathClassName = getClassName(pluginName, 'path')
65
+
66
+
67
+ function createAreaPath (lineCurve: string = 'curveLinear', valueAxisStart: number): d3.Line<ComputedDatumGrid> {
68
+ return d3.area<ComputedDatumGrid>()
69
+ .x((d) => d.axisX)
70
+ .y0(d => valueAxisStart)
71
+ .y1((d) => d.axisY)
72
+ .curve((d3 as any)[lineCurve])
73
+
74
+ }
75
+
76
+ // 依無值的資料分段
77
+ function makeSegmentData (data: ComputedDatumGrid[]): ComputedDatumGrid[][] {
78
+ let segmentData: ComputedDatumGrid[][] = [[]]
79
+
80
+ let currentIndex = 0
81
+ for (let i in data) {
82
+ if (data[i].visible == false || data[i].value === undefined || data[i].value === null) {
83
+ // 換下一段的 index
84
+ if (segmentData[currentIndex].length) {
85
+ currentIndex ++
86
+ segmentData[currentIndex] = []
87
+ }
88
+ continue
89
+ }
90
+ segmentData[currentIndex].push(data[i])
91
+ }
92
+
93
+ return segmentData
94
+ }
95
+
96
+
97
+ function renderLineAreas ({ selection, pathClassName, segmentData, areaPath, linearGradientIds, params }: {
98
+ selection: d3.Selection<SVGGElement, unknown, any, unknown>
99
+ pathClassName: string
100
+ segmentData: ComputedDatumGrid[][]
101
+ areaPath: d3.Line<ComputedDatumGrid>
102
+ linearGradientIds: string[]
103
+ params: BaseLineAreasParams
104
+ }): d3.Selection<SVGPathElement, ComputedDatumGrid[], any, any> {
105
+ // if (!data[0]) {
106
+ // return undefined
107
+ // }
108
+
109
+ const lineAreas = selection
110
+ .selectAll<SVGPathElement, ComputedDatumGrid[]>('path')
111
+ .data(segmentData, (d, i) => d.length ? `${d[0].id}_${d[d.length - 1].id}` : i) // 以線段起迄id結合為線段id
112
+ .join(
113
+ enter => {
114
+ return enter
115
+ .append<SVGPathElement>('path')
116
+ .classed(pathClassName, true)
117
+ .attr("fill","none")
118
+ // .attr('pointer-events', 'visibleStroke') // 只對線條產生事件
119
+ .style('vector-effect', 'non-scaling-stroke')
120
+ .style('cursor', 'pointer')
121
+ },
122
+ update => update,
123
+ exit => exit.remove()
124
+ )
125
+ // .attr("stroke-width", params.lineWidth)
126
+ // .attr("stroke", (d, i) => d[0] && d[0].color)
127
+ .attr("fill", (d, i) => d[0] ? `url(#${linearGradientIds[d[0].seriesIndex]})` : '')
128
+ .attr("d", (d) => {
129
+ return areaPath(d)
130
+ })
131
+
132
+ return lineAreas
133
+ }
134
+
135
+ function highlightLineAreas ({ selection, seriesLabel, fullChartParams }: {
136
+ selection: d3.Selection<any, string, any, any>
137
+ seriesLabel: string | null
138
+ fullChartParams: ChartParams
139
+ }) {
140
+ selection.interrupt('highlight')
141
+ if (!seriesLabel) {
142
+ // remove highlight
143
+ selection
144
+ .transition('highlight')
145
+ .duration(200)
146
+ .style('opacity', 1)
147
+ return
148
+ }
149
+
150
+ selection
151
+ .each((currentSeriesLabel, i, n) => {
152
+ // const currentSeriesLabel = d[0] ? d[0].seriesLabel : ''
153
+
154
+ if (currentSeriesLabel === seriesLabel) {
155
+ d3.select(n[i])
156
+ .style('opacity', 1)
157
+ } else {
158
+ d3.select(n[i])
159
+ .style('opacity', fullChartParams.styles.unhighlightedOpacity)
160
+ }
161
+ })
162
+ }
163
+
164
+ function renderLinearGradient ({ defsSelection, computedData, linearGradientIds, params }: {
165
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
166
+ computedData: ComputedDataGrid
167
+ linearGradientIds: string[]
168
+ params: BaseLineAreasParams
169
+ }) {
170
+ defsSelection!
171
+ .selectAll<SVGLinearGradientElement, ComputedDatumGrid>('linearGradient')
172
+ .data(computedData ?? [])
173
+ .join(
174
+ enter => {
175
+ return enter
176
+ .append('linearGradient')
177
+ .attr('x1', '0%')
178
+ .attr('x2', '0%')
179
+ .attr('y1', '100%')
180
+ .attr('y2', '0%')
181
+ .attr('spreadMethod', 'pad')
182
+ },
183
+ update => update,
184
+ exit => exit.remove()
185
+ )
186
+ .attr('id', (d, i) => {
187
+ return d[0] ? linearGradientIds[d[0].seriesIndex] : ''
188
+ })
189
+ .html((d, i) => {
190
+ const color = d[0] ? d[0].color : ''
191
+ return `
192
+ <stop offset="0%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[0]}"/>
193
+ <stop offset="100%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[1]}"/>
194
+ `
195
+ })
196
+
197
+ }
198
+
199
+ function renderClipPath ({ defsSelection, clipPathData, transitionDuration, transitionEase }: {
200
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
201
+ clipPathData: ClipPathDatum[]
202
+ transitionDuration: number
203
+ transitionEase: string
204
+ }) {
205
+ const clipPath = defsSelection
206
+ .selectAll<SVGClipPathElement, Layout>('clipPath')
207
+ .data(clipPathData)
208
+ .join(
209
+ enter => {
210
+ return enter
211
+ .append('clipPath')
212
+ },
213
+ update => update,
214
+ exit => exit.remove()
215
+ )
216
+ .attr('id', d => d.id)
217
+ .each((d, i, g) => {
218
+ const rect = d3.select(g[i])
219
+ .selectAll<SVGRectElement, typeof d>('rect')
220
+ .data([d])
221
+ .join(
222
+ enter => {
223
+ const enterSelection = enter
224
+ .append('rect')
225
+ enterSelection
226
+ .transition()
227
+ .duration(transitionDuration)
228
+ .ease(getD3TransitionEase(transitionEase))
229
+ // .delay(100) // @Q@ 不知為何如果沒加 delay位置會有點跑掉
230
+ .tween('tween', (_d, _i, _g) => {
231
+ return (t) => {
232
+ const transitionWidth = _d.width * t
233
+
234
+ enterSelection
235
+ .attr('x', 0)
236
+ .attr('y', 0)
237
+ .attr('width', _d => transitionWidth)
238
+ .attr('height', _d => _d.height)
239
+ }
240
+ })
241
+ return enterSelection
242
+ },
243
+ update => {
244
+ return update
245
+ .attr('x', 0)
246
+ .attr('y', 0)
247
+ .attr('width', _d => _d.width)
248
+ .attr('height', _d => _d.height)
249
+ },
250
+ exit => exit.remove()
251
+ )
252
+ })
253
+
254
+ }
255
+
256
+ export const createBaseLineAreas: BasePluginFn<BaseLineAreasContext> = (pluginName: string, {
257
+ selection,
258
+ computedData$,
259
+ existSeriesLabels$,
260
+ SeriesDataMap$,
261
+ GroupDataMap$,
262
+ fullParams$,
263
+ fullDataFormatter$,
264
+ fullChartParams$,
265
+ gridAxesTransform$,
266
+ gridGraphicTransform$,
267
+ gridAxesSize$,
268
+ gridHighlight$,
269
+ gridContainer$,
270
+ layout$,
271
+ event$
272
+ }) => {
273
+
274
+ const destroy$ = new Subject()
275
+
276
+ const clipPathID = getUniID(pluginName, 'clipPath-box')
277
+ const pathClassName = getClassName(pluginName, 'path')
278
+
279
+ const {
280
+ seriesSelection$,
281
+ axesSelection$,
282
+ defsSelection$,
283
+ graphicGSelection$
284
+ } = gridSelectionsObservable({
285
+ selection,
286
+ pluginName,
287
+ clipPathID,
288
+ existSeriesLabels$,
289
+ gridContainer$,
290
+ gridAxesTransform$,
291
+ gridGraphicTransform$
292
+ })
293
+
294
+ // valueAxis 的起始座標
295
+ const valueAxisStart$: Observable<number> = gridGraphicTransform$.pipe(
296
+ takeUntil(destroy$),
297
+ map(data => {
298
+ // 抵消掉外層的變型
299
+ return - data.translate[1] / data.scale[1]
300
+ })
301
+ )
302
+
303
+ const areaPath$: Observable<d3.Line<ComputedDatumGrid>> = new Observable(subscriber => {
304
+ const paramsSubscription = combineLatest({
305
+ fullParams: fullParams$,
306
+ valueAxisStart: valueAxisStart$
307
+ }).pipe(
308
+ takeUntil(destroy$)
309
+ )
310
+ .subscribe(d => {
311
+ const areaPath = createAreaPath(d.fullParams.lineCurve, d.valueAxisStart)
312
+ subscriber.next(areaPath)
313
+ })
314
+ return () => {
315
+ paramsSubscription.unsubscribe()
316
+ }
317
+ })
318
+
319
+ // 顯示範圍內的series labels
320
+ const seriesLabels$: Observable<string[]> = new Observable(subscriber => {
321
+ computedData$.pipe(
322
+ takeUntil(destroy$),
323
+ // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
324
+ switchMap(async (d) => d),
325
+ ).subscribe(data => {
326
+ const labels = data[0] && data[0][0]
327
+ ? data.map(d => d[0].seriesLabel)
328
+ : []
329
+ subscriber.next(labels)
330
+ })
331
+ })
332
+
333
+ // const axisSize$ = gridAxisSizeObservable({
334
+ // fullDataFormatter$,
335
+ // computedLayout$
336
+ // })
337
+
338
+ const transitionDuration$ = fullChartParams$
339
+ .pipe(
340
+ map(d => d.transitionDuration),
341
+ distinctUntilChanged()
342
+ )
343
+
344
+ const transitionEase$ = fullChartParams$
345
+ .pipe(
346
+ map(d => d.transitionEase),
347
+ distinctUntilChanged()
348
+ )
349
+
350
+ const clipPathSubscription = combineLatest({
351
+ defsSelection: defsSelection$,
352
+ seriesLabels: seriesLabels$,
353
+ axisSize: gridAxesSize$,
354
+ transitionDuration: transitionDuration$,
355
+ transitionEase: transitionEase$
356
+ }).pipe(
357
+ takeUntil(destroy$),
358
+ // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
359
+ switchMap(async (d) => d),
360
+ ).subscribe(data => {
361
+ // 外層的遮罩
362
+ const clipPathBox = [{
363
+ id: clipPathID,
364
+ width: data.axisSize.width,
365
+ height: data.axisSize.height
366
+ }]
367
+ // 各別線條的遮罩(各別動畫)
368
+ const clipPathData = clipPathBox.concat(
369
+ data.seriesLabels.map(d => {
370
+ return {
371
+ id: `orbcharts__clipPath_${d}`,
372
+ width: data.axisSize.width,
373
+ height: data.axisSize.height
374
+ }
375
+ })
376
+ )
377
+ renderClipPath({
378
+ defsSelection: data.defsSelection,
379
+ clipPathData,
380
+ transitionDuration: data.transitionDuration,
381
+ transitionEase: data.transitionEase
382
+ })
383
+ })
384
+
385
+ // const SeriesDataMap$ = computedData$.pipe(
386
+ // map(d => makeGridSeriesDataMap(d))
387
+ // )
388
+
389
+ // const GroupDataMap$ = computedData$.pipe(
390
+ // map(d => makeGridGroupDataMap(d))
391
+ // )
392
+
393
+ const DataMap$ = computedData$.pipe(
394
+ map(d => {
395
+ const DataMap: Map<string, ComputedDatumGrid> = new Map()
396
+ d.flat().forEach(_d => DataMap.set(_d.id, _d))
397
+ return DataMap
398
+ })
399
+ )
400
+
401
+ // 取得事件座標的group資料
402
+ const gridGroupPositionFn$ = gridGroupPositionFnObservable({
403
+ fullDataFormatter$,
404
+ gridAxesSize$: gridAxesSize$,
405
+ computedData$: computedData$,
406
+ fullChartParams$: fullChartParams$
407
+ })
408
+
409
+ const highlightTarget$ = fullChartParams$.pipe(
410
+ takeUntil(destroy$),
411
+ map(d => d.highlightTarget),
412
+ distinctUntilChanged()
413
+ )
414
+
415
+ const linearGradientIds$ = seriesLabels$.pipe(
416
+ takeUntil(destroy$),
417
+ map(d => d.map((d, i) => {
418
+ return getUniID(pluginName, `lineargradient-${d}`)
419
+ }))
420
+ )
421
+
422
+ const graphSubscription = combineLatest({
423
+ graphicGSelection: graphicGSelection$,
424
+ defsSelection: defsSelection$,
425
+ seriesLabels: seriesLabels$,
426
+ computedData: computedData$,
427
+ linearGradientIds: linearGradientIds$,
428
+ SeriesDataMap: SeriesDataMap$,
429
+ GroupDataMap: GroupDataMap$,
430
+ areaPath: areaPath$,
431
+ params: fullParams$,
432
+ highlightTarget: highlightTarget$,
433
+ gridGroupPositionFn: gridGroupPositionFn$,
434
+ }).pipe(
435
+ takeUntil(destroy$),
436
+ // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
437
+ switchMap(async (d) => d),
438
+ ).subscribe(data => {
439
+
440
+ // const updateGraphic = data.graphicGSelection
441
+ // .selectAll<SVGGElement, number>('g')
442
+ // .data(data.seriesLabels, (d, i) => d)
443
+ // const enterGraphic = updateGraphic.enter()
444
+ // .append('g')
445
+ // .classed(graphicClassName, true)
446
+ // updateGraphic.exit().remove()
447
+ // const graphicSelection = updateGraphic.merge(enterGraphic)
448
+ // .attr('clip-path', (d, i) => `url(#orbcharts__clipPath_${d})`)
449
+
450
+ // 繪圖
451
+ data.graphicGSelection.each((d, i, all) => {
452
+ // 將資料分段
453
+ const segmentData = makeSegmentData(data.computedData[i] ?? [])
454
+
455
+ const pathSelection = renderLineAreas({
456
+ selection: d3.select(all[i]),
457
+ pathClassName,
458
+ areaPath: data.areaPath,
459
+ segmentData: segmentData,
460
+ linearGradientIds: data.linearGradientIds,
461
+ params: data.params
462
+ })
463
+ renderLinearGradient({
464
+ defsSelection: data.defsSelection,
465
+ computedData: data.computedData,
466
+ linearGradientIds: data.linearGradientIds,
467
+ params: data.params
468
+ })
469
+
470
+ pathSelection
471
+ .on('mouseover', (event, datum) => {
472
+ event.stopPropagation()
473
+
474
+ const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
475
+ const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
476
+ const groupData = data.GroupDataMap.get(groupLabel)!
477
+ const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
478
+ const _datum = targetDatum ?? datum[0]
479
+
480
+ event$.next({
481
+ type: 'grid',
482
+ eventName: 'mouseover',
483
+ pluginName,
484
+ highlightTarget: data.highlightTarget,
485
+ datum: _datum,
486
+ gridIndex: _datum.gridIndex,
487
+ series: data.SeriesDataMap.get(_datum.seriesLabel)!,
488
+ seriesIndex: _datum.seriesIndex,
489
+ seriesLabel: _datum.seriesLabel,
490
+ groups: data.GroupDataMap.get(_datum.groupLabel)!,
491
+ groupIndex: _datum.groupIndex,
492
+ groupLabel: _datum.groupLabel,
493
+ event,
494
+ data: data.computedData
495
+ })
496
+ })
497
+ .on('mousemove', (event, datum) => {
498
+ event.stopPropagation()
499
+
500
+ const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
501
+ const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
502
+ const groupData = data.GroupDataMap.get(groupLabel)!
503
+ const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
504
+ const _datum = targetDatum ?? datum[0]
505
+
506
+ event$.next({
507
+ type: 'grid',
508
+ eventName: 'mousemove',
509
+ pluginName,
510
+ highlightTarget: data.highlightTarget,
511
+ datum: _datum,
512
+ gridIndex: _datum.gridIndex,
513
+ series: data.SeriesDataMap.get(_datum.seriesLabel)!,
514
+ seriesIndex: _datum.seriesIndex,
515
+ seriesLabel: _datum.seriesLabel,
516
+ groups: data.GroupDataMap.get(_datum.groupLabel)!,
517
+ groupIndex: _datum.groupIndex,
518
+ groupLabel: _datum.groupLabel,
519
+ event,
520
+ data: data.computedData
521
+ })
522
+ })
523
+ .on('mouseout', (event, datum) => {
524
+ event.stopPropagation()
525
+
526
+ const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
527
+ const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
528
+ const groupData = data.GroupDataMap.get(groupLabel)!
529
+ const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
530
+ const _datum = targetDatum ?? datum[0]
531
+
532
+ event$.next({
533
+ type: 'grid',
534
+ eventName: 'mouseout',
535
+ pluginName,
536
+ highlightTarget: data.highlightTarget,
537
+ datum: _datum,
538
+ gridIndex: _datum.gridIndex,
539
+ series: data.SeriesDataMap.get(_datum.seriesLabel)!,
540
+ seriesIndex: _datum.seriesIndex,
541
+ seriesLabel: _datum.seriesLabel,
542
+ groups: data.GroupDataMap.get(_datum.groupLabel)!,
543
+ groupIndex: _datum.groupIndex,
544
+ groupLabel: _datum.groupLabel,
545
+ event,
546
+ data: data.computedData
547
+ })
548
+ })
549
+ .on('click', (event, datum) => {
550
+ event.stopPropagation()
551
+
552
+ const seriesLabel = datum[0] ? datum[0].seriesLabel : ''
553
+ const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
554
+ const groupData = data.GroupDataMap.get(groupLabel)!
555
+ const targetDatum = groupData.find(d => d.seriesLabel === seriesLabel)
556
+ const _datum = targetDatum ?? datum[0]
557
+
558
+ event$.next({
559
+ type: 'grid',
560
+ eventName: 'click',
561
+ pluginName,
562
+ highlightTarget: data.highlightTarget,
563
+ datum: _datum,
564
+ gridIndex: _datum.gridIndex,
565
+ series: data.SeriesDataMap.get(_datum.seriesLabel)!,
566
+ seriesIndex: _datum.seriesIndex,
567
+ seriesLabel: _datum.seriesLabel,
568
+ groups: data.GroupDataMap.get(_datum.groupLabel)!,
569
+ groupIndex: _datum.groupIndex,
570
+ groupLabel: _datum.groupLabel,
571
+ event,
572
+ data: data.computedData
573
+ })
574
+ })
575
+
576
+ })
577
+
578
+
579
+
580
+ // graphicSelection$.next(graphicSelection)
581
+
582
+
583
+ // pathSelection = renderLineAreas({
584
+ // selection: graphicSelection,
585
+ // areaPath: d.areaPath,
586
+ // data: d.computedData
587
+ // })
588
+ })
589
+
590
+ // const datumList$ = computedData$.pipe(
591
+ // takeUntil(destroy$),
592
+ // map(d => d.flat())
593
+ // )
594
+ // const highlight$ = highlightObservable({ datumList$, fullChartParams$, event$: store.event$ })
595
+ // const highlightSubscription = gridHighlight$.subscribe()
596
+
597
+ fullChartParams$.pipe(
598
+ takeUntil(destroy$),
599
+ filter(d => d.highlightTarget === 'series'),
600
+ switchMap(d => combineLatest({
601
+ graphicGSelection: graphicGSelection$,
602
+ gridHighlight: gridHighlight$,
603
+ DataMap: DataMap$,
604
+ fullChartParams: fullChartParams$
605
+ }).pipe(
606
+ takeUntil(destroy$),
607
+ switchMap(async d => d)
608
+ ))
609
+ ).subscribe(data => {
610
+ const seriesLabel = data.gridHighlight[0] ? data.gridHighlight[0].seriesLabel : null
611
+ highlightLineAreas({
612
+ selection: data.graphicGSelection,
613
+ seriesLabel,
614
+ fullChartParams: data.fullChartParams
615
+ })
616
+ })
617
+
618
+ return () => {
619
+ destroy$.next(undefined)
620
+ // highlightSubscription.unsubscribe()
621
+ }
625
622
  }