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

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 (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,638 +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<string[]>
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$,
619
- onlyShowHighlighted: onlyShowHighlighted$,
620
- fullChartParams: fullChartParams$
621
- }).pipe(
622
- takeUntil(destroy$),
623
- switchMap(async d => d)
624
- ))
625
- ).subscribe(data => {
626
- highlightDots({
627
- selection: data.graphicSelection,
628
- ids: data.highlight,
629
- onlyShowHighlighted: data.onlyShowHighlighted,
630
- fullChartParams: data.fullChartParams
631
- })
632
- })
633
-
634
- return () => {
635
- destroy$.next(undefined)
636
- highlightSubscription.unsubscribe()
637
- }
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
+ }
638
640
  }