@orbcharts/plugins-basic 3.0.0-alpha.30 → 3.0.0-alpha.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. package/dist/orbcharts-plugins-basic.es.js +15995 -15706
  2. package/dist/orbcharts-plugins-basic.umd.js +8 -8
  3. package/dist/src/base/BaseBarStack.d.ts +29 -0
  4. package/dist/src/base/BaseBars.d.ts +29 -0
  5. package/dist/src/base/BaseBarsTriangle.d.ts +28 -0
  6. package/dist/src/base/BaseLegend.d.ts +17 -6
  7. package/dist/src/base/BaseLines.d.ts +27 -0
  8. package/dist/src/base/types.d.ts +2 -2
  9. package/dist/src/grid/defaults.d.ts +10 -10
  10. package/dist/src/grid/plugins/BarStack.d.ts +1 -3
  11. package/dist/src/grid/plugins/Bars.d.ts +1 -3
  12. package/dist/src/grid/plugins/BarsTriangle.d.ts +1 -3
  13. package/dist/src/grid/plugins/Lines.d.ts +1 -3
  14. package/dist/src/grid/types.d.ts +10 -2
  15. package/dist/src/index.d.ts +1 -0
  16. package/dist/src/multiGrid/defaults.d.ts +4 -0
  17. package/dist/src/multiGrid/index.d.ts +4 -0
  18. package/dist/src/multiGrid/plugins/BarsAndLines.d.ts +1 -0
  19. package/dist/src/multiGrid/plugins/MultiGridLegend.d.ts +1 -0
  20. package/dist/src/multiGrid/types.d.ts +24 -0
  21. package/dist/src/series/defaults.d.ts +2 -2
  22. package/dist/src/series/types.d.ts +10 -2
  23. package/package.json +2 -2
  24. package/src/base/BaseBarStack.ts +699 -0
  25. package/src/base/BaseBars.ts +639 -0
  26. package/src/base/BaseBarsTriangle.ts +626 -0
  27. package/src/base/BaseLegend.ts +50 -20
  28. package/src/base/BaseLines.ts +566 -0
  29. package/src/base/types.ts +2 -2
  30. package/src/grid/defaults.ts +10 -10
  31. package/src/grid/plugins/BarStack.ts +18 -645
  32. package/src/grid/plugins/Bars.ts +17 -588
  33. package/src/grid/plugins/BarsTriangle.ts +16 -579
  34. package/src/grid/plugins/Dots.ts +2 -2
  35. package/src/grid/plugins/GridLegend.ts +19 -1
  36. package/src/grid/plugins/GroupArea.ts +2 -2
  37. package/src/grid/plugins/GroupAxis.ts +2 -2
  38. package/src/grid/plugins/Lines.ts +15 -509
  39. package/src/grid/plugins/ScalingArea.ts +2 -2
  40. package/src/grid/plugins/ValueAxis.ts +2 -2
  41. package/src/grid/plugins/ValueStackAxis.ts +2 -2
  42. package/src/grid/types.ts +12 -2
  43. package/src/index.ts +1 -0
  44. package/src/multiGrid/defaults.ts +33 -0
  45. package/src/multiGrid/index.ts +4 -0
  46. package/src/multiGrid/plugins/BarsAndLines.ts +110 -0
  47. package/src/multiGrid/plugins/BarsTriangleAndLines.ts +0 -0
  48. package/src/multiGrid/plugins/DivergingValueAxes.ts +0 -0
  49. package/src/multiGrid/plugins/FirstGroupScaleAxis.ts +0 -0
  50. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -0
  51. package/src/multiGrid/plugins/TwoValueScaleAxes.ts +0 -0
  52. package/src/multiGrid/types.ts +27 -0
  53. package/src/series/defaults.ts +2 -2
  54. package/src/series/plugins/Bubbles.ts +2 -2
  55. package/src/series/plugins/Pie.ts +2 -2
  56. package/src/series/plugins/SeriesLegend.ts +19 -1
  57. package/src/series/types.ts +12 -2
  58. /package/dist/src/multiGrid/plugins/{DivergingAxes.d.ts → BarStackAndLines.d.ts} +0 -0
  59. /package/dist/src/multiGrid/plugins/{TwoScaleAxes.d.ts → BarsTriangleAndLines.d.ts} +0 -0
  60. /package/dist/src/multiGrid/plugins/{TwoScales.d.ts → DivergingValueAxes.d.ts} +0 -0
  61. /package/{src/multiGrid/plugins/DivergingAxes.ts → dist/src/multiGrid/plugins/FirstGroupScaleAxis.d.ts} +0 -0
  62. /package/{src/multiGrid/plugins/TwoScaleAxes.ts → dist/src/multiGrid/plugins/TwoValueScaleAxes.d.ts} +0 -0
  63. /package/src/multiGrid/plugins/{TwoScales.ts → BarStackAndLines.ts} +0 -0
