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

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 (75) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +5611 -5571
  3. package/dist/orbcharts-plugins-basic.umd.js +7 -7
  4. package/dist/src/base/BaseLegend.d.ts +1 -0
  5. package/package.json +42 -42
  6. package/src/base/BaseBarStack.ts +881 -881
  7. package/src/base/BaseBars.ts +750 -750
  8. package/src/base/BaseBarsTriangle.ts +659 -659
  9. package/src/base/BaseDots.ts +639 -639
  10. package/src/base/BaseGroupAxis.ts +496 -496
  11. package/src/base/BaseLegend.ts +641 -636
  12. package/src/base/BaseLineAreas.ts +621 -621
  13. package/src/base/BaseLines.ts +692 -692
  14. package/src/base/BaseValueAxis.ts +479 -479
  15. package/src/base/types.ts +2 -2
  16. package/src/grid/defaults.ts +121 -121
  17. package/src/grid/gridObservables.ts +263 -263
  18. package/src/grid/index.ts +15 -15
  19. package/src/grid/plugins/BarStack.ts +37 -37
  20. package/src/grid/plugins/Bars.ts +37 -37
  21. package/src/grid/plugins/BarsDiverging.ts +39 -39
  22. package/src/grid/plugins/BarsTriangle.ts +34 -34
  23. package/src/grid/plugins/Dots.ts +35 -35
  24. package/src/grid/plugins/GridLegend.ts +59 -58
  25. package/src/grid/plugins/GroupAux.ts +646 -643
  26. package/src/grid/plugins/GroupAxis.ts +30 -30
  27. package/src/grid/plugins/LineAreas.ts +36 -36
  28. package/src/grid/plugins/Lines.ts +35 -35
  29. package/src/grid/plugins/ScalingArea.ts +174 -174
  30. package/src/grid/plugins/ValueAxis.ts +31 -31
  31. package/src/grid/plugins/ValueStackAxis.ts +70 -70
  32. package/src/grid/types.ts +120 -120
  33. package/src/index.ts +9 -9
  34. package/src/multiGrid/defaults.ts +147 -147
  35. package/src/multiGrid/index.ts +11 -11
  36. package/src/multiGrid/multiGridObservables.ts +289 -289
  37. package/src/multiGrid/plugins/MultiBarStack.ts +60 -60
  38. package/src/multiGrid/plugins/MultiBars.ts +59 -59
  39. package/src/multiGrid/plugins/MultiBarsTriangle.ts +58 -58
  40. package/src/multiGrid/plugins/MultiDots.ts +58 -58
  41. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -88
  42. package/src/multiGrid/plugins/MultiGroupAxis.ts +53 -53
  43. package/src/multiGrid/plugins/MultiLineAreas.ts +59 -59
  44. package/src/multiGrid/plugins/MultiLines.ts +58 -58
  45. package/src/multiGrid/plugins/MultiValueAxis.ts +53 -53
  46. package/src/multiGrid/plugins/OverlappingValueAxes.ts +164 -164
  47. package/src/multiGrid/types.ts +67 -67
  48. package/src/noneData/defaults.ts +61 -61
  49. package/src/noneData/index.ts +3 -3
  50. package/src/noneData/plugins/Container.ts +10 -10
  51. package/src/noneData/plugins/Tooltip.ts +310 -304
  52. package/src/noneData/types.ts +26 -26
  53. package/src/series/defaults.ts +99 -99
  54. package/src/series/index.ts +6 -6
  55. package/src/series/plugins/Bubbles.ts +551 -551
  56. package/src/series/plugins/Pie.ts +600 -600
  57. package/src/series/plugins/PieEventTexts.ts +194 -194
  58. package/src/series/plugins/PieLabels.ts +288 -288
  59. package/src/series/plugins/SeriesLegend.ts +59 -58
  60. package/src/series/seriesUtils.ts +50 -50
  61. package/src/series/types.ts +67 -67
  62. package/src/tree/defaults.ts +22 -22
  63. package/src/tree/index.ts +3 -3
  64. package/src/tree/plugins/TreeLegend.ts +59 -58
  65. package/src/tree/plugins/TreeMap.ts +305 -302
  66. package/src/tree/types.ts +23 -23
  67. package/src/utils/commonUtils.ts +21 -21
  68. package/src/utils/d3Graphics.ts +124 -124
  69. package/src/utils/d3Utils.ts +73 -73
  70. package/src/utils/observables.ts +14 -14
  71. package/src/utils/orbchartsUtils.ts +100 -100
  72. package/tsconfig.dev.json +16 -16
  73. package/tsconfig.json +13 -13
  74. package/tsconfig.prod.json +13 -13
  75. package/vite.config.js +49 -49
