@orbcharts/plugins-basic 3.0.0-alpha.61 → 3.0.0-alpha.63

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