@@ -0,0 +1,699 @@
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
+ DataFormatterGrid,
15
+ EventGrid,
16
+ ChartParams,
17
+ Layout,
18
+ TransformData } from '@orbcharts/core'
19
+ import { getD3TransitionEase } from '../utils/d3Utils'
20
+ import { getClassName, getUniID } from '../utils/orbchartsUtils'
21
+
22
+ export interface BaseBarStackParams {
23
+ barWidth: number
24
+ barGroupPadding: number
25
+ barRadius: number | boolean
26
+ }
27
+
28
+ interface BaseBarStackContext {
29
+ selection: d3.Selection<any, unknown, any, unknown>
30
+ computedData$: Observable<ComputedDataGrid>
31
+ visibleComputedData$: Observable<ComputedDatumGrid[][]>
32
+ SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
33
+ GroupDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
34
+ fullParams$: Observable<BaseBarStackParams>
35
+ fullDataFormatter$: Observable<DataFormatterGrid>
36
+ fullChartParams$: Observable<ChartParams>
37
+ gridAxesTransform$: Observable<TransformData>
38
+ gridGraphicTransform$: Observable<TransformData>
39
+ gridAxesSize$: Observable<{
40
+ width: number;
41
+ height: number;
42
+ }>
43
+ gridHighlight$: Observable<string[]>
44
+ event$: Subject<EventGrid>
45
+ }
46
+
47
+
48
+ interface GraphicDatum extends ComputedDatumGrid {
49
+ _barStartY: number // bar的起點y座標
50
+ _barHeight: number // bar的高度
51
+ }
52
+
53
+ interface RenderBarParams {
54
+ selection: d3.Selection<SVGGElement, unknown, any, any>
55
+ data: GraphicDatum[][]
56
+ zeroY: number
57
+ groupLabels: string[]
58
+ // barScale: d3.ScalePoint<string>
59
+ params: BaseBarStackParams
60
+ chartParams: ChartParams
61
+ barWidth: number
62
+ transformedBarRadius: [number, number]
63
+ delayGroup: number
64
+ transitionItem: number
65
+ }
66
+
67
+ type ClipPathDatum = {
68
+ id: string;
69
+ // x: number;
70
+ // y: number;
71
+ width: number;
72
+ height: number;
73
+ }
74
+
75
+ const pluginName = 'BarStack'
76
+ const gClassName = getClassName(pluginName, 'g')
77
+ const gContentClassName = getClassName(pluginName, 'g-content')
78
+ // group的delay在動畫中的佔比(剩餘部份的時間為圖形本身的動畫時間,因為delay時間和最後一個group的動畫時間加總為1)
79
+ const groupDelayProportionOfDuration = 0.3
80
+
81
+ function calcBarWidth ({ axisWidth, groupAmount, barGroupPadding = 0 }: {
82
+ axisWidth: number
83
+ groupAmount: number
84
+ barGroupPadding: number
85
+ }) {
86
+ const eachGroupWidth = axisWidth / (groupAmount - 1)
87
+ const width = eachGroupWidth - barGroupPadding
88
+ return width > 1 ? width : 1
89
+
90
+ }
91
+
92
+ // function makeBarScale (barWidth: number, seriesLabels: string[], params: BarStackParams) {
93
+ // const barHalfWidth = barWidth! / 2
94
+ // const barGroupWidth = barWidth * seriesLabels.length + params.barPadding! * seriesLabels.length
95
+ // return d3.scalePoint()
96
+ // .domain(seriesLabels)
97
+ // .range([-barGroupWidth / 2 + barHalfWidth, barGroupWidth / 2 - barHalfWidth])
98
+ // }
99
+
100
+ function calcDelayGroup (barGroupAmount: number, totalDuration: number) {
101
+ if (barGroupAmount <= 1) {
102
+ // 一筆內計算會出錯所以不算
103
+ return 0
104
+ }
105
+ return totalDuration / (barGroupAmount - 1) * groupDelayProportionOfDuration // 依group數量計算
106
+ }
107
+
108
+ function calctransitionItem (barGroupAmount: number, totalDuration: number) {
109
+ if (barGroupAmount <= 1) {
110
+ // 一筆內不會有delay
111
+ return totalDuration
112
+ }
113
+ return totalDuration * (1 - groupDelayProportionOfDuration) // delay後剩餘的時間
114
+ }
115
+
116
+ function renderRectBars ({ selection, data, zeroY, groupLabels, params, chartParams, barWidth, transformedBarRadius, delayGroup, transitionItem }: RenderBarParams) {
117
+
118
+ const barHalfWidth = barWidth! / 2
119
+
120
+ const barGroup = selection
121
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${gClassName}`)
122
+ .data(data, (d, i) => groupLabels[i])
123
+ .join(
124
+ enter => {
125
+ return enter
126
+ .append('g')
127
+ .classed(gClassName, true)
128
+ .attr('cursor', 'pointer')
129
+ },
130
+ update => update,
131
+ exit => exit.remove()
132
+ )
133
+ .attr('transform', (d, i) => `translate(${d[0] ? d[0].axisX : 0}, ${0})`)
134
+ .each((d, i, g) => {
135
+ const bars = d3.select(g[i])
136
+ .selectAll<SVGGElement, ComputedDatumGrid>('g')
137
+ .data(d, _d => _d.id)
138
+ .join(
139
+ enter => {
140
+ return enter
141
+ .append('g')
142
+ .classed(gContentClassName, true)
143
+ },
144
+ update => update,
145
+ exit => exit.remove()
146
+ )
147
+ .each((_d, _i, _g) => {
148
+ const rect = d3.select(_g[_i])
149
+ .selectAll<SVGRectElement, ComputedDatumGrid>('rect')
150
+ .data([_d], _d => _d.id)
151
+ .join(
152
+ enter => {
153
+ return enter
154
+ .append('rect')
155
+ .attr('y', d => zeroY)
156
+ .attr('height', d => 0)
157
+ },
158
+ update => update,
159
+ exit => exit.remove()
160
+ )
161
+ .attr('rx', transformedBarRadius[0])
162
+ .attr('ry', transformedBarRadius[1])
163
+ .attr('fill', d => d.color)
164
+ .attr('transform', `translate(${-barHalfWidth}, 0)`)
165
+ .attr('x', d => 0)
166
+ .attr('width', barWidth!)
167
+ .transition()
168
+ .duration(transitionItem)
169
+ .ease(getD3TransitionEase(chartParams.transitionEase))
170
+ .delay((d, i) => d.groupIndex * delayGroup)
171
+ .attr('y', d => d._barStartY)
172
+ .attr('height', d => Math.abs(d._barHeight))
173
+ })
174
+
175
+ })
176
+
177
+ const graphicBarSelection: d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown> = barGroup.selectAll(`g.${gContentClassName}`)
178
+
179
+
180
+ return graphicBarSelection
181
+ }
182
+
183
+ function renderClipPath ({ defsSelection, clipPathData }: {
184
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
185
+ clipPathData: ClipPathDatum[]
186
+ }) {
187
+ const clipPath = defsSelection
188
+ .selectAll<SVGClipPathElement, Layout>('clipPath')
189
+ .data(clipPathData)
190
+ .join(
191
+ enter => {
192
+ return enter
193
+ .append('clipPath')
194
+ },
195
+ update => update,
196
+ exit => exit.remove()
197
+ )
198
+ .attr('id', d => d.id)
199
+ .each((d, i, g) => {
200
+ const rect = d3.select(g[i])
201
+ .selectAll<SVGRectElement, typeof d>('rect')
202
+ .data([d])
203
+ .join(
204
+ enter => {
205
+ return enter
206
+ .append('rect')
207
+ },
208
+ update => update,
209
+ exit => exit.remove()
210
+ )
211
+ .attr('x', 0)
212
+ .attr('y', 0)
213
+ .attr('width', _d => _d.width)
214
+ .attr('height', _d => _d.height)
215
+ })
216
+ }
217
+
218
+ function highlight ({ selection, ids, fullChartParams }: {
219
+ selection: d3.Selection<any, ComputedDatumGrid, any, any>
220
+ ids: string[]
221
+ fullChartParams: ChartParams
222
+ }) {
223
+ selection.interrupt('highlight')
224
+
225
+ if (!ids.length) {
226
+ // remove highlight
227
+ selection
228
+ .transition('highlight')
229
+ .duration(200)
230
+ .style('opacity', 1)
231
+ return
232
+ }
233
+
234
+ selection
235
+ .each((d, i, n) => {
236
+ if (ids.includes(d.id)) {
237
+ d3.select(n[i])
238
+ .style('opacity', 1)
239
+ } else {
240
+ d3.select(n[i])
241
+ .style('opacity', fullChartParams.styles.unhighlightedOpacity)
242
+ }
243
+ })
244
+ }
245
+
246
+
247
+ export const createBaseBarStack: BasePluginFn<BaseBarStackContext> = (pluginName: string, {
248
+ selection,
249
+ computedData$,
250
+ visibleComputedData$,
251
+ SeriesDataMap$,
252
+ GroupDataMap$,
253
+ fullParams$,
254
+ fullDataFormatter$,
255
+ fullChartParams$,
256
+ gridAxesTransform$,
257
+ gridGraphicTransform$,
258
+ gridAxesSize$,
259
+ gridHighlight$,
260
+ event$
261
+ }) => {
262
+
263
+ const destroy$ = new Subject()
264
+
265
+ const clipPathID = getUniID(pluginName, 'clipPath-box')
266
+
267
+ const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
268
+ .append('g')
269
+ .attr('clip-path', `url(#${clipPathID})`)
270
+ const defsSelection: d3.Selection<SVGDefsElement, ComputedDatumGrid, any, any> = axisSelection.append('defs')
271
+ const graphicGSelection: d3.Selection<SVGGElement, any, any, any> = axisSelection.append('g')
272
+ const barSelection$: Subject<d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown>> = new Subject()
273
+
274
+ gridAxesTransform$
275
+ .pipe(
276
+ takeUntil(destroy$),
277
+ map(d => d.value),
278
+ distinctUntilChanged()
279
+ ).subscribe(d => {
280
+ axisSelection
281
+ .style('transform', d)
282
+ })
283
+
284
+ gridGraphicTransform$
285
+ .pipe(
286
+ takeUntil(destroy$),
287
+ switchMap(async d => d.value),
288
+ distinctUntilChanged()
289
+ ).subscribe(d => {
290
+ graphicGSelection
291
+ .transition()
292
+ .duration(50)
293
+ .style('transform', d)
294
+ })
295
+
296
+ // const axisSize$ = gridAxisSizeObservable({
297
+ // dataFormatter$,
298
+ // layout$
299
+ // })
300
+
301
+ // const visibleComputedData$ = computedData$.pipe(
302
+ // takeUntil(destroy$),
303
+ // map(data => {
304
+ // const visibleComputedData = data
305
+ // .map(d => {
306
+ // return d.filter(_d => {
307
+ // return _d.visible == true
308
+ // })
309
+ // })
310
+ // .filter(d => d.length)
311
+ // // console.log('visibleComputedData', visibleComputedData)
312
+ // return visibleComputedData
313
+ // })
314
+ // )
315
+
316
+ const zeroY$ = visibleComputedData$.pipe(
317
+ map(d => d[0] && d[0][0]
318
+ ? d[0][0].axisY - d[0][0].axisYFromZero
319
+ : 0),
320
+ distinctUntilChanged()
321
+ )
322
+
323
+ const barWidth$ = new Observable<number>(subscriber => {
324
+ combineLatest({
325
+ computedData: computedData$,
326
+ // visibleComputedData: visibleComputedData$,
327
+ params: fullParams$,
328
+ axisSize: gridAxesSize$
329
+ }).pipe(
330
+ switchMap(async d => d)
331
+ ).subscribe(data => {
332
+ const barWidth = data.params.barWidth
333
+ ? data.params.barWidth
334
+ : calcBarWidth({
335
+ axisWidth: data.axisSize.width,
336
+ groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
337
+ barGroupPadding: data.params.barGroupPadding
338
+ })
339
+ subscriber.next(barWidth)
340
+ })
341
+ }).pipe(
342
+ takeUntil(destroy$),
343
+ distinctUntilChanged()
344
+ )
345
+
346
+ // 圓角的值 [rx, ry]
347
+ const transformedBarRadius$: Observable<[number, number]> = combineLatest({
348
+ gridGraphicTransform: gridGraphicTransform$,
349
+ barWidth: barWidth$,
350
+ params: fullParams$
351
+ }).pipe(
352
+ takeUntil(destroy$),
353
+ switchMap(async data => data),
354
+ map(data => {
355
+ const barHalfWidth = data.barWidth! / 2
356
+ const radius = data.params.barRadius === true ? barHalfWidth
357
+ : data.params.barRadius === false ? 0
358
+ : typeof data.params.barRadius == 'number' ? data.params.barRadius
359
+ : 0
360
+ const transformedRx = radius == 0
361
+ ? 0
362
+ : radius / data.gridGraphicTransform.scale[0] // 反向外層scale的變型
363
+ const transformedRy = radius == 0
364
+ ? 0
365
+ : radius / data.gridGraphicTransform.scale[1]
366
+ return [transformedRx, transformedRy]
367
+ })
368
+ )
369
+
370
+ // const seriesLabels$ = visibleComputedData$.pipe(
371
+ // takeUntil(destroy$),
372
+ // map(data => {
373
+ // const SeriesLabelSet: Set<string> = new Set()
374
+ // data.forEach(d => {
375
+ // d.forEach(_d => {
376
+ // SeriesLabelSet.add(_d.seriesLabel)
377
+ // })
378
+ // })
379
+ // return Array.from(SeriesLabelSet)
380
+ // })
381
+ // )
382
+
383
+ const groupLabels$ = visibleComputedData$.pipe(
384
+ takeUntil(destroy$),
385
+ map(data => {
386
+ const GroupLabelSet: Set<string> = new Set()
387
+ data.forEach(d => {
388
+ d.forEach(_d => {
389
+ GroupLabelSet.add(_d.groupLabel)
390
+ })
391
+ })
392
+ return Array.from(GroupLabelSet)
393
+ })
394
+ )
395
+
396
+ // const barScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
397
+ // combineLatest({
398
+ // seriesLabels: seriesLabels$,
399
+ // barWidth: barWidth$,
400
+ // params: fullParams$,
401
+ // }).pipe(
402
+ // takeUntil(destroy$),
403
+ // switchMap(async d => d)
404
+ // ).subscribe(data => {
405
+ // const barScale = makeBarScale(data.barWidth, data.seriesLabels, data.params)
406
+ // subscriber.next(barScale)
407
+ // })
408
+ // })
409
+
410
+ const transitionDuration$ = fullChartParams$.pipe(
411
+ takeUntil(destroy$),
412
+ map(d => d.transitionDuration),
413
+ distinctUntilChanged()
414
+ )
415
+
416
+ const delayGroup$ = new Observable<number>(subscriber => {
417
+ combineLatest({
418
+ groupLabels: groupLabels$,
419
+ transitionDuration: transitionDuration$,
420
+ }).pipe(
421
+ switchMap(async d => d)
422
+ ).subscribe(data => {
423
+ const delay = calcDelayGroup(data.groupLabels.length, data.transitionDuration)
424
+ subscriber.next(delay)
425
+ })
426
+ }).pipe(
427
+ takeUntil(destroy$),
428
+ distinctUntilChanged()
429
+ )
430
+
431
+ const transitionItem$ = new Observable<number>(subscriber => {
432
+ combineLatest({
433
+ groupLabels: groupLabels$,
434
+ transitionDuration: transitionDuration$
435
+ }).pipe(
436
+ switchMap(async d => d)
437
+ ).subscribe(data => {
438
+ const transition = calctransitionItem(data.groupLabels.length, data.transitionDuration)
439
+ subscriber.next(transition)
440
+ })
441
+ }).pipe(
442
+ takeUntil(destroy$),
443
+ distinctUntilChanged()
444
+ )
445
+
446
+ const transposedVisibleData$: Observable<ComputedDataGrid> = visibleComputedData$.pipe(
447
+ takeUntil(destroy$),
448
+ map(data => {
449
+ console.log('visibleComputedData', data)
450
+ // 取得原始陣列的維度
451
+ const rows = data.length;
452
+ const cols = data.reduce((prev, current) => {
453
+ return Math.max(prev, current.length)
454
+ }, 0)
455
+
456
+ // 初始化轉換後的陣列
457
+ const transposedArray = new Array(cols).fill(null).map(() => new Array(rows).fill(null))
458
+
459
+ // 遍歷原始陣列,進行轉換
460
+ for (let i = 0; i < rows; i++) {
461
+ for (let j = 0; j < cols; j++) {
462
+ transposedArray[j][i] = data[i][j]
463
+ }
464
+ }
465
+ return transposedArray
466
+ })
467
+ )
468
+
469
+ const yRatio$ = combineLatest({
470
+ transposedVisibleData: transposedVisibleData$,
471
+ dataFormatter: fullDataFormatter$,
472
+ }).pipe(
473
+ takeUntil(destroy$),
474
+ switchMap(async d => d),
475
+ map(data => {
476
+ const groupMin = 0
477
+ const groupMax = data.transposedVisibleData.length - 1
478
+ const groupScaleDomainMin = data.dataFormatter.groupAxis.scaleDomain[0] === 'auto'
479
+ ? groupMin - data.dataFormatter.groupAxis.scalePadding
480
+ : data.dataFormatter.groupAxis.scaleDomain[0] as number - data.dataFormatter.groupAxis.scalePadding
481
+ const groupScaleDomainMax = data.dataFormatter.groupAxis.scaleDomain[1] === 'auto'
482
+ ? groupMax + data.dataFormatter.groupAxis.scalePadding
483
+ : data.dataFormatter.groupAxis.scaleDomain[1] as number + data.dataFormatter.groupAxis.scalePadding
484
+
485
+ const filteredData = data.transposedVisibleData
486
+ .map(d => {
487
+ return d.filter((_d, i) => {
488
+ return _d.groupIndex >= groupScaleDomainMin && _d.groupIndex <= groupScaleDomainMax
489
+ })
490
+ })
491
+ // console.log('filteredData', filteredData)
492
+
493
+ if (!filteredData.flat().length) {
494
+ return 1
495
+ } else {
496
+ const yArr = filteredData.flat().map(d => d.axisYFromZero)
497
+ const barMaxY = Math.max(...yArr)
498
+ const stackYArr = filteredData.map(d => d.reduce((prev, current) => prev + current.axisYFromZero, 0))
499
+ const barStackMaxY = Math.max(...stackYArr)
500
+
501
+ return barMaxY / barStackMaxY
502
+ }
503
+ })
504
+ )
505
+
506
+ const graphicData$ = combineLatest({
507
+ transposedVisibleData: transposedVisibleData$,
508
+ yRatio: yRatio$,
509
+ zeroY: zeroY$
510
+ }).pipe(
511
+ takeUntil(destroy$),
512
+ map(data => {
513
+ console.log(data.transposedVisibleData)
514
+ return data.transposedVisibleData.map(d => {
515
+ let accY = data.zeroY
516
+ return d.map(_d => {
517
+ const _barStartY = accY
518
+ const _barHeight = _d.axisYFromZero * data.yRatio
519
+ accY = accY + _barHeight
520
+ return <GraphicDatum>{
521
+ ..._d,
522
+ _barStartY,
523
+ _barHeight
524
+ }
525
+ })
526
+ })
527
+ })
528
+ )
529
+
530
+ gridAxesSize$.pipe(
531
+ takeUntil(destroy$)
532
+ ).subscribe(data => {
533
+ const clipPathData = [{
534
+ id: clipPathID,
535
+ width: data.width,
536
+ height: data.height
537
+ }]
538
+ renderClipPath({
539
+ defsSelection,
540
+ clipPathData
541
+ })
542
+ })
543
+
544
+ // const SeriesDataMap$ = visibleComputedData$.pipe(
545
+ // map(d => makeGridSeriesDataMap(d))
546
+ // )
547
+
548
+ // const GroupDataMap$ = visibleComputedData$.pipe(
549
+ // map(d => makeGridGroupDataMap(d))
550
+ // )
551
+
552
+ const highlightTarget$ = fullChartParams$.pipe(
553
+ takeUntil(destroy$),
554
+ map(d => d.highlightTarget),
555
+ distinctUntilChanged()
556
+ )
557
+
558
+ combineLatest({
559
+ // renderBarsFn: renderBarsFn$,
560
+ graphicData: graphicData$,
561
+ zeroY: zeroY$,
562
+ groupLabels: groupLabels$,
563
+ // barScale: barScale$,
564
+ params: fullParams$,
565
+ chartParams: fullChartParams$,
566
+ highlightTarget: highlightTarget$,
567
+ barWidth: barWidth$,
568
+ transformedBarRadius: transformedBarRadius$,
569
+ delayGroup: delayGroup$,
570
+ transitionItem: transitionItem$,
571
+ SeriesDataMap: SeriesDataMap$,
572
+ GroupDataMap: GroupDataMap$
573
+ }).pipe(
574
+ takeUntil(destroy$),
575
+ // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
576
+ switchMap(async (d) => d),
577
+ ).subscribe(data => {
578
+ const barSelection = renderRectBars({
579
+ selection: graphicGSelection,
580
+ data: data.graphicData,
581
+ zeroY: data.zeroY,
582
+ groupLabels: data.groupLabels,
583
+ // barScale: data.barScale,
584
+ params: data.params,
585
+ chartParams: data.chartParams,
586
+ barWidth: data.barWidth,
587
+ transformedBarRadius: data.transformedBarRadius,
588
+ delayGroup: data.delayGroup,
589
+ transitionItem: data.transitionItem
590
+ })
591
+
592
+ barSelection!
593
+ .on('mouseover', (event, datum) => {
594
+ event.stopPropagation()
595
+
596
+ event$.next({
597
+ type: 'grid',
598
+ eventName: 'mouseover',
599
+ pluginName,
600
+ highlightTarget: data.highlightTarget,
601
+ datum,
602
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
603
+ seriesIndex: datum.seriesIndex,
604
+ seriesLabel: datum.seriesLabel,
605
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
606
+ groupIndex: datum.groupIndex,
607
+ groupLabel: datum.groupLabel,
608
+ event,
609
+ data: data.graphicData
610
+ })
611
+ })
612
+ .on('mousemove', (event, datum) => {
613
+ event.stopPropagation()
614
+
615
+ event$.next({
616
+ type: 'grid',
617
+ eventName: 'mousemove',
618
+ pluginName,
619
+ highlightTarget: data.highlightTarget,
620
+ datum,
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.graphicData
629
+ })
630
+ })
631
+ .on('mouseout', (event, datum) => {
632
+ event.stopPropagation()
633
+
634
+ event$.next({
635
+ type: 'grid',
636
+ eventName: 'mouseout',
637
+ pluginName,
638
+ highlightTarget: data.highlightTarget,
639
+ datum,
640
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
641
+ seriesIndex: datum.seriesIndex,
642
+ seriesLabel: datum.seriesLabel,
643
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
644
+ groupIndex: datum.groupIndex,
645
+ groupLabel: datum.groupLabel,
646
+ event,
647
+ data: data.graphicData
648
+ })
649
+ })
650
+ .on('click', (event, datum) => {
651
+ event.stopPropagation()
652
+
653
+ event$.next({
654
+ type: 'grid',
655
+ eventName: 'click',
656
+ pluginName,
657
+ highlightTarget: data.highlightTarget,
658
+ datum,
659
+ series: data.SeriesDataMap.get(datum.seriesLabel)!,
660
+ seriesIndex: datum.seriesIndex,
661
+ seriesLabel: datum.seriesLabel,
662
+ groups: data.GroupDataMap.get(datum.groupLabel)!,
663
+ groupIndex: datum.groupIndex,
664
+ groupLabel: datum.groupLabel,
665
+ event,
666
+ data: data.graphicData
667
+ })
668
+ })
669
+
670
+ barSelection$.next(barSelection!)
671
+ })
672
+
673
+ // const datumList$ = computedData$.pipe(
674
+ // takeUntil(destroy$),
675
+ // map(d => d.flat())
676
+ // )
677
+ // const highlight$ = highlightObservable({ datumList$, chartParams$, event$: store.event$ })
678
+ const highlightSubscription = gridHighlight$.subscribe()
679
+
680
+ combineLatest({
681
+ barSelection: barSelection$,
682
+ highlight: gridHighlight$,
683
+ fullChartParams: fullChartParams$
684
+ }).pipe(
685
+ takeUntil(destroy$),
686
+ switchMap(async d => d)
687
+ ).subscribe(data => {
688
+ highlight({
689
+ selection: data.barSelection,
690
+ ids: data.highlight,
691
+ fullChartParams: data.fullChartParams
692
+ })
693
+ })
694
+
695
+ return () => {
696
+ destroy$.next(undefined)
697
+ highlightSubscription.unsubscribe()
698
+ }
699
+ }