@@ -1,640 +1,640 @@
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
- EventGrid,
15
- ChartParams,
16
- ContainerPosition,
17
- Layout,
18
- TransformData,
19
- ColorType } from '@orbcharts/core'
20
- import { getDatumColor, getClassName, getUniID } from '../utils/orbchartsUtils'
21
- import { gridSelectionsObservable } from '../grid/gridObservables'
22
-
23
- export interface BaseDotsParams {
24
- radius: number
25
- fillColorType: ColorType
26
- strokeColorType: ColorType
27
- strokeWidth: number
28
- onlyShowHighlighted: boolean
29
- }
30
-
31
- interface BaseDotsContext {
32
- selection: d3.Selection<any, unknown, any, unknown>
33
- computedData$: Observable<ComputedDataGrid>
34
- visibleComputedData$: Observable<ComputedDatumGrid[][]>
35
- existSeriesLabels$: Observable<string[]>
36
- SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
37
- GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
38
- fullParams$: Observable<BaseDotsParams>
39
- fullChartParams$: Observable<ChartParams>
40
- gridAxesTransform$: Observable<TransformData>
41
- gridGraphicTransform$: Observable<TransformData>
42
- gridGraphicReverseScale$: Observable<[number, number][]>
43
- gridAxesSize$: Observable<{
44
- width: number;
45
- height: number;
46
- }>
47
- gridHighlight$: Observable<ComputedDatumGrid[]>
48
- gridContainer$: Observable<ContainerPosition[]>
49
- event$: Subject<EventGrid>
50
- }
51
-
52
-
53
- type ClipPathDatum = {
54
- id: string;
55
- // x: number;
56
- // y: number;
57
- width: number;
58
- height: number;
59
- }
60
-
61
- // const pluginName = 'Dots'
62
- // const circleGClassName = getClassName(pluginName, 'circleG')
63
- // const circleClassName = getClassName(pluginName, 'circle')
64
-
65
- function renderDots ({ graphicGSelection, circleGClassName, circleClassName, data, fullParams, fullChartParams, graphicReverseScale }: {
66
- graphicGSelection: d3.Selection<SVGGElement, any, any, any>
67
- circleGClassName: string
68
- circleClassName: string
69
- data: ComputedDatumGrid[][]
70
- fullParams: BaseDotsParams
71
- fullChartParams: ChartParams
72
- graphicReverseScale: [number, number][]
73
- }) {
74
- const createEnterDuration = (enter: d3.Selection<d3.EnterElement, ComputedDatumGrid, SVGGElement, any>) => {
75
- const enterSize = enter.size()
76
- const eachDuration = fullChartParams.transitionDuration / enterSize
77
- return eachDuration
78
- }
79
- // enterDuration
80
- let enterDuration = 0
81
-
82
- graphicGSelection
83
- .each((seriesData, seriesIndex, g) => {
84
- d3.select(g[seriesIndex])
85
- .selectAll<SVGGElement, ComputedDatumGrid>('g')
86
- .data(data[seriesIndex], d => d.id)
87
- .join(
88
- enter => {
89
- // enterDuration
90
- enterDuration = createEnterDuration(enter)
91
-
92
- return enter
93
- .append('g')
94
- .classed(circleGClassName, true)
95
- },
96
- update => update,
97
- exit => exit.remove()
98
- )
99
- .attr('transform', d => `translate(${d.axisX}, ${d.axisY})`)
100
- .each((d, i, g) => {
101
- const circle = d3.select(g[i])
102
- .selectAll('circle')
103
- .data([d])
104
- .join(
105
- enter => {
106
- return enter
107
- .append('circle')
108
- .style('cursor', 'pointer')
109
- .style('vector-effect', 'non-scaling-stroke')
110
- .classed(circleClassName, true)
111
- .attr('opacity', 0)
112
- .transition()
113
- .delay((_d, _i) => {
114
- return i * enterDuration
115
- })
116
- .attr('opacity', 1)
117
- },
118
- update => {
119
- return update
120
- .transition()
121
- .duration(50)
122
- // .attr('cx', d => d.axisX)
123
- // .attr('cy', d => d.axisY)
124
- .attr('opacity', 1)
125
- },
126
- exit => exit.remove()
127
- )
128
- .attr('r', fullParams.radius)
129
- .attr('fill', (d, i) => getDatumColor({ datum: d, colorType: fullParams.fillColorType, fullChartParams }))
130
- .attr('stroke', (d, i) => getDatumColor({ datum: d, colorType: fullParams.strokeColorType, fullChartParams }))
131
- .attr('stroke-width', fullParams.strokeWidth)
132
- .attr('transform', `scale(${graphicReverseScale[seriesIndex][0] ?? 1}, ${graphicReverseScale[seriesIndex][1] ?? 1})`)
133
- })
134
- })
135
-
136
- // const dots = graphicGSelection
137
- // .selectAll<SVGGElement, ComputedDatumGrid>('g')
138
- // .data(data, d => d.id)
139
- // .join(
140
- // enter => {
141
- // // enterDuration
142
- // enterDuration = createEnterDuration(enter)
143
-
144
- // return enter
145
- // .append('g')
146
- // .classed(circleGClassName, true)
147
- // },
148
- // update => update,
149
- // exit => exit.remove()
150
- // )
151
- // .attr('transform', d => `translate(${d.axisX}, ${d.axisY})`)
152
- // .each((d, i, g) => {
153
- // const circle = d3.select(g[i])
154
- // .selectAll('circle')
155
- // .data([d])
156
- // .join(
157
- // enter => {
158
- // return enter
159
- // .append('circle')
160
- // .style('cursor', 'pointer')
161
- // .style('vector-effect', 'non-scaling-stroke')
162
- // .classed(circleClassName, true)
163
- // .attr('opacity', 0)
164
- // .transition()
165
- // .delay((_d, _i) => {
166
- // return i * enterDuration
167
- // })
168
- // .attr('opacity', 1)
169
- // },
170
- // update => {
171
- // return update
172
- // .transition()
173
- // .duration(50)
174
- // // .attr('cx', d => d.axisX)
175
- // // .attr('cy', d => d.axisY)
176
- // .attr('opacity', 1)
177
- // },
178
- // exit => exit.remove()
179
- // )
180
- // .attr('r', fullParams.radius)
181
- // .attr('fill', (d, i) => getDatumColor({ datum: d, colorType: fullParams.fillColorType, fullChartParams }))
182
- // .attr('stroke', (d, i) => getDatumColor({ datum: d, colorType: fullParams.strokeColorType, fullChartParams }))
183
- // .attr('stroke-width', fullParams.strokeWidth)
184
- // .attr('transform', `scale(${graphicReverseScale[0]}, ${graphicReverseScale[1]})`)
185
- // })
186
-
187
- const graphicCircleSelection: d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown> = graphicGSelection.selectAll(`circle.${circleClassName}`)
188
-
189
- return graphicCircleSelection
190
- }
191
-
192
-
193
- function highlightDots ({ selection, ids, onlyShowHighlighted, fullChartParams }: {
194
- selection: d3.Selection<SVGGElement, ComputedDatumGrid, any, any>
195
- ids: string[]
196
- onlyShowHighlighted: boolean
197
- fullChartParams: ChartParams
198
- }) {
199
- selection.interrupt('highlight')
200
- if (!ids.length) {
201
- // remove highlight
202
- selection
203
- .transition('highlight')
204
- .duration(200)
205
- .style('opacity', onlyShowHighlighted === true ? 0 : 1)
206
- return
207
- }
208
-
209
- selection
210
- .each((d, i, n) => {
211
- if (ids.includes(d.id)) {
212
- d3.select(n[i])
213
- .style('opacity', 1)
214
- .transition('highlight')
215
- .duration(200)
216
- } else {
217
- d3.select(n[i])
218
- .style('opacity', onlyShowHighlighted === true ? 0 : fullChartParams.styles.unhighlightedOpacity)
219
- .transition('highlight')
220
- .duration(200)
221
- }
222
- })
223
- }
224
-
225
- function renderClipPath ({ defsSelection, clipPathData }: {
226
- defsSelection: d3.Selection<SVGDefsElement, any, any, any>
227
- clipPathData: ClipPathDatum[]
228
- }) {
229
- const clipPath = defsSelection
230
- .selectAll<SVGClipPathElement, Layout>('clipPath')
231
- .data(clipPathData)
232
- .join(
233
- enter => {
234
- return enter
235
- .append('clipPath')
236
- },
237
- update => update,
238
- exit => exit.remove()
239
- )
240
- .attr('id', d => d.id)
241
- .each((d, i, g) => {
242
- const rect = d3.select(g[i])
243
- .selectAll<SVGRectElement, typeof d>('rect')
244
- .data([d])
245
- .join('rect')
246
- .attr('x', 0)
247
- .attr('y', 0)
248
- .attr('width', _d => _d.width)
249
- .attr('height', _d => _d.height)
250
- })
251
-
252
- }
253
-
254
-
255
-
256
- export const createBaseDots: BasePluginFn<BaseDotsContext> = (pluginName: string, {
257
- selection,
258
- computedData$,
259
- visibleComputedData$,
260
- existSeriesLabels$,
261
- SeriesDataMap$,
262
- GroupDataMap$,
263
- fullParams$,
264
- fullChartParams$,
265
- gridAxesTransform$,
266
- gridGraphicTransform$,
267
- gridGraphicReverseScale$,
268
- gridAxesSize$,
269
- gridHighlight$,
270
- gridContainer$,
271
- event$
272
- }) => {
273
-
274
- const destroy$ = new Subject()
275
-
276
- const clipPathID = getUniID(pluginName, 'clipPath-box')
277
- const circleGClassName = getClassName(pluginName, 'circleG')
278
- const circleClassName = getClassName(pluginName, 'circle')
279
-
280
- // const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
281
- // .append('g')
282
- // .attr('clip-path', `url(#${clipPathID})`)
283
- // const defsSelection: d3.Selection<SVGDefsElement, any, any, any> = axisSelection.append('defs')
284
- // const dataAreaSelection: d3.Selection<SVGGElement, any, any, any> = axisSelection.append('g')
285
- const graphicSelection$: Subject<d3.Selection<SVGGElement, ComputedDatumGrid, any, any>> = new Subject()
286
-
287
- // gridAxesTransform$
288
- // .pipe(
289
- // takeUntil(destroy$),
290
- // map(d => d.value),
291
- // distinctUntilChanged()
292
- // ).subscribe(d => {
293
- // axisSelection
294
- // .style('transform', d)
295
- // })
296
-
297
- // gridGraphicTransform$
298
- // .pipe(
299
- // takeUntil(destroy$),
300
- // switchMap(async d => d.value),
301
- // distinctUntilChanged()
302
- // ).subscribe(d => {
303
- // dataAreaSelection
304
- // .transition()
305
- // .duration(50)
306
- // .style('transform', d)
307
- // })
308
-
309
- // const seriesSelection$ = computedData$.pipe(
310
- // takeUntil(destroy$),
311
- // distinctUntilChanged((a, b) => {
312
- // // 只有當series的數量改變時,才重新計算
313
- // return a.length === b.length
314
- // }),
315
- // map((computedData, i) => {
316
- // return selection
317
- // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${seriesClassName}`)
318
- // .data(computedData, d => d[0] ? d[0].seriesIndex : i)
319
- // .join(
320
- // enter => {
321
- // return enter
322
- // .append('g')
323
- // .classed(seriesClassName, true)
324
- // .each((d, i, g) => {
325
- // const axesSelection = d3.select(g[i])
326
- // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${axesClassName}`)
327
- // .data([i])
328
- // .join(
329
- // enter => {
330
- // return enter
331
- // .append('g')
332
- // .classed(axesClassName, true)
333
- // .attr('clip-path', `url(#${clipPathID})`)
334
- // .each((d, i, g) => {
335
- // const defsSelection = d3.select(g[i])
336
- // .selectAll<SVGDefsElement, any>('defs')
337
- // .data([i])
338
- // .join('defs')
339
-
340
- // const graphicGSelection = d3.select(g[i])
341
- // .selectAll<SVGGElement, any>('g')
342
- // .data([i])
343
- // .join('g')
344
- // .classed(graphicClassName, true)
345
- // })
346
- // },
347
- // update => update,
348
- // exit => exit.remove()
349
- // )
350
- // })
351
- // },
352
- // update => update,
353
- // exit => exit.remove()
354
- // )
355
- // })
356
- // )
357
-
358
- // combineLatest({
359
- // seriesSelection: seriesSelection$,
360
- // gridContainer: gridContainer$
361
- // }).pipe(
362
- // takeUntil(destroy$),
363
- // switchMap(async d => d)
364
- // ).subscribe(data => {
365
- // data.seriesSelection
366
- // .transition()
367
- // .attr('transform', (d, i) => {
368
- // const translate = data.gridContainer[i].translate
369
- // const scale = data.gridContainer[i].scale
370
- // return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
371
- // })
372
- // })
373
-
374
-
375
- // const axesSelection$ = combineLatest({
376
- // seriesSelection: seriesSelection$,
377
- // gridAxesTransform: gridAxesTransform$
378
- // }).pipe(
379
- // takeUntil(destroy$),
380
- // switchMap(async d => d),
381
- // map(data => {
382
- // return data.seriesSelection
383
- // .select<SVGGElement>(`g.${axesClassName}`)
384
- // .style('transform', data.gridAxesTransform.value)
385
- // })
386
- // )
387
- // const defsSelection$ = axesSelection$.pipe(
388
- // takeUntil(destroy$),
389
- // map(axesSelection => {
390
- // return axesSelection.select<SVGDefsElement>('defs')
391
- // })
392
- // )
393
- // const graphicGSelection$ = combineLatest({
394
- // axesSelection: axesSelection$,
395
- // gridGraphicTransform: gridGraphicTransform$
396
- // }).pipe(
397
- // takeUntil(destroy$),
398
- // switchMap(async d => d),
399
- // map(data => {
400
- // const graphicGSelection = data.axesSelection
401
- // .select<SVGGElement>(`g.${graphicClassName}`)
402
- // graphicGSelection
403
- // .transition()
404
- // .duration(50)
405
- // .style('transform', data.gridGraphicTransform.value)
406
- // return graphicGSelection
407
- // })
408
- // )
409
-
410
- const {
411
- seriesSelection$,
412
- axesSelection$,
413
- defsSelection$,
414
- graphicGSelection$
415
- } = gridSelectionsObservable({
416
- selection,
417
- pluginName,
418
- clipPathID,
419
- existSeriesLabels$,
420
- gridContainer$,
421
- gridAxesTransform$,
422
- gridGraphicTransform$
423
- })
424
-
425
- const graphicReverseScale$: Observable<[number, number][]> = combineLatest({
426
- // gridGraphicTransform: gridGraphicTransform$,
427
- // gridContainer: gridContainer$,
428
- // gridAxesTransform: gridAxesTransform$
429
- computedData: computedData$,
430
- gridGraphicReverseScale: gridGraphicReverseScale$
431
- }).pipe(
432
- takeUntil(destroy$),
433
- switchMap(async data => data),
434
- map(data => {
435
- return data.computedData.map((series, seriesIndex) => {
436
- return data.gridGraphicReverseScale[seriesIndex]
437
- })
438
- })
439
- )
440
-
441
- const clipPathSubscription = combineLatest({
442
- defsSelection: defsSelection$,
443
- gridAxesSize: gridAxesSize$,
444
- }).pipe(
445
- takeUntil(destroy$),
446
- switchMap(async (d) => d),
447
- ).subscribe(data => {
448
- // 外層的遮罩
449
- const clipPathData = [{
450
- id: clipPathID,
451
- width: data.gridAxesSize.width,
452
- height: data.gridAxesSize.height
453
- }]
454
- renderClipPath({
455
- defsSelection: data.defsSelection,
456
- clipPathData,
457
- })
458
- })
459
-
460
- // const visibleComputedData$ = computedData$.pipe(
461
- // map(computedData => {
462
- // return computedData
463
- // .map(d => {
464
- // return d.filter(_d => _d.visible == true)
465
- // })
466
- // })
467
- // )
468
-
469
- // const SeriesDataMap$ = visibleComputedData$.pipe(
470
- // map(d => makeGridSeriesDataMap(d))
471
- // )
472
-
473
- // const GroupDataMap$ = visibleComputedData$.pipe(
474
- // map(d => makeGridGroupDataMap(d))
475
- // )
476
-
477
- // const DataMap$ = computedData$.pipe(
478
- // map(d => {
479
- // const DataMap: Map<string, ComputedDatumGrid> = new Map()
480
- // d.flat().forEach(_d => DataMap.set(_d.id, _d))
481
- // return DataMap
482
- // })
483
- // )
484
-
485
- const highlightTarget$ = fullChartParams$.pipe(
486
- takeUntil(destroy$),
487
- map(d => d.highlightTarget),
488
- distinctUntilChanged()
489
- )
490
-
491
- combineLatest({
492
- graphicGSelection: graphicGSelection$,
493
- computedData: computedData$,
494
- visibleComputedData: visibleComputedData$,
495
- SeriesDataMap: SeriesDataMap$,
496
- GroupDataMap: GroupDataMap$,
497
- graphicReverseScale: graphicReverseScale$,
498
- fullChartParams: fullChartParams$,
499
- fullParams: fullParams$,
500
- highlightTarget: highlightTarget$
501
- }).pipe(
502
- takeUntil(destroy$),
503
- switchMap(async (d) => d),
504
- ).subscribe(data => {
505
-
506
- const graphicSelection = renderDots({
507
- graphicGSelection: data.graphicGSelection,
508
- circleGClassName,
509
- circleClassName,
510
- data: data.visibleComputedData,
511
- fullParams: data.fullParams,
512
- fullChartParams: data.fullChartParams,
513
- graphicReverseScale: data.graphicReverseScale
514
- })
515
-
516
- graphicSelection
517
- .on('mouseover', (event, datum) => {
518
- event.stopPropagation()
519
-
520
- event$.next({
521
- type: 'grid',
522
- eventName: 'mouseover',
523
- pluginName,
524
- highlightTarget: data.highlightTarget,
525
- datum,
526
- gridIndex: datum.gridIndex,
527
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
528
- seriesIndex: datum.seriesIndex,
529
- seriesLabel: datum.seriesLabel,
530
- groups: data.GroupDataMap.get(datum.groupLabel)!,
531
- groupIndex: datum.groupIndex,
532
- groupLabel: datum.groupLabel,
533
- event,
534
- data: data.computedData
535
- })
536
- })
537
- .on('mousemove', (event, datum) => {
538
- event.stopPropagation()
539
-
540
- event$.next({
541
- type: 'grid',
542
- eventName: 'mousemove',
543
- pluginName,
544
- highlightTarget: data.highlightTarget,
545
- data: data.computedData,
546
- datum,
547
- gridIndex: datum.gridIndex,
548
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
549
- seriesIndex: datum.seriesIndex,
550
- seriesLabel: datum.seriesLabel,
551
- groups: data.GroupDataMap.get(datum.groupLabel)!,
552
- groupIndex: datum.groupIndex,
553
- groupLabel: datum.groupLabel,
554
- event
555
- })
556
- })
557
- .on('mouseout', (event, datum) => {
558
- event.stopPropagation()
559
-
560
- event$.next({
561
- type: 'grid',
562
- eventName: 'mouseout',
563
- pluginName,
564
- highlightTarget: data.highlightTarget,
565
- datum,
566
- gridIndex: datum.gridIndex,
567
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
568
- seriesIndex: datum.seriesIndex,
569
- seriesLabel: datum.seriesLabel,
570
- groups: data.GroupDataMap.get(datum.groupLabel)!,
571
- groupIndex: datum.groupIndex,
572
- groupLabel: datum.groupLabel,
573
- event,
574
- data: data.computedData
575
- })
576
- })
577
- .on('click', (event, datum) => {
578
- event.stopPropagation()
579
-
580
- event$.next({
581
- type: 'grid',
582
- eventName: 'click',
583
- pluginName,
584
- highlightTarget: data.highlightTarget,
585
- datum,
586
- gridIndex: datum.gridIndex,
587
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
588
- seriesIndex: datum.seriesIndex,
589
- seriesLabel: datum.seriesLabel,
590
- groups: data.GroupDataMap.get(datum.groupLabel)!,
591
- groupIndex: datum.groupIndex,
592
- groupLabel: datum.groupLabel,
593
- event,
594
- data: data.computedData
595
- })
596
- })
597
-
598
- graphicSelection$.next(graphicSelection)
599
-
600
- })
601
-
602
- // const datumList$ = computedData$.pipe(
603
- // takeUntil(destroy$),
604
- // map(d => d.flat())
605
- // )
606
- // const highlight$ = highlightObservable({ datumList$, fullChartParams$, event$: store.event$ })
607
- // const highlightSubscription = gridHighlight$.subscribe()
608
- const onlyShowHighlighted$ = fullParams$.pipe(
609
- takeUntil(destroy$),
610
- map(d => d.onlyShowHighlighted),
611
- distinctUntilChanged()
612
- )
613
-
614
- fullChartParams$.pipe(
615
- takeUntil(destroy$),
616
- switchMap(d => combineLatest({
617
- graphicSelection: graphicSelection$,
618
- highlight: gridHighlight$.pipe(
619
- map(data => data.map(d => d.id))
620
- ),
621
- onlyShowHighlighted: onlyShowHighlighted$,
622
- fullChartParams: fullChartParams$
623
- }).pipe(
624
- takeUntil(destroy$),
625
- switchMap(async d => d)
626
- ))
627
- ).subscribe(data => {
628
- highlightDots({
629
- selection: data.graphicSelection,
630
- ids: data.highlight,
631
- onlyShowHighlighted: data.onlyShowHighlighted,
632
- fullChartParams: data.fullChartParams
633
- })
634
- })
635
-
636
- return () => {
637
- destroy$.next(undefined)
638
- // highlightSubscription.unsubscribe()
639
- }
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
+ EventGrid,
15
+ ChartParams,
16
+ ContainerPosition,
17
+ Layout,
18
+ TransformData,
19
+ ColorType } from '@orbcharts/core'
20
+ import { getDatumColor, getClassName, getUniID } from '../utils/orbchartsUtils'
21
+ import { gridSelectionsObservable } from '../grid/gridObservables'
22
+
23
+ export interface BaseDotsParams {
24
+ radius: number
25
+ fillColorType: ColorType
26
+ strokeColorType: ColorType
27
+ strokeWidth: number
28
+ onlyShowHighlighted: boolean
29
+ }
30
+
31
+ interface BaseDotsContext {
32
+ selection: d3.Selection<any, unknown, any, unknown>
33
+ computedData$: Observable<ComputedDataGrid>
34
+ visibleComputedData$: Observable<ComputedDatumGrid[][]>
35
+ existSeriesLabels$: Observable<string[]>
36
+ SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
37
+ GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
38
+ fullParams$: Observable<BaseDotsParams>
39
+ fullChartParams$: Observable<ChartParams>
40
+ gridAxesTransform$: Observable<TransformData>
41
+ gridGraphicTransform$: Observable<TransformData>
42
+ gridGraphicReverseScale$: Observable<[number, number][]>
43
+ gridAxesSize$: Observable<{
44
+ width: number;
45
+ height: number;
46
+ }>
47
+ gridHighlight$: Observable<ComputedDatumGrid[]>
48
+ gridContainer$: Observable<ContainerPosition[]>
49
+ event$: Subject<EventGrid>
50
+ }
51
+
52
+
53
+ type ClipPathDatum = {
54
+ id: string;
55
+ // x: number;
56
+ // y: number;
57
+ width: number;
58
+ height: number;
59
+ }
60
+
61
+ // const pluginName = 'Dots'
62
+ // const circleGClassName = getClassName(pluginName, 'circleG')
63
+ // const circleClassName = getClassName(pluginName, 'circle')
64
+
65
+ function renderDots ({ graphicGSelection, circleGClassName, circleClassName, data, fullParams, fullChartParams, graphicReverseScale }: {
66
+ graphicGSelection: d3.Selection<SVGGElement, any, any, any>
67
+ circleGClassName: string
68
+ circleClassName: string
69
+ data: ComputedDatumGrid[][]
70
+ fullParams: BaseDotsParams
71
+ fullChartParams: ChartParams
72
+ graphicReverseScale: [number, number][]
73
+ }) {
74
+ const createEnterDuration = (enter: d3.Selection<d3.EnterElement, ComputedDatumGrid, SVGGElement, any>) => {
75
+ const enterSize = enter.size()
76
+ const eachDuration = fullChartParams.transitionDuration / enterSize
77
+ return eachDuration
78
+ }
79
+ // enterDuration
80
+ let enterDuration = 0
81
+
82
+ graphicGSelection
83
+ .each((seriesData, seriesIndex, g) => {
84
+ d3.select(g[seriesIndex])
85
+ .selectAll<SVGGElement, ComputedDatumGrid>('g')
86
+ .data(data[seriesIndex], d => d.id)
87
+ .join(
88
+ enter => {
89
+ // enterDuration
90
+ enterDuration = createEnterDuration(enter)
91
+
92
+ return enter
93
+ .append('g')
94
+ .classed(circleGClassName, true)
95
+ },
96
+ update => update,
97
+ exit => exit.remove()
98
+ )
99
+ .attr('transform', d => `translate(${d.axisX}, ${d.axisY})`)
100
+ .each((d, i, g) => {
101
+ const circle = d3.select(g[i])
102
+ .selectAll('circle')
103
+ .data([d])
104
+ .join(
105
+ enter => {
106
+ return enter
107
+ .append('circle')
108
+ .style('cursor', 'pointer')
109
+ .style('vector-effect', 'non-scaling-stroke')
110
+ .classed(circleClassName, true)
111
+ .attr('opacity', 0)
112
+ .transition()
113
+ .delay((_d, _i) => {
114
+ return i * enterDuration
115
+ })
116
+ .attr('opacity', 1)
117
+ },
118
+ update => {
119
+ return update
120
+ .transition()
121
+ .duration(50)
122
+ // .attr('cx', d => d.axisX)
123
+ // .attr('cy', d => d.axisY)
124
+ .attr('opacity', 1)
125
+ },
126
+ exit => exit.remove()
127
+ )
128
+ .attr('r', fullParams.radius)
129
+ .attr('fill', (d, i) => getDatumColor({ datum: d, colorType: fullParams.fillColorType, fullChartParams }))
130
+ .attr('stroke', (d, i) => getDatumColor({ datum: d, colorType: fullParams.strokeColorType, fullChartParams }))
131
+ .attr('stroke-width', fullParams.strokeWidth)
132
+ .attr('transform', `scale(${graphicReverseScale[seriesIndex][0] ?? 1}, ${graphicReverseScale[seriesIndex][1] ?? 1})`)
133
+ })
134
+ })
135
+
136
+ // const dots = graphicGSelection
137
+ // .selectAll<SVGGElement, ComputedDatumGrid>('g')
138
+ // .data(data, d => d.id)
139
+ // .join(
140
+ // enter => {
141
+ // // enterDuration
142
+ // enterDuration = createEnterDuration(enter)
143
+
144
+ // return enter
145
+ // .append('g')
146
+ // .classed(circleGClassName, true)
147
+ // },
148
+ // update => update,
149
+ // exit => exit.remove()
150
+ // )
151
+ // .attr('transform', d => `translate(${d.axisX}, ${d.axisY})`)
152
+ // .each((d, i, g) => {
153
+ // const circle = d3.select(g[i])
154
+ // .selectAll('circle')
155
+ // .data([d])
156
+ // .join(
157
+ // enter => {
158
+ // return enter
159
+ // .append('circle')
160
+ // .style('cursor', 'pointer')
161
+ // .style('vector-effect', 'non-scaling-stroke')
162
+ // .classed(circleClassName, true)
163
+ // .attr('opacity', 0)
164
+ // .transition()
165
+ // .delay((_d, _i) => {
166
+ // return i * enterDuration
167
+ // })
168
+ // .attr('opacity', 1)
169
+ // },
170
+ // update => {
171
+ // return update
172
+ // .transition()
173
+ // .duration(50)
174
+ // // .attr('cx', d => d.axisX)
175
+ // // .attr('cy', d => d.axisY)
176
+ // .attr('opacity', 1)
177
+ // },
178
+ // exit => exit.remove()
179
+ // )
180
+ // .attr('r', fullParams.radius)
181
+ // .attr('fill', (d, i) => getDatumColor({ datum: d, colorType: fullParams.fillColorType, fullChartParams }))
182
+ // .attr('stroke', (d, i) => getDatumColor({ datum: d, colorType: fullParams.strokeColorType, fullChartParams }))
183
+ // .attr('stroke-width', fullParams.strokeWidth)
184
+ // .attr('transform', `scale(${graphicReverseScale[0]}, ${graphicReverseScale[1]})`)
185
+ // })
186
+
187
+ const graphicCircleSelection: d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown> = graphicGSelection.selectAll(`circle.${circleClassName}`)
188
+
189
+ return graphicCircleSelection
190
+ }
191
+
192
+
193
+ function highlightDots ({ selection, ids, onlyShowHighlighted, fullChartParams }: {
194
+ selection: d3.Selection<SVGGElement, ComputedDatumGrid, any, any>
195
+ ids: string[]
196
+ onlyShowHighlighted: boolean
197
+ fullChartParams: ChartParams
198
+ }) {
199
+ selection.interrupt('highlight')
200
+ if (!ids.length) {
201
+ // remove highlight
202
+ selection
203
+ .transition('highlight')
204
+ .duration(200)
205
+ .style('opacity', onlyShowHighlighted === true ? 0 : 1)
206
+ return
207
+ }
208
+
209
+ selection
210
+ .each((d, i, n) => {
211
+ if (ids.includes(d.id)) {
212
+ d3.select(n[i])
213
+ .style('opacity', 1)
214
+ .transition('highlight')
215
+ .duration(200)
216
+ } else {
217
+ d3.select(n[i])
218
+ .style('opacity', onlyShowHighlighted === true ? 0 : fullChartParams.styles.unhighlightedOpacity)
219
+ .transition('highlight')
220
+ .duration(200)
221
+ }
222
+ })
223
+ }
224
+
225
+ function renderClipPath ({ defsSelection, clipPathData }: {
226
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
227
+ clipPathData: ClipPathDatum[]
228
+ }) {
229
+ const clipPath = defsSelection
230
+ .selectAll<SVGClipPathElement, Layout>('clipPath')
231
+ .data(clipPathData)
232
+ .join(
233
+ enter => {
234
+ return enter
235
+ .append('clipPath')
236
+ },
237
+ update => update,
238
+ exit => exit.remove()
239
+ )
240
+ .attr('id', d => d.id)
241
+ .each((d, i, g) => {
242
+ const rect = d3.select(g[i])
243
+ .selectAll<SVGRectElement, typeof d>('rect')
244
+ .data([d])
245
+ .join('rect')
246
+ .attr('x', 0)
247
+ .attr('y', 0)
248
+ .attr('width', _d => _d.width)
249
+ .attr('height', _d => _d.height)
250
+ })
251
+
252
+ }
253
+
254
+
255
+
256
+ export const createBaseDots: BasePluginFn<BaseDotsContext> = (pluginName: string, {
257
+ selection,
258
+ computedData$,
259
+ visibleComputedData$,
260
+ existSeriesLabels$,
261
+ SeriesDataMap$,
262
+ GroupDataMap$,
263
+ fullParams$,
264
+ fullChartParams$,
265
+ gridAxesTransform$,
266
+ gridGraphicTransform$,
267
+ gridGraphicReverseScale$,
268
+ gridAxesSize$,
269
+ gridHighlight$,
270
+ gridContainer$,
271
+ event$
272
+ }) => {
273
+
274
+ const destroy$ = new Subject()
275
+
276
+ const clipPathID = getUniID(pluginName, 'clipPath-box')
277
+ const circleGClassName = getClassName(pluginName, 'circleG')
278
+ const circleClassName = getClassName(pluginName, 'circle')
279
+
280
+ // const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
281
+ // .append('g')
282
+ // .attr('clip-path', `url(#${clipPathID})`)
283
+ // const defsSelection: d3.Selection<SVGDefsElement, any, any, any> = axisSelection.append('defs')
284
+ // const dataAreaSelection: d3.Selection<SVGGElement, any, any, any> = axisSelection.append('g')
285
+ const graphicSelection$: Subject<d3.Selection<SVGGElement, ComputedDatumGrid, any, any>> = new Subject()
286
+
287
+ // gridAxesTransform$
288
+ // .pipe(
289
+ // takeUntil(destroy$),
290
+ // map(d => d.value),
291
+ // distinctUntilChanged()
292
+ // ).subscribe(d => {
293
+ // axisSelection
294
+ // .style('transform', d)
295
+ // })
296
+
297
+ // gridGraphicTransform$
298
+ // .pipe(
299
+ // takeUntil(destroy$),
300
+ // switchMap(async d => d.value),
301
+ // distinctUntilChanged()
302
+ // ).subscribe(d => {
303
+ // dataAreaSelection
304
+ // .transition()
305
+ // .duration(50)
306
+ // .style('transform', d)
307
+ // })
308
+
309
+ // const seriesSelection$ = computedData$.pipe(
310
+ // takeUntil(destroy$),
311
+ // distinctUntilChanged((a, b) => {
312
+ // // 只有當series的數量改變時,才重新計算
313
+ // return a.length === b.length
314
+ // }),
315
+ // map((computedData, i) => {
316
+ // return selection
317
+ // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${seriesClassName}`)
318
+ // .data(computedData, d => d[0] ? d[0].seriesIndex : i)
319
+ // .join(
320
+ // enter => {
321
+ // return enter
322
+ // .append('g')
323
+ // .classed(seriesClassName, true)
324
+ // .each((d, i, g) => {
325
+ // const axesSelection = d3.select(g[i])
326
+ // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${axesClassName}`)
327
+ // .data([i])
328
+ // .join(
329
+ // enter => {
330
+ // return enter
331
+ // .append('g')
332
+ // .classed(axesClassName, true)
333
+ // .attr('clip-path', `url(#${clipPathID})`)
334
+ // .each((d, i, g) => {
335
+ // const defsSelection = d3.select(g[i])
336
+ // .selectAll<SVGDefsElement, any>('defs')
337
+ // .data([i])
338
+ // .join('defs')
339
+
340
+ // const graphicGSelection = d3.select(g[i])
341
+ // .selectAll<SVGGElement, any>('g')
342
+ // .data([i])
343
+ // .join('g')
344
+ // .classed(graphicClassName, true)
345
+ // })
346
+ // },
347
+ // update => update,
348
+ // exit => exit.remove()
349
+ // )
350
+ // })
351
+ // },
352
+ // update => update,
353
+ // exit => exit.remove()
354
+ // )
355
+ // })
356
+ // )
357
+
358
+ // combineLatest({
359
+ // seriesSelection: seriesSelection$,
360
+ // gridContainer: gridContainer$
361
+ // }).pipe(
362
+ // takeUntil(destroy$),
363
+ // switchMap(async d => d)
364
+ // ).subscribe(data => {
365
+ // data.seriesSelection
366
+ // .transition()
367
+ // .attr('transform', (d, i) => {
368
+ // const translate = data.gridContainer[i].translate
369
+ // const scale = data.gridContainer[i].scale
370
+ // return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
371
+ // })
372
+ // })
373
+
374
+
375
+ // const axesSelection$ = combineLatest({
376
+ // seriesSelection: seriesSelection$,
377
+ // gridAxesTransform: gridAxesTransform$
378
+ // }).pipe(
379
+ // takeUntil(destroy$),
380
+ // switchMap(async d => d),
381
+ // map(data => {
382
+ // return data.seriesSelection
383
+ // .select<SVGGElement>(`g.${axesClassName}`)
384
+ // .style('transform', data.gridAxesTransform.value)
385
+ // })
386
+ // )
387
+ // const defsSelection$ = axesSelection$.pipe(
388
+ // takeUntil(destroy$),
389
+ // map(axesSelection => {
390
+ // return axesSelection.select<SVGDefsElement>('defs')
391
+ // })
392
+ // )
393
+ // const graphicGSelection$ = combineLatest({
394
+ // axesSelection: axesSelection$,
395
+ // gridGraphicTransform: gridGraphicTransform$
396
+ // }).pipe(
397
+ // takeUntil(destroy$),
398
+ // switchMap(async d => d),
399
+ // map(data => {
400
+ // const graphicGSelection = data.axesSelection
401
+ // .select<SVGGElement>(`g.${graphicClassName}`)
402
+ // graphicGSelection
403
+ // .transition()
404
+ // .duration(50)
405
+ // .style('transform', data.gridGraphicTransform.value)
406
+ // return graphicGSelection
407
+ // })
408
+ // )
409
+
410
+ const {
411
+ seriesSelection$,
412
+ axesSelection$,
413
+ defsSelection$,
414
+ graphicGSelection$
415
+ } = gridSelectionsObservable({
416
+ selection,
417
+ pluginName,
418
+ clipPathID,
419
+ existSeriesLabels$,
420
+ gridContainer$,
421
+ gridAxesTransform$,
422
+ gridGraphicTransform$
423
+ })
424
+
425
+ const graphicReverseScale$: Observable<[number, number][]> = combineLatest({
426
+ // gridGraphicTransform: gridGraphicTransform$,
427
+ // gridContainer: gridContainer$,
428
+ // gridAxesTransform: gridAxesTransform$
429
+ computedData: computedData$,
430
+ gridGraphicReverseScale: gridGraphicReverseScale$
431
+ }).pipe(
432
+ takeUntil(destroy$),
433
+ switchMap(async data => data),
434
+ map(data => {
435
+ return data.computedData.map((series, seriesIndex) => {
436
+ return data.gridGraphicReverseScale[seriesIndex]
437
+ })
438
+ })
439
+ )
440
+
441
+ const clipPathSubscription = combineLatest({
442
+ defsSelection: defsSelection$,
443
+ gridAxesSize: gridAxesSize$,
444
+ }).pipe(
445
+ takeUntil(destroy$),
446
+ switchMap(async (d) => d),
447
+ ).subscribe(data => {
448
+ // 外層的遮罩
449
+ const clipPathData = [{
450
+ id: clipPathID,
451
+ width: data.gridAxesSize.width,
452
+ height: data.gridAxesSize.height
453
+ }]
454
+ renderClipPath({
455
+ defsSelection: data.defsSelection,
456
+ clipPathData,
457
+ })
458
+ })
459
+
460
+ // const visibleComputedData$ = computedData$.pipe(
461
+ // map(computedData => {
462
+ // return computedData
463
+ // .map(d => {
464
+ // return d.filter(_d => _d.visible == true)
465
+ // })
466
+ // })
467
+ // )
468
+
469
+ // const SeriesDataMap$ = visibleComputedData$.pipe(
470
+ // map(d => makeGridSeriesDataMap(d))
471
+ // )
472
+
473
+ // const GroupDataMap$ = visibleComputedData$.pipe(
474
+ // map(d => makeGridGroupDataMap(d))
475
+ // )
476
+
477
+ // const DataMap$ = computedData$.pipe(
478
+ // map(d => {
479
+ // const DataMap: Map<string, ComputedDatumGrid> = new Map()
480
+ // d.flat().forEach(_d => DataMap.set(_d.id, _d))
481
+ // return DataMap
482
+ // })
483
+ // )
484
+
485
+ const highlightTarget$ = fullChartParams$.pipe(
486
+ takeUntil(destroy$),
487
+ map(d => d.highlightTarget),
488
+ distinctUntilChanged()
489
+ )
490
+
491
+ combineLatest({
492
+ graphicGSelection: graphicGSelection$,
493
+ computedData: computedData$,
494
+ visibleComputedData: visibleComputedData$,
495
+ SeriesDataMap: SeriesDataMap$,
496
+ GroupDataMap: GroupDataMap$,
497
+ graphicReverseScale: graphicReverseScale$,
498
+ fullChartParams: fullChartParams$,
499
+ fullParams: fullParams$,
500
+ highlightTarget: highlightTarget$
501
+ }).pipe(
502
+ takeUntil(destroy$),
503
+ switchMap(async (d) => d),
504
+ ).subscribe(data => {
505
+
506
+ const graphicSelection = renderDots({
507
+ graphicGSelection: data.graphicGSelection,
508
+ circleGClassName,
509
+ circleClassName,
510
+ data: data.visibleComputedData,
511
+ fullParams: data.fullParams,
512
+ fullChartParams: data.fullChartParams,
513
+ graphicReverseScale: data.graphicReverseScale
514
+ })
515
+
516
+ graphicSelection
517
+ .on('mouseover', (event, datum) => {
518
+ event.stopPropagation()
519
+
520
+ event$.next({
521
+ type: 'grid',
522
+ eventName: 'mouseover',
523
+ pluginName,
524
+ highlightTarget: data.highlightTarget,
525
+ datum,
526
+ gridIndex: datum.gridIndex,
527
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
528
+ seriesIndex: datum.seriesIndex,
529
+ seriesLabel: datum.seriesLabel,
530
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
531
+ groupIndex: datum.groupIndex,
532
+ groupLabel: datum.groupLabel,
533
+ event,
534
+ data: data.computedData
535
+ })
536
+ })
537
+ .on('mousemove', (event, datum) => {
538
+ event.stopPropagation()
539
+
540
+ event$.next({
541
+ type: 'grid',
542
+ eventName: 'mousemove',
543
+ pluginName,
544
+ highlightTarget: data.highlightTarget,
545
+ data: data.computedData,
546
+ datum,
547
+ gridIndex: datum.gridIndex,
548
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
549
+ seriesIndex: datum.seriesIndex,
550
+ seriesLabel: datum.seriesLabel,
551
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
552
+ groupIndex: datum.groupIndex,
553
+ groupLabel: datum.groupLabel,
554
+ event
555
+ })
556
+ })
557
+ .on('mouseout', (event, datum) => {
558
+ event.stopPropagation()
559
+
560
+ event$.next({
561
+ type: 'grid',
562
+ eventName: 'mouseout',
563
+ pluginName,
564
+ highlightTarget: data.highlightTarget,
565
+ datum,
566
+ gridIndex: datum.gridIndex,
567
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
568
+ seriesIndex: datum.seriesIndex,
569
+ seriesLabel: datum.seriesLabel,
570
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
571
+ groupIndex: datum.groupIndex,
572
+ groupLabel: datum.groupLabel,
573
+ event,
574
+ data: data.computedData
575
+ })
576
+ })
577
+ .on('click', (event, datum) => {
578
+ event.stopPropagation()
579
+
580
+ event$.next({
581
+ type: 'grid',
582
+ eventName: 'click',
583
+ pluginName,
584
+ highlightTarget: data.highlightTarget,
585
+ datum,
586
+ gridIndex: datum.gridIndex,
587
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
588
+ seriesIndex: datum.seriesIndex,
589
+ seriesLabel: datum.seriesLabel,
590
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
591
+ groupIndex: datum.groupIndex,
592
+ groupLabel: datum.groupLabel,
593
+ event,
594
+ data: data.computedData
595
+ })
596
+ })
597
+
598
+ graphicSelection$.next(graphicSelection)
599
+
600
+ })
601
+
602
+ // const datumList$ = computedData$.pipe(
603
+ // takeUntil(destroy$),
604
+ // map(d => d.flat())
605
+ // )
606
+ // const highlight$ = highlightObservable({ datumList$, fullChartParams$, event$: store.event$ })
607
+ // const highlightSubscription = gridHighlight$.subscribe()
608
+ const onlyShowHighlighted$ = fullParams$.pipe(
609
+ takeUntil(destroy$),
610
+ map(d => d.onlyShowHighlighted),
611
+ distinctUntilChanged()
612
+ )
613
+
614
+ fullChartParams$.pipe(
615
+ takeUntil(destroy$),
616
+ switchMap(d => combineLatest({
617
+ graphicSelection: graphicSelection$,
618
+ highlight: gridHighlight$.pipe(
619
+ map(data => data.map(d => d.id))
620
+ ),
621
+ onlyShowHighlighted: onlyShowHighlighted$,
622
+ fullChartParams: fullChartParams$
623
+ }).pipe(
624
+ takeUntil(destroy$),
625
+ switchMap(async d => d)
626
+ ))
627
+ ).subscribe(data => {
628
+ highlightDots({
629
+ selection: data.graphicSelection,
630
+ ids: data.highlight,
631
+ onlyShowHighlighted: data.onlyShowHighlighted,
632
+ fullChartParams: data.fullChartParams
633
+ })
634
+ })
635
+
636
+ return () => {
637
+ destroy$.next(undefined)
638
+ // highlightSubscription.unsubscribe()
639
+ }
640
640
  }