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

Sign up to get free protection for your applications and to get access to all the features.
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,660 +1,660 @@
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 } from '@orbcharts/core'
19
- import { getD3TransitionEase } from '../utils/d3Utils'
20
- import { getClassName, getUniID } from '../utils/orbchartsUtils'
21
- import { gridSelectionsObservable } from '../grid/gridObservables'
22
-
23
- export interface BaseBarsTriangleParams {
24
- barWidth: number
25
- barPadding: number
26
- barGroupPadding: number // 群組和群組間的間隔
27
- linearGradientOpacity: [number, number]
28
- }
29
-
30
- interface BaseBarsContext {
31
- selection: d3.Selection<any, unknown, any, unknown>
32
- computedData$: Observable<ComputedDataGrid>
33
- visibleComputedData$: Observable<ComputedDatumGrid[][]>
34
- existSeriesLabels$: Observable<string[]>
35
- SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
36
- GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
37
- fullParams$: Observable<BaseBarsTriangleParams>
38
- fullChartParams$: Observable<ChartParams>
39
- gridAxesTransform$: Observable<TransformData>
40
- gridGraphicTransform$: Observable<TransformData>
41
- gridAxesSize$: Observable<{
42
- width: number;
43
- height: number;
44
- }>
45
- gridHighlight$: Observable<ComputedDatumGrid[]>
46
- gridContainer$: Observable<ContainerPosition[]>
47
- isSeriesPositionSeprate$: Observable<boolean>
48
- event$: Subject<EventGrid>
49
- }
50
-
51
-
52
- interface RenderBarParams {
53
- graphicGSelection: d3.Selection<SVGGElement, unknown, any, any>
54
- pathGClassName: string
55
- pathClassName: string
56
- computedData: ComputedDataGrid
57
- linearGradientIds: string[]
58
- zeroYArr: number[]
59
- groupLabels: string[]
60
- barScale: d3.ScalePoint<string>
61
- params: BaseBarsTriangleParams
62
- chartParams: ChartParams
63
- barWidth: number
64
- delayGroup: number
65
- transitionItem: number
66
- isSeriesPositionSeprate: boolean
67
- }
68
-
69
- // interface BarDatumGrid extends ComputedDatumGrid {
70
- // linearGradientId: string
71
- // }
72
-
73
- type ClipPathDatum = {
74
- id: string;
75
- // x: number;
76
- // y: number;
77
- width: number;
78
- height: number;
79
- }
80
-
81
- // const pluginName = 'BaseBarsTriangle'
82
- // const pathGClassName = getClassName(pluginName, 'pathG')
83
- // const pathClassName = getClassName(pluginName, 'path')
84
- // group的delay在動畫中的佔比(剩餘部份的時間為圖形本身的動畫時間,因為delay時間和最後一個group的動畫時間加總為1)
85
- const groupDelayProportionOfDuration = 0.3
86
-
87
- function calcBarWidth ({ axisWidth, groupAmount, barAmountOfGroup, barPadding = 0, barGroupPadding = 0 }: {
88
- axisWidth: number
89
- groupAmount: number
90
- barAmountOfGroup: number
91
- barPadding: number
92
- barGroupPadding: number
93
- }) {
94
- const eachGroupWidth = axisWidth / (groupAmount - 1)
95
- const width = (eachGroupWidth - barGroupPadding) / barAmountOfGroup - barPadding
96
- return width > 1 ? width : 1
97
- }
98
-
99
- function makeBarScale (barWidth: number, seriesLabels: string[], params: BaseBarsTriangleParams) {
100
- const barHalfWidth = barWidth! / 2
101
- const barGroupWidth = barWidth * seriesLabels.length + params.barPadding! * seriesLabels.length
102
- return d3.scalePoint()
103
- .domain(seriesLabels)
104
- .range([-barGroupWidth / 2 + barHalfWidth, barGroupWidth / 2 - barHalfWidth])
105
- }
106
-
107
- function calcDelayGroup (barGroupAmount: number, totalDuration: number) {
108
- if (barGroupAmount <= 1) {
109
- // 一筆內計算會出錯所以不算
110
- return 0
111
- }
112
- return totalDuration / (barGroupAmount - 1) * groupDelayProportionOfDuration // 依group數量計算
113
- }
114
-
115
- function calctransitionItem (barGroupAmount: number, totalDuration: number) {
116
- if (barGroupAmount <= 1) {
117
- // 一筆內不會有delay
118
- return totalDuration
119
- }
120
- return totalDuration * (1 - groupDelayProportionOfDuration) // delay後剩餘的時間
121
- }
122
-
123
- function renderTriangleBars ({ graphicGSelection, pathGClassName, pathClassName, computedData, linearGradientIds, zeroYArr, groupLabels, barScale, params, chartParams, barWidth, delayGroup, transitionItem, isSeriesPositionSeprate }: RenderBarParams) {
124
-
125
- const barHalfWidth = barWidth! / 2
126
-
127
- graphicGSelection
128
- .each((d, seriesIndex, g) => {
129
- // g
130
- const gSelection = d3.select(g[seriesIndex])
131
- .selectAll<SVGGElement, ComputedDatumGrid>(`g.${pathGClassName}`)
132
- .data(computedData[seriesIndex] ?? [])
133
- .join(
134
- enter => {
135
- const enterSelection = enter
136
- .append('g')
137
- .classed(pathGClassName, true)
138
- .attr('cursor', 'pointer')
139
- enterSelection
140
- .append('path')
141
- .classed(pathClassName, true)
142
- .style('vector-effect', 'non-scaling-stroke')
143
- .attr('d', (d) => {
144
- const x = -barHalfWidth
145
- const y1 = zeroYArr[seriesIndex]
146
- const y2 = zeroYArr[seriesIndex]
147
- return `M${x},${y1} L${x + (barWidth! / 2)},${y2} ${x + barWidth!},${y1}`
148
- })
149
- return enterSelection
150
- },
151
- update => update,
152
- exit => exit.remove()
153
- )
154
- .attr('transform', d => `translate(${isSeriesPositionSeprate ? 0 : barScale(d.seriesLabel)!}, 0)`)
155
-
156
- // path
157
- gSelection.select(`path.${pathClassName}`)
158
- .attr('height', d => Math.abs(d.axisYFromZero))
159
- .attr('y', d => d.axisY < zeroYArr[seriesIndex] ? d.axisY : zeroYArr[seriesIndex])
160
- .attr('x', d => isSeriesPositionSeprate ? 0 : barScale(d.seriesLabel)!)
161
- // .style('fill', d => `url(#${d.linearGradientId})`)
162
- .style('fill', d => `url(#${linearGradientIds[d.seriesIndex]})`)
163
- .attr('stroke', d => d.color)
164
- .attr('transform', d => `translate(${(d ? d.axisX : 0)}, ${0})`)
165
- .transition()
166
- .duration(transitionItem)
167
- .ease(getD3TransitionEase(chartParams.transitionEase))
168
- .delay((d, i) => d.groupIndex * delayGroup)
169
- // .attr('transform', `translate(${-barHalfWidth}, 0)`)
170
- // .attr('x', d => itemScale(d.itemLabel)!)
171
- // .attr('y', d => -d.y)
172
- .attr('d', (d) => {
173
- const x = -barHalfWidth
174
- const y1 = zeroYArr[seriesIndex]
175
- const y2 = d.axisY
176
- return `M${x},${y1} L${x + (barWidth! / 2)},${y2} ${x + barWidth!},${y1}`
177
- })
178
- })
179
-
180
- const graphicBarSelection: d3.Selection<SVGPathElement, ComputedDatumGrid, any, any> = graphicGSelection.selectAll(`path.${pathClassName}`)
181
-
182
- return graphicBarSelection
183
- }
184
-
185
- function renderLinearGradient ({ defsSelection, computedData, linearGradientIds, params }: {
186
- defsSelection: d3.Selection<SVGDefsElement, any, any, any>
187
- computedData: ComputedDataGrid
188
- linearGradientIds: string[]
189
- params: BaseBarsTriangleParams
190
- }) {
191
- defsSelection!
192
- .selectAll<SVGLinearGradientElement, ComputedDatumGrid>('linearGradient')
193
- .data(computedData ?? [])
194
- .join(
195
- enter => {
196
- return enter
197
- .append('linearGradient')
198
- .attr('x1', '0%')
199
- .attr('x2', '0%')
200
- .attr('y1', '100%')
201
- .attr('y2', '0%')
202
- .attr('spreadMethod', 'pad')
203
- },
204
- update => update,
205
- exit => exit.remove()
206
- )
207
- .attr('id', (d, i) => {
208
- return d[0] ? linearGradientIds[d[0].seriesIndex] : ''
209
- })
210
- .html((d, i) => {
211
- const color = d[0] ? d[0].color : ''
212
- return `
213
- <stop offset="0%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[0]}"/>
214
- <stop offset="100%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[1]}"/>
215
- `
216
- })
217
-
218
- }
219
-
220
-
221
- function renderClipPath ({ defsSelection, clipPathData }: {
222
- defsSelection: d3.Selection<SVGDefsElement, any, any, any>
223
- clipPathData: ClipPathDatum[]
224
- }) {
225
- const clipPath = defsSelection
226
- .selectAll<SVGClipPathElement, Layout>('clipPath')
227
- .data(clipPathData)
228
- .join(
229
- enter => {
230
- return enter
231
- .append('clipPath')
232
- },
233
- update => update,
234
- exit => exit.remove()
235
- )
236
- .attr('id', d => d.id)
237
- .each((d, i, g) => {
238
- const rect = d3.select(g[i])
239
- .selectAll<SVGRectElement, typeof d>('rect')
240
- .data([d])
241
- .join(
242
- enter => {
243
- return enter
244
- .append('rect')
245
- },
246
- update => update,
247
- exit => exit.remove()
248
- )
249
- .attr('x', 0)
250
- .attr('y', 0)
251
- .attr('width', _d => _d.width)
252
- .attr('height', _d => _d.height)
253
- })
254
- }
255
-
256
- function highlight ({ selection, ids, fullChartParams }: {
257
- selection: d3.Selection<SVGPathElement, ComputedDatumGrid, any, any>
258
- ids: string[]
259
- fullChartParams: ChartParams
260
- }) {
261
- selection.interrupt('highlight')
262
-
263
- const removeHighlight = () => {
264
- selection
265
- .transition('highlight')
266
- .duration(200)
267
- .style('opacity', 1)
268
- }
269
-
270
- if (!ids.length) {
271
- removeHighlight()
272
- return
273
- }
274
-
275
- selection
276
- .each((d, i, n) => {
277
- if (ids.includes(d.id)) {
278
- d3.select(n[i])
279
- .style('opacity', 1)
280
- } else {
281
- d3.select(n[i])
282
- .style('opacity', fullChartParams.styles.unhighlightedOpacity)
283
- }
284
- })
285
- }
286
-
287
-
288
- export const createBaseBarsTriangle: BasePluginFn<BaseBarsContext> = (pluginName: string, {
289
- selection,
290
- computedData$,
291
- visibleComputedData$,
292
- existSeriesLabels$,
293
- SeriesDataMap$,
294
- GroupDataMap$,
295
- fullParams$,
296
- fullChartParams$,
297
- gridAxesTransform$,
298
- gridGraphicTransform$,
299
- gridAxesSize$,
300
- gridHighlight$,
301
- gridContainer$,
302
- isSeriesPositionSeprate$,
303
- event$
304
- }) => {
305
- const destroy$ = new Subject()
306
-
307
- const clipPathID = getUniID(pluginName, 'clipPath-box')
308
- const pathGClassName = getClassName(pluginName, 'pathG')
309
- const pathClassName = getClassName(pluginName, 'path')
310
-
311
- const {
312
- seriesSelection$,
313
- axesSelection$,
314
- defsSelection$,
315
- graphicGSelection$
316
- } = gridSelectionsObservable({
317
- selection,
318
- pluginName,
319
- clipPathID,
320
- existSeriesLabels$,
321
- gridContainer$,
322
- gridAxesTransform$,
323
- gridGraphicTransform$
324
- })
325
-
326
- // valueAxis 的起始座標
327
- const valueAxisStart$: Observable<number> = gridGraphicTransform$.pipe(
328
- takeUntil(destroy$),
329
- map(data => {
330
- // 抵消掉外層的變型
331
- return - data.translate[1] / data.scale[1]
332
- })
333
- )
334
-
335
- const zeroYArr$ = visibleComputedData$.pipe(
336
- // map(d => d[0] && d[0][0]
337
- // ? d[0][0].axisY - d[0][0].axisYFromZero
338
- // : 0),
339
- map(data => {
340
- return data.map(d => {
341
- return d[0] ? d[0].axisY - d[0].axisYFromZero : 0
342
- })
343
- }),
344
- distinctUntilChanged()
345
- )
346
-
347
- const barWidth$ = combineLatest({
348
- computedData: computedData$,
349
- visibleComputedData: visibleComputedData$,
350
- params: fullParams$,
351
- gridAxesSize: gridAxesSize$,
352
- isSeriesPositionSeprate: isSeriesPositionSeprate$
353
- }).pipe(
354
- takeUntil(destroy$),
355
- switchMap(async d => d),
356
- map(data => {
357
- if (data.params.barWidth) {
358
- return data.params.barWidth
359
- } else if (data.isSeriesPositionSeprate) {
360
- return calcBarWidth({
361
- axisWidth: data.gridAxesSize.width,
362
- groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
363
- barAmountOfGroup: 1,
364
- barPadding: data.params.barPadding,
365
- barGroupPadding: data.params.barGroupPadding
366
- })
367
- } else {
368
- return calcBarWidth({
369
- axisWidth: data.gridAxesSize.width,
370
- groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
371
- barAmountOfGroup: data.visibleComputedData.length,
372
- barPadding: data.params.barPadding,
373
- barGroupPadding: data.params.barGroupPadding
374
- })
375
- }
376
- })
377
- )
378
-
379
- const seriesLabels$ = visibleComputedData$.pipe(
380
- takeUntil(destroy$),
381
- map(data => {
382
- const SeriesLabelSet: Set<string> = new Set()
383
- data.forEach(d => {
384
- d.forEach(_d => {
385
- SeriesLabelSet.add(_d.seriesLabel)
386
- })
387
- })
388
- return Array.from(SeriesLabelSet)
389
- })
390
- )
391
-
392
- const groupLabels$ = visibleComputedData$.pipe(
393
- takeUntil(destroy$),
394
- map(data => {
395
- const GroupLabelSet: Set<string> = new Set()
396
- data.forEach(d => {
397
- d.forEach(_d => {
398
- GroupLabelSet.add(_d.groupLabel)
399
- })
400
- })
401
- return Array.from(GroupLabelSet)
402
- })
403
- )
404
-
405
- const barScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
406
- combineLatest({
407
- seriesLabels: seriesLabels$,
408
- barWidth: barWidth$,
409
- params: fullParams$,
410
- }).pipe(
411
- takeUntil(destroy$),
412
- switchMap(async d => d)
413
- ).subscribe(data => {
414
- const barScale = makeBarScale(data.barWidth, data.seriesLabels, data.params)
415
- subscriber.next(barScale)
416
- })
417
- })
418
-
419
- const transitionDuration$ = fullChartParams$.pipe(
420
- takeUntil(destroy$),
421
- map(d => d.transitionDuration),
422
- distinctUntilChanged()
423
- )
424
-
425
- const delayGroup$ = new Observable<number>(subscriber => {
426
- combineLatest({
427
- groupLabels: groupLabels$,
428
- transitionDuration: transitionDuration$,
429
- }).pipe(
430
- switchMap(async d => d)
431
- ).subscribe(data => {
432
- const delay = calcDelayGroup(data.groupLabels.length, data.transitionDuration)
433
- subscriber.next(delay)
434
- })
435
- }).pipe(
436
- takeUntil(destroy$),
437
- distinctUntilChanged()
438
- )
439
-
440
- const transitionItem$ = new Observable<number>(subscriber => {
441
- combineLatest({
442
- groupLabels: groupLabels$,
443
- transitionDuration: transitionDuration$
444
- }).pipe(
445
- switchMap(async d => d)
446
- ).subscribe(data => {
447
- const transition = calctransitionItem(data.groupLabels.length, data.transitionDuration)
448
- subscriber.next(transition)
449
- })
450
- }).pipe(
451
- takeUntil(destroy$),
452
- distinctUntilChanged()
453
- )
454
-
455
- //
456
-
457
- combineLatest({
458
- defsSelection: defsSelection$,
459
- gridAxesSize: gridAxesSize$,
460
- }).pipe(
461
- takeUntil(destroy$),
462
- switchMap(async d => d)
463
- ).subscribe(data => {
464
- const clipPathData = [{
465
- id: clipPathID,
466
- width: data.gridAxesSize.width,
467
- height: data.gridAxesSize.height
468
- }]
469
- renderClipPath({
470
- defsSelection: data.defsSelection,
471
- clipPathData
472
- })
473
- })
474
-
475
-
476
- const highlightTarget$ = fullChartParams$.pipe(
477
- takeUntil(destroy$),
478
- map(d => d.highlightTarget),
479
- distinctUntilChanged()
480
- )
481
-
482
- const barSelection$ = new Subject<d3.Selection<SVGPathElement, ComputedDatumGrid, SVGGElement, unknown>>()
483
-
484
- const linearGradientIds$ = seriesLabels$.pipe(
485
- takeUntil(destroy$),
486
- map(d => d.map((d, i) => {
487
- return getUniID(pluginName, `lineargradient-${d}`)
488
- }))
489
- )
490
-
491
- // const barData$ = combineLatest({
492
- // linearGradientIds: linearGradientIds$,
493
- // computedData: computedData$
494
- // }).pipe(
495
- // takeUntil(destroy$),
496
- // switchMap(async d => d),
497
- // map(data => {
498
- // return data.computedData.map((series, seriesIndex) => {
499
- // return series.map((_d, _i) => {
500
- // return <BarDatumGrid>{
501
- // linearGradientId: data.linearGradientIds[seriesIndex],
502
- // ..._d
503
- // }
504
- // })
505
- // })
506
- // })
507
- // )
508
-
509
- combineLatest({
510
- graphicGSelection: graphicGSelection$,
511
- defsSelection: defsSelection$,
512
- computedData: computedData$,
513
- linearGradientIds: linearGradientIds$,
514
- zeroYArr: zeroYArr$,
515
- groupLabels: groupLabels$,
516
- barScale: barScale$,
517
- params: fullParams$,
518
- chartParams: fullChartParams$,
519
- highlightTarget: highlightTarget$,
520
- barWidth: barWidth$,
521
- delayGroup: delayGroup$,
522
- transitionItem: transitionItem$,
523
- SeriesDataMap: SeriesDataMap$,
524
- GroupDataMap: GroupDataMap$,
525
- isSeriesPositionSeprate: isSeriesPositionSeprate$
526
- }).pipe(
527
- takeUntil(destroy$),
528
- switchMap(async (d) => d),
529
- ).subscribe(data => {
530
-
531
- const barSelection = renderTriangleBars({
532
- graphicGSelection: data.graphicGSelection,
533
- pathGClassName,
534
- pathClassName,
535
- computedData: data.computedData,
536
- linearGradientIds: data.linearGradientIds,
537
- zeroYArr: data.zeroYArr,
538
- groupLabels: data.groupLabels,
539
- barScale: data.barScale,
540
- params: data.params,
541
- chartParams: data.chartParams,
542
- barWidth: data.barWidth,
543
- delayGroup: data.delayGroup,
544
- transitionItem: data.transitionItem,
545
- isSeriesPositionSeprate: data.isSeriesPositionSeprate
546
- })
547
- renderLinearGradient({
548
- defsSelection: data.defsSelection,
549
- computedData: data.computedData,
550
- linearGradientIds: data.linearGradientIds,
551
- params: data.params
552
- })
553
-
554
- barSelection!
555
- .on('mouseover', (event, datum) => {
556
- event.stopPropagation()
557
-
558
- event$.next({
559
- type: 'grid',
560
- eventName: 'mouseover',
561
- pluginName,
562
- highlightTarget: data.highlightTarget,
563
- 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
- .on('mousemove', (event, datum) => {
576
- event.stopPropagation()
577
-
578
- event$.next({
579
- type: 'grid',
580
- eventName: 'mousemove',
581
- pluginName,
582
- highlightTarget: data.highlightTarget,
583
- datum,
584
- gridIndex: datum.gridIndex,
585
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
586
- seriesIndex: datum.seriesIndex,
587
- seriesLabel: datum.seriesLabel,
588
- groups: data.GroupDataMap.get(datum.groupLabel)!,
589
- groupIndex: datum.groupIndex,
590
- groupLabel: datum.groupLabel,
591
- event,
592
- data: data.computedData
593
- })
594
- })
595
- .on('mouseout', (event, datum) => {
596
- event.stopPropagation()
597
-
598
- event$.next({
599
- type: 'grid',
600
- eventName: 'mouseout',
601
- pluginName,
602
- highlightTarget: data.highlightTarget,
603
- datum,
604
- gridIndex: datum.gridIndex,
605
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
606
- seriesIndex: datum.seriesIndex,
607
- seriesLabel: datum.seriesLabel,
608
- groups: data.GroupDataMap.get(datum.groupLabel)!,
609
- groupIndex: datum.groupIndex,
610
- groupLabel: datum.groupLabel,
611
- event,
612
- data: data.computedData
613
- })
614
- })
615
- .on('click', (event, datum) => {
616
- event.stopPropagation()
617
-
618
- event$.next({
619
- type: 'grid',
620
- eventName: 'click',
621
- pluginName,
622
- highlightTarget: data.highlightTarget,
623
- datum,
624
- gridIndex: datum.gridIndex,
625
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
626
- seriesIndex: datum.seriesIndex,
627
- seriesLabel: datum.seriesLabel,
628
- groups: data.GroupDataMap.get(datum.groupLabel)!,
629
- groupIndex: datum.groupIndex,
630
- groupLabel: datum.groupLabel,
631
- event,
632
- data: data.computedData
633
- })
634
- })
635
-
636
- barSelection$.next(barSelection!)
637
- })
638
-
639
-
640
- combineLatest({
641
- barSelection: barSelection$,
642
- highlight: gridHighlight$.pipe(
643
- map(data => data.map(d => d.id))
644
- ),
645
- fullChartParams: fullChartParams$
646
- }).pipe(
647
- takeUntil(destroy$),
648
- switchMap(async d => d)
649
- ).subscribe(data => {
650
- highlight({
651
- selection: data.barSelection,
652
- ids: data.highlight,
653
- fullChartParams: data.fullChartParams
654
- })
655
- })
656
-
657
- return () => {
658
- destroy$.next(undefined)
659
- }
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 } from '@orbcharts/core'
19
+ import { getD3TransitionEase } from '../utils/d3Utils'
20
+ import { getClassName, getUniID } from '../utils/orbchartsUtils'
21
+ import { gridSelectionsObservable } from '../grid/gridObservables'
22
+
23
+ export interface BaseBarsTriangleParams {
24
+ barWidth: number
25
+ barPadding: number
26
+ barGroupPadding: number // 群組和群組間的間隔
27
+ linearGradientOpacity: [number, number]
28
+ }
29
+
30
+ interface BaseBarsContext {
31
+ selection: d3.Selection<any, unknown, any, unknown>
32
+ computedData$: Observable<ComputedDataGrid>
33
+ visibleComputedData$: Observable<ComputedDatumGrid[][]>
34
+ existSeriesLabels$: Observable<string[]>
35
+ SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
36
+ GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
37
+ fullParams$: Observable<BaseBarsTriangleParams>
38
+ fullChartParams$: Observable<ChartParams>
39
+ gridAxesTransform$: Observable<TransformData>
40
+ gridGraphicTransform$: Observable<TransformData>
41
+ gridAxesSize$: Observable<{
42
+ width: number;
43
+ height: number;
44
+ }>
45
+ gridHighlight$: Observable<ComputedDatumGrid[]>
46
+ gridContainer$: Observable<ContainerPosition[]>
47
+ isSeriesPositionSeprate$: Observable<boolean>
48
+ event$: Subject<EventGrid>
49
+ }
50
+
51
+
52
+ interface RenderBarParams {
53
+ graphicGSelection: d3.Selection<SVGGElement, unknown, any, any>
54
+ pathGClassName: string
55
+ pathClassName: string
56
+ computedData: ComputedDataGrid
57
+ linearGradientIds: string[]
58
+ zeroYArr: number[]
59
+ groupLabels: string[]
60
+ barScale: d3.ScalePoint<string>
61
+ params: BaseBarsTriangleParams
62
+ chartParams: ChartParams
63
+ barWidth: number
64
+ delayGroup: number
65
+ transitionItem: number
66
+ isSeriesPositionSeprate: boolean
67
+ }
68
+
69
+ // interface BarDatumGrid extends ComputedDatumGrid {
70
+ // linearGradientId: string
71
+ // }
72
+
73
+ type ClipPathDatum = {
74
+ id: string;
75
+ // x: number;
76
+ // y: number;
77
+ width: number;
78
+ height: number;
79
+ }
80
+
81
+ // const pluginName = 'BaseBarsTriangle'
82
+ // const pathGClassName = getClassName(pluginName, 'pathG')
83
+ // const pathClassName = getClassName(pluginName, 'path')
84
+ // group的delay在動畫中的佔比(剩餘部份的時間為圖形本身的動畫時間,因為delay時間和最後一個group的動畫時間加總為1)
85
+ const groupDelayProportionOfDuration = 0.3
86
+
87
+ function calcBarWidth ({ axisWidth, groupAmount, barAmountOfGroup, barPadding = 0, barGroupPadding = 0 }: {
88
+ axisWidth: number
89
+ groupAmount: number
90
+ barAmountOfGroup: number
91
+ barPadding: number
92
+ barGroupPadding: number
93
+ }) {
94
+ const eachGroupWidth = axisWidth / (groupAmount - 1)
95
+ const width = (eachGroupWidth - barGroupPadding) / barAmountOfGroup - barPadding
96
+ return width > 1 ? width : 1
97
+ }
98
+
99
+ function makeBarScale (barWidth: number, seriesLabels: string[], params: BaseBarsTriangleParams) {
100
+ const barHalfWidth = barWidth! / 2
101
+ const barGroupWidth = barWidth * seriesLabels.length + params.barPadding! * seriesLabels.length
102
+ return d3.scalePoint()
103
+ .domain(seriesLabels)
104
+ .range([-barGroupWidth / 2 + barHalfWidth, barGroupWidth / 2 - barHalfWidth])
105
+ }
106
+
107
+ function calcDelayGroup (barGroupAmount: number, totalDuration: number) {
108
+ if (barGroupAmount <= 1) {
109
+ // 一筆內計算會出錯所以不算
110
+ return 0
111
+ }
112
+ return totalDuration / (barGroupAmount - 1) * groupDelayProportionOfDuration // 依group數量計算
113
+ }
114
+
115
+ function calctransitionItem (barGroupAmount: number, totalDuration: number) {
116
+ if (barGroupAmount <= 1) {
117
+ // 一筆內不會有delay
118
+ return totalDuration
119
+ }
120
+ return totalDuration * (1 - groupDelayProportionOfDuration) // delay後剩餘的時間
121
+ }
122
+
123
+ function renderTriangleBars ({ graphicGSelection, pathGClassName, pathClassName, computedData, linearGradientIds, zeroYArr, groupLabels, barScale, params, chartParams, barWidth, delayGroup, transitionItem, isSeriesPositionSeprate }: RenderBarParams) {
124
+
125
+ const barHalfWidth = barWidth! / 2
126
+
127
+ graphicGSelection
128
+ .each((d, seriesIndex, g) => {
129
+ // g
130
+ const gSelection = d3.select(g[seriesIndex])
131
+ .selectAll<SVGGElement, ComputedDatumGrid>(`g.${pathGClassName}`)
132
+ .data(computedData[seriesIndex] ?? [])
133
+ .join(
134
+ enter => {
135
+ const enterSelection = enter
136
+ .append('g')
137
+ .classed(pathGClassName, true)
138
+ .attr('cursor', 'pointer')
139
+ enterSelection
140
+ .append('path')
141
+ .classed(pathClassName, true)
142
+ .style('vector-effect', 'non-scaling-stroke')
143
+ .attr('d', (d) => {
144
+ const x = -barHalfWidth
145
+ const y1 = zeroYArr[seriesIndex]
146
+ const y2 = zeroYArr[seriesIndex]
147
+ return `M${x},${y1} L${x + (barWidth! / 2)},${y2} ${x + barWidth!},${y1}`
148
+ })
149
+ return enterSelection
150
+ },
151
+ update => update,
152
+ exit => exit.remove()
153
+ )
154
+ .attr('transform', d => `translate(${isSeriesPositionSeprate ? 0 : barScale(d.seriesLabel)!}, 0)`)
155
+
156
+ // path
157
+ gSelection.select(`path.${pathClassName}`)
158
+ .attr('height', d => Math.abs(d.axisYFromZero))
159
+ .attr('y', d => d.axisY < zeroYArr[seriesIndex] ? d.axisY : zeroYArr[seriesIndex])
160
+ .attr('x', d => isSeriesPositionSeprate ? 0 : barScale(d.seriesLabel)!)
161
+ // .style('fill', d => `url(#${d.linearGradientId})`)
162
+ .style('fill', d => `url(#${linearGradientIds[d.seriesIndex]})`)
163
+ .attr('stroke', d => d.color)
164
+ .attr('transform', d => `translate(${(d ? d.axisX : 0)}, ${0})`)
165
+ .transition()
166
+ .duration(transitionItem)
167
+ .ease(getD3TransitionEase(chartParams.transitionEase))
168
+ .delay((d, i) => d.groupIndex * delayGroup)
169
+ // .attr('transform', `translate(${-barHalfWidth}, 0)`)
170
+ // .attr('x', d => itemScale(d.itemLabel)!)
171
+ // .attr('y', d => -d.y)
172
+ .attr('d', (d) => {
173
+ const x = -barHalfWidth
174
+ const y1 = zeroYArr[seriesIndex]
175
+ const y2 = d.axisY
176
+ return `M${x},${y1} L${x + (barWidth! / 2)},${y2} ${x + barWidth!},${y1}`
177
+ })
178
+ })
179
+
180
+ const graphicBarSelection: d3.Selection<SVGPathElement, ComputedDatumGrid, any, any> = graphicGSelection.selectAll(`path.${pathClassName}`)
181
+
182
+ return graphicBarSelection
183
+ }
184
+
185
+ function renderLinearGradient ({ defsSelection, computedData, linearGradientIds, params }: {
186
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
187
+ computedData: ComputedDataGrid
188
+ linearGradientIds: string[]
189
+ params: BaseBarsTriangleParams
190
+ }) {
191
+ defsSelection!
192
+ .selectAll<SVGLinearGradientElement, ComputedDatumGrid>('linearGradient')
193
+ .data(computedData ?? [])
194
+ .join(
195
+ enter => {
196
+ return enter
197
+ .append('linearGradient')
198
+ .attr('x1', '0%')
199
+ .attr('x2', '0%')
200
+ .attr('y1', '100%')
201
+ .attr('y2', '0%')
202
+ .attr('spreadMethod', 'pad')
203
+ },
204
+ update => update,
205
+ exit => exit.remove()
206
+ )
207
+ .attr('id', (d, i) => {
208
+ return d[0] ? linearGradientIds[d[0].seriesIndex] : ''
209
+ })
210
+ .html((d, i) => {
211
+ const color = d[0] ? d[0].color : ''
212
+ return `
213
+ <stop offset="0%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[0]}"/>
214
+ <stop offset="100%" stop-color="${color}" stop-opacity="${params.linearGradientOpacity[1]}"/>
215
+ `
216
+ })
217
+
218
+ }
219
+
220
+
221
+ function renderClipPath ({ defsSelection, clipPathData }: {
222
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
223
+ clipPathData: ClipPathDatum[]
224
+ }) {
225
+ const clipPath = defsSelection
226
+ .selectAll<SVGClipPathElement, Layout>('clipPath')
227
+ .data(clipPathData)
228
+ .join(
229
+ enter => {
230
+ return enter
231
+ .append('clipPath')
232
+ },
233
+ update => update,
234
+ exit => exit.remove()
235
+ )
236
+ .attr('id', d => d.id)
237
+ .each((d, i, g) => {
238
+ const rect = d3.select(g[i])
239
+ .selectAll<SVGRectElement, typeof d>('rect')
240
+ .data([d])
241
+ .join(
242
+ enter => {
243
+ return enter
244
+ .append('rect')
245
+ },
246
+ update => update,
247
+ exit => exit.remove()
248
+ )
249
+ .attr('x', 0)
250
+ .attr('y', 0)
251
+ .attr('width', _d => _d.width)
252
+ .attr('height', _d => _d.height)
253
+ })
254
+ }
255
+
256
+ function highlight ({ selection, ids, fullChartParams }: {
257
+ selection: d3.Selection<SVGPathElement, ComputedDatumGrid, any, any>
258
+ ids: string[]
259
+ fullChartParams: ChartParams
260
+ }) {
261
+ selection.interrupt('highlight')
262
+
263
+ const removeHighlight = () => {
264
+ selection
265
+ .transition('highlight')
266
+ .duration(200)
267
+ .style('opacity', 1)
268
+ }
269
+
270
+ if (!ids.length) {
271
+ removeHighlight()
272
+ return
273
+ }
274
+
275
+ selection
276
+ .each((d, i, n) => {
277
+ if (ids.includes(d.id)) {
278
+ d3.select(n[i])
279
+ .style('opacity', 1)
280
+ } else {
281
+ d3.select(n[i])
282
+ .style('opacity', fullChartParams.styles.unhighlightedOpacity)
283
+ }
284
+ })
285
+ }
286
+
287
+
288
+ export const createBaseBarsTriangle: BasePluginFn<BaseBarsContext> = (pluginName: string, {
289
+ selection,
290
+ computedData$,
291
+ visibleComputedData$,
292
+ existSeriesLabels$,
293
+ SeriesDataMap$,
294
+ GroupDataMap$,
295
+ fullParams$,
296
+ fullChartParams$,
297
+ gridAxesTransform$,
298
+ gridGraphicTransform$,
299
+ gridAxesSize$,
300
+ gridHighlight$,
301
+ gridContainer$,
302
+ isSeriesPositionSeprate$,
303
+ event$
304
+ }) => {
305
+ const destroy$ = new Subject()
306
+
307
+ const clipPathID = getUniID(pluginName, 'clipPath-box')
308
+ const pathGClassName = getClassName(pluginName, 'pathG')
309
+ const pathClassName = getClassName(pluginName, 'path')
310
+
311
+ const {
312
+ seriesSelection$,
313
+ axesSelection$,
314
+ defsSelection$,
315
+ graphicGSelection$
316
+ } = gridSelectionsObservable({
317
+ selection,
318
+ pluginName,
319
+ clipPathID,
320
+ existSeriesLabels$,
321
+ gridContainer$,
322
+ gridAxesTransform$,
323
+ gridGraphicTransform$
324
+ })
325
+
326
+ // valueAxis 的起始座標
327
+ const valueAxisStart$: Observable<number> = gridGraphicTransform$.pipe(
328
+ takeUntil(destroy$),
329
+ map(data => {
330
+ // 抵消掉外層的變型
331
+ return - data.translate[1] / data.scale[1]
332
+ })
333
+ )
334
+
335
+ const zeroYArr$ = visibleComputedData$.pipe(
336
+ // map(d => d[0] && d[0][0]
337
+ // ? d[0][0].axisY - d[0][0].axisYFromZero
338
+ // : 0),
339
+ map(data => {
340
+ return data.map(d => {
341
+ return d[0] ? d[0].axisY - d[0].axisYFromZero : 0
342
+ })
343
+ }),
344
+ distinctUntilChanged()
345
+ )
346
+
347
+ const barWidth$ = combineLatest({
348
+ computedData: computedData$,
349
+ visibleComputedData: visibleComputedData$,
350
+ params: fullParams$,
351
+ gridAxesSize: gridAxesSize$,
352
+ isSeriesPositionSeprate: isSeriesPositionSeprate$
353
+ }).pipe(
354
+ takeUntil(destroy$),
355
+ switchMap(async d => d),
356
+ map(data => {
357
+ if (data.params.barWidth) {
358
+ return data.params.barWidth
359
+ } else if (data.isSeriesPositionSeprate) {
360
+ return calcBarWidth({
361
+ axisWidth: data.gridAxesSize.width,
362
+ groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
363
+ barAmountOfGroup: 1,
364
+ barPadding: data.params.barPadding,
365
+ barGroupPadding: data.params.barGroupPadding
366
+ })
367
+ } else {
368
+ return calcBarWidth({
369
+ axisWidth: data.gridAxesSize.width,
370
+ groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
371
+ barAmountOfGroup: data.visibleComputedData.length,
372
+ barPadding: data.params.barPadding,
373
+ barGroupPadding: data.params.barGroupPadding
374
+ })
375
+ }
376
+ })
377
+ )
378
+
379
+ const seriesLabels$ = visibleComputedData$.pipe(
380
+ takeUntil(destroy$),
381
+ map(data => {
382
+ const SeriesLabelSet: Set<string> = new Set()
383
+ data.forEach(d => {
384
+ d.forEach(_d => {
385
+ SeriesLabelSet.add(_d.seriesLabel)
386
+ })
387
+ })
388
+ return Array.from(SeriesLabelSet)
389
+ })
390
+ )
391
+
392
+ const groupLabels$ = visibleComputedData$.pipe(
393
+ takeUntil(destroy$),
394
+ map(data => {
395
+ const GroupLabelSet: Set<string> = new Set()
396
+ data.forEach(d => {
397
+ d.forEach(_d => {
398
+ GroupLabelSet.add(_d.groupLabel)
399
+ })
400
+ })
401
+ return Array.from(GroupLabelSet)
402
+ })
403
+ )
404
+
405
+ const barScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
406
+ combineLatest({
407
+ seriesLabels: seriesLabels$,
408
+ barWidth: barWidth$,
409
+ params: fullParams$,
410
+ }).pipe(
411
+ takeUntil(destroy$),
412
+ switchMap(async d => d)
413
+ ).subscribe(data => {
414
+ const barScale = makeBarScale(data.barWidth, data.seriesLabels, data.params)
415
+ subscriber.next(barScale)
416
+ })
417
+ })
418
+
419
+ const transitionDuration$ = fullChartParams$.pipe(
420
+ takeUntil(destroy$),
421
+ map(d => d.transitionDuration),
422
+ distinctUntilChanged()
423
+ )
424
+
425
+ const delayGroup$ = new Observable<number>(subscriber => {
426
+ combineLatest({
427
+ groupLabels: groupLabels$,
428
+ transitionDuration: transitionDuration$,
429
+ }).pipe(
430
+ switchMap(async d => d)
431
+ ).subscribe(data => {
432
+ const delay = calcDelayGroup(data.groupLabels.length, data.transitionDuration)
433
+ subscriber.next(delay)
434
+ })
435
+ }).pipe(
436
+ takeUntil(destroy$),
437
+ distinctUntilChanged()
438
+ )
439
+
440
+ const transitionItem$ = new Observable<number>(subscriber => {
441
+ combineLatest({
442
+ groupLabels: groupLabels$,
443
+ transitionDuration: transitionDuration$
444
+ }).pipe(
445
+ switchMap(async d => d)
446
+ ).subscribe(data => {
447
+ const transition = calctransitionItem(data.groupLabels.length, data.transitionDuration)
448
+ subscriber.next(transition)
449
+ })
450
+ }).pipe(
451
+ takeUntil(destroy$),
452
+ distinctUntilChanged()
453
+ )
454
+
455
+ //
456
+
457
+ combineLatest({
458
+ defsSelection: defsSelection$,
459
+ gridAxesSize: gridAxesSize$,
460
+ }).pipe(
461
+ takeUntil(destroy$),
462
+ switchMap(async d => d)
463
+ ).subscribe(data => {
464
+ const clipPathData = [{
465
+ id: clipPathID,
466
+ width: data.gridAxesSize.width,
467
+ height: data.gridAxesSize.height
468
+ }]
469
+ renderClipPath({
470
+ defsSelection: data.defsSelection,
471
+ clipPathData
472
+ })
473
+ })
474
+
475
+
476
+ const highlightTarget$ = fullChartParams$.pipe(
477
+ takeUntil(destroy$),
478
+ map(d => d.highlightTarget),
479
+ distinctUntilChanged()
480
+ )
481
+
482
+ const barSelection$ = new Subject<d3.Selection<SVGPathElement, ComputedDatumGrid, SVGGElement, unknown>>()
483
+
484
+ const linearGradientIds$ = seriesLabels$.pipe(
485
+ takeUntil(destroy$),
486
+ map(d => d.map((d, i) => {
487
+ return getUniID(pluginName, `lineargradient-${d}`)
488
+ }))
489
+ )
490
+
491
+ // const barData$ = combineLatest({
492
+ // linearGradientIds: linearGradientIds$,
493
+ // computedData: computedData$
494
+ // }).pipe(
495
+ // takeUntil(destroy$),
496
+ // switchMap(async d => d),
497
+ // map(data => {
498
+ // return data.computedData.map((series, seriesIndex) => {
499
+ // return series.map((_d, _i) => {
500
+ // return <BarDatumGrid>{
501
+ // linearGradientId: data.linearGradientIds[seriesIndex],
502
+ // ..._d
503
+ // }
504
+ // })
505
+ // })
506
+ // })
507
+ // )
508
+
509
+ combineLatest({
510
+ graphicGSelection: graphicGSelection$,
511
+ defsSelection: defsSelection$,
512
+ computedData: computedData$,
513
+ linearGradientIds: linearGradientIds$,
514
+ zeroYArr: zeroYArr$,
515
+ groupLabels: groupLabels$,
516
+ barScale: barScale$,
517
+ params: fullParams$,
518
+ chartParams: fullChartParams$,
519
+ highlightTarget: highlightTarget$,
520
+ barWidth: barWidth$,
521
+ delayGroup: delayGroup$,
522
+ transitionItem: transitionItem$,
523
+ SeriesDataMap: SeriesDataMap$,
524
+ GroupDataMap: GroupDataMap$,
525
+ isSeriesPositionSeprate: isSeriesPositionSeprate$
526
+ }).pipe(
527
+ takeUntil(destroy$),
528
+ switchMap(async (d) => d),
529
+ ).subscribe(data => {
530
+
531
+ const barSelection = renderTriangleBars({
532
+ graphicGSelection: data.graphicGSelection,
533
+ pathGClassName,
534
+ pathClassName,
535
+ computedData: data.computedData,
536
+ linearGradientIds: data.linearGradientIds,
537
+ zeroYArr: data.zeroYArr,
538
+ groupLabels: data.groupLabels,
539
+ barScale: data.barScale,
540
+ params: data.params,
541
+ chartParams: data.chartParams,
542
+ barWidth: data.barWidth,
543
+ delayGroup: data.delayGroup,
544
+ transitionItem: data.transitionItem,
545
+ isSeriesPositionSeprate: data.isSeriesPositionSeprate
546
+ })
547
+ renderLinearGradient({
548
+ defsSelection: data.defsSelection,
549
+ computedData: data.computedData,
550
+ linearGradientIds: data.linearGradientIds,
551
+ params: data.params
552
+ })
553
+
554
+ barSelection!
555
+ .on('mouseover', (event, datum) => {
556
+ event.stopPropagation()
557
+
558
+ event$.next({
559
+ type: 'grid',
560
+ eventName: 'mouseover',
561
+ pluginName,
562
+ highlightTarget: data.highlightTarget,
563
+ 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
+ .on('mousemove', (event, datum) => {
576
+ event.stopPropagation()
577
+
578
+ event$.next({
579
+ type: 'grid',
580
+ eventName: 'mousemove',
581
+ pluginName,
582
+ highlightTarget: data.highlightTarget,
583
+ datum,
584
+ gridIndex: datum.gridIndex,
585
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
586
+ seriesIndex: datum.seriesIndex,
587
+ seriesLabel: datum.seriesLabel,
588
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
589
+ groupIndex: datum.groupIndex,
590
+ groupLabel: datum.groupLabel,
591
+ event,
592
+ data: data.computedData
593
+ })
594
+ })
595
+ .on('mouseout', (event, datum) => {
596
+ event.stopPropagation()
597
+
598
+ event$.next({
599
+ type: 'grid',
600
+ eventName: 'mouseout',
601
+ pluginName,
602
+ highlightTarget: data.highlightTarget,
603
+ datum,
604
+ gridIndex: datum.gridIndex,
605
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
606
+ seriesIndex: datum.seriesIndex,
607
+ seriesLabel: datum.seriesLabel,
608
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
609
+ groupIndex: datum.groupIndex,
610
+ groupLabel: datum.groupLabel,
611
+ event,
612
+ data: data.computedData
613
+ })
614
+ })
615
+ .on('click', (event, datum) => {
616
+ event.stopPropagation()
617
+
618
+ event$.next({
619
+ type: 'grid',
620
+ eventName: 'click',
621
+ pluginName,
622
+ highlightTarget: data.highlightTarget,
623
+ datum,
624
+ gridIndex: datum.gridIndex,
625
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
626
+ seriesIndex: datum.seriesIndex,
627
+ seriesLabel: datum.seriesLabel,
628
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
629
+ groupIndex: datum.groupIndex,
630
+ groupLabel: datum.groupLabel,
631
+ event,
632
+ data: data.computedData
633
+ })
634
+ })
635
+
636
+ barSelection$.next(barSelection!)
637
+ })
638
+
639
+
640
+ combineLatest({
641
+ barSelection: barSelection$,
642
+ highlight: gridHighlight$.pipe(
643
+ map(data => data.map(d => d.id))
644
+ ),
645
+ fullChartParams: fullChartParams$
646
+ }).pipe(
647
+ takeUntil(destroy$),
648
+ switchMap(async d => d)
649
+ ).subscribe(data => {
650
+ highlight({
651
+ selection: data.barSelection,
652
+ ids: data.highlight,
653
+ fullChartParams: data.fullChartParams
654
+ })
655
+ })
656
+
657
+ return () => {
658
+ destroy$.next(undefined)
659
+ }
660
660
  }