@orbcharts/plugins-basic 3.0.0-alpha.55 → 3.0.0-alpha.57

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +7072 -7073
  3. package/dist/orbcharts-plugins-basic.umd.js +10 -10
  4. package/dist/src/base/BaseLineAreas.d.ts +1 -0
  5. package/dist/src/base/BaseLines.d.ts +3 -1
  6. package/dist/src/grid/gridObservables.d.ts +19 -2
  7. package/dist/src/grid/types.d.ts +1 -0
  8. package/dist/vite.config.d.mts +2 -0
  9. package/package.json +43 -42
  10. package/src/base/BaseBarStack.ts +778 -778
  11. package/src/base/BaseBars.ts +764 -764
  12. package/src/base/BaseBarsTriangle.ts +672 -672
  13. package/src/base/BaseDots.ts +513 -513
  14. package/src/base/BaseGroupAxis.ts +558 -558
  15. package/src/base/BaseLegend.ts +641 -641
  16. package/src/base/BaseLineAreas.ts +628 -625
  17. package/src/base/BaseLines.ts +704 -699
  18. package/src/base/BaseValueAxis.ts +478 -478
  19. package/src/base/types.ts +2 -2
  20. package/src/grid/defaults.ts +128 -127
  21. package/src/grid/gridObservables.ts +539 -248
  22. package/src/grid/index.ts +15 -15
  23. package/src/grid/plugins/BarStack.ts +43 -43
  24. package/src/grid/plugins/Bars.ts +44 -44
  25. package/src/grid/plugins/BarsPN.ts +41 -41
  26. package/src/grid/plugins/BarsTriangle.ts +42 -42
  27. package/src/grid/plugins/Dots.ts +37 -37
  28. package/src/grid/plugins/GridLegend.ts +59 -59
  29. package/src/grid/plugins/GroupAux.ts +976 -922
  30. package/src/grid/plugins/GroupAxis.ts +35 -35
  31. package/src/grid/plugins/LineAreas.ts +40 -39
  32. package/src/grid/plugins/Lines.ts +40 -38
  33. package/src/grid/plugins/ScalingArea.ts +173 -173
  34. package/src/grid/plugins/ValueAxis.ts +36 -36
  35. package/src/grid/plugins/ValueStackAxis.ts +38 -38
  36. package/src/grid/types.ts +123 -122
  37. package/src/index.ts +9 -9
  38. package/src/multiGrid/defaults.ts +158 -158
  39. package/src/multiGrid/index.ts +13 -13
  40. package/src/multiGrid/multiGridObservables.ts +49 -49
  41. package/src/multiGrid/plugins/MultiBarStack.ts +78 -78
  42. package/src/multiGrid/plugins/MultiBars.ts +77 -77
  43. package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -77
  44. package/src/multiGrid/plugins/MultiDots.ts +65 -65
  45. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
  46. package/src/multiGrid/plugins/MultiGroupAxis.ts +69 -69
  47. package/src/multiGrid/plugins/MultiLineAreas.ts +77 -67
  48. package/src/multiGrid/plugins/MultiLines.ts +77 -66
  49. package/src/multiGrid/plugins/MultiValueAxis.ts +69 -69
  50. package/src/multiGrid/plugins/MultiValueStackAxis.ts +69 -69
  51. package/src/multiGrid/plugins/OverlappingValueAxes.ts +167 -166
  52. package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +168 -167
  53. package/src/multiGrid/types.ts +72 -72
  54. package/src/noneData/defaults.ts +102 -102
  55. package/src/noneData/index.ts +3 -3
  56. package/src/noneData/plugins/Container.ts +10 -10
  57. package/src/noneData/plugins/Tooltip.ts +310 -310
  58. package/src/noneData/types.ts +26 -26
  59. package/src/series/defaults.ts +144 -144
  60. package/src/series/index.ts +9 -9
  61. package/src/series/plugins/Bubbles.ts +545 -545
  62. package/src/series/plugins/Pie.ts +576 -576
  63. package/src/series/plugins/PieEventTexts.ts +262 -262
  64. package/src/series/plugins/PieLabels.ts +304 -304
  65. package/src/series/plugins/Rose.ts +472 -472
  66. package/src/series/plugins/RoseLabels.ts +362 -362
  67. package/src/series/plugins/SeriesLegend.ts +59 -59
  68. package/src/series/seriesObservables.ts +145 -145
  69. package/src/series/seriesUtils.ts +51 -51
  70. package/src/series/types.ts +83 -83
  71. package/src/tree/defaults.ts +23 -23
  72. package/src/tree/index.ts +3 -3
  73. package/src/tree/plugins/TreeLegend.ts +59 -59
  74. package/src/tree/plugins/TreeMap.ts +305 -305
  75. package/src/tree/types.ts +23 -23
  76. package/src/utils/commonUtils.ts +21 -21
  77. package/src/utils/d3Graphics.ts +124 -124
  78. package/src/utils/d3Utils.ts +73 -73
  79. package/src/utils/observables.ts +14 -14
  80. package/src/utils/orbchartsUtils.ts +100 -100
  81. package/{tsconfig.json → tsconfig.base.json} +13 -13
  82. package/tsconfig.json.bak.vite-plugin-tsconfig +8 -0
  83. package/tsconfig.prod.json +2 -13
  84. package/vite.config.mjs +41 -0
  85. package/dist/vite.config.d.ts +0 -2
  86. package/tsconfig.dev.json +0 -17
  87. package/vite.config.js +0 -50
@@ -1,923 +1,977 @@
1
- import * as d3 from 'd3'
2
- import {
3
- // of,
4
- iif,
5
- EMPTY,
6
- combineLatest,
7
- switchMap,
8
- map,
9
- filter,
10
- first,
11
- takeUntil,
12
- distinctUntilChanged,
13
- shareReplay,
14
- Subject,
15
- Observable } from 'rxjs'
16
- import {
17
- defineGridPlugin } from '@orbcharts/core'
18
- import type {
19
- TransformData,
20
- DataFormatterGrid,
21
- ChartParams } from '@orbcharts/core'
22
- import { DEFAULT_GROUP_AREA_PARAMS } from '../defaults'
23
- import { parseTickFormatValue } from '../../utils/d3Utils'
24
- import { measureTextWidth } from '../../utils/commonUtils'
25
- import { getColor, getClassName, getUniID } from '../../utils/orbchartsUtils'
26
- import { d3EventObservable } from '../../utils/observables'
27
- import { gridGroupPositionFnObservable } from '../gridObservables'
28
- import { createAxisPointScale } from '@orbcharts/core'
29
- import type { GroupAuxParams } from '../types'
30
- import { gridSelectionsObservable } from '../gridObservables'
31
-
32
- interface LineDatum {
33
- id: string
34
- x1: number
35
- x2: number
36
- y1: number
37
- y2: number
38
- }
39
-
40
- interface LabelDatum {
41
- id: string
42
- text: string
43
- x: number
44
- y: number
45
- }
46
-
47
- const pluginName = 'GroupAux'
48
- const labelClassName = getClassName(pluginName, 'label-box')
49
-
50
- function createLineData ({ groupLabel, axisX, axisHeight, fullParams }: {
51
- groupLabel: string
52
- axisX: number
53
- axisHeight: number
54
- fullParams: GroupAuxParams
55
- }): LineDatum[] {
56
- return fullParams.showLine && groupLabel
57
- ? [{
58
- id: groupLabel,
59
- x1: axisX,
60
- x2: axisX,
61
- y1: 0,
62
- y2: axisHeight
63
- }]
64
- : []
65
- }
66
-
67
- function renderLine ({ selection, pluginName, lineData, fullParams, fullChartParams }: {
68
- selection: d3.Selection<any, unknown, any, unknown>
69
- pluginName: string
70
- lineData: LineDatum[]
71
- fullParams: GroupAuxParams
72
- fullChartParams: ChartParams
73
- }) {
74
- const gClassName = getClassName(pluginName, 'auxline')
75
- const update = selection
76
- .selectAll<SVGLineElement, LineDatum>(`line.${gClassName}`)
77
- .data(lineData)
78
- const enter = update
79
- .enter()
80
- .append('line')
81
- .classed(gClassName, true)
82
- // .style('stroke', '#E4E7ED')
83
- .style('stroke', d => getColor(fullParams.lineColorType, fullChartParams))
84
- .style('stroke-width', 1)
85
- .style('stroke-dasharray', fullParams.lineDashArray ?? 'none')
86
- .style('pointer-events', 'none')
87
- // .attr('opacity', 0)
88
- const auxLineSelection = update.merge(enter)
89
- // .attr('opacity', (d) => {
90
- // return d.active == true ? 1 : 0
91
- // })
92
- update.exit().remove()
93
- enter
94
- .attr('x1', d => d.x1)
95
- .attr('y1', d => d.y1)
96
- .attr('x2', d => d.x2)
97
- .attr('y2', d => d.y2)
98
- update
99
- .transition()
100
- .duration(50)
101
- .attr('x1', d => d.x1)
102
- .attr('y1', d => d.y1)
103
- .attr('x2', d => d.x2)
104
- .attr('y2', d => d.y2)
105
-
106
- return auxLineSelection
107
- }
108
-
109
- function removeLine (selection: d3.Selection<any, unknown, any, unknown>) {
110
- const update = selection
111
- .selectAll<SVGLineElement, LineDatum>('line')
112
- .data([])
113
-
114
- update.exit().remove()
115
- }
116
-
117
- function createLabelData ({ groupLabel, axisX, fullParams }: {
118
- groupLabel: string
119
- axisX: number
120
- fullParams: GroupAuxParams
121
- }) {
122
- return fullParams.showLabel && groupLabel
123
- ? [{
124
- id: groupLabel,
125
- x: axisX,
126
- y: - fullParams.labelPadding,
127
- text: parseTickFormatValue(groupLabel, fullParams.labelTextFormat)
128
- }]
129
- : []
130
- }
131
-
132
- function renderLabel ({ selection, labelData, fullParams, fullDataFormatter, fullChartParams, labelTransform, textSizePx }: {
133
- selection: d3.Selection<any, unknown, any, unknown>
134
- labelData: LabelDatum[]
135
- fullParams: GroupAuxParams
136
- fullDataFormatter: DataFormatterGrid
137
- fullChartParams: ChartParams
138
- // gridAxesReverseTransformValue: string
139
- labelTransform: string
140
- textSizePx: number
141
- }) {
142
- const rectHeight = textSizePx + 4
143
-
144
- const gUpdate = selection
145
- .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
146
- .data(labelData)
147
- const gEnter = gUpdate
148
- .enter()
149
- .append('g')
150
- .classed(labelClassName, true)
151
- .style('cursor', 'pointer')
152
- const axisLabelSelection = gEnter.merge(gUpdate)
153
- gEnter
154
- .attr("transform", (d, i) => {
155
- return `translate(${d.x}, ${d.y})`
156
- })
157
- gUpdate
158
- .transition()
159
- .duration(50)
160
- .attr("transform", (d, i) => {
161
- return `translate(${d.x}, ${d.y})`
162
- })
163
- gUpdate.exit().remove()
164
-
165
- axisLabelSelection.each((datum, i, n) => {
166
- const rectWidth = measureTextWidth(datum.text, textSizePx) + 12
167
- // -- label偏移位置 --
168
- let rectX = - rectWidth / 2
169
- let rectY = -2
170
- if (fullDataFormatter.grid.groupAxis.position === 'bottom') {
171
- rectX = - rectWidth / 2
172
- rectY = 2
173
- } else if (fullDataFormatter.grid.groupAxis.position === 'left') {
174
- rectX = - rectWidth + 2
175
- rectY = - rectHeight / 2
176
- } else if (fullDataFormatter.grid.groupAxis.position === 'right') {
177
- rectX = - 2
178
- rectY = - rectHeight / 2
179
- } else if (fullDataFormatter.grid.groupAxis.position === 'top') {
180
- rectX = - rectWidth / 2
181
- rectY = - rectHeight + 2
182
- }
183
-
184
- const rectUpdate = d3.select(n[i])
185
- .selectAll<SVGRectElement, LabelDatum>('rect')
186
- .data([datum])
187
- const rectEnter = rectUpdate
188
- .enter()
189
- .append('rect')
190
- .attr('height', `${rectHeight}px`)
191
- .attr('fill', d => getColor(fullParams.labelColorType, fullChartParams))
192
- .attr('x', rectX)
193
- .attr('y', rectY)
194
- .attr('rx', 5)
195
- .attr('ry', 5)
196
- .style('cursor', 'pointer')
197
- // .style('pointer-events', 'none')
198
- const rect = rectUpdate.merge(rectEnter)
199
- .attr('width', d => `${rectWidth}px`)
200
- .style('transform', labelTransform)
201
- rectUpdate.exit().remove()
202
-
203
- const textUpdate = d3.select(n[i])
204
- .selectAll<SVGTextElement, LabelDatum>('text')
205
- .data([datum])
206
- const textEnter = textUpdate
207
- .enter()
208
- .append('text')
209
- .style('dominant-baseline', 'hanging')
210
- .style('cursor', 'pointer')
211
- // .style('pointer-events', 'none')
212
- const text = textUpdate.merge(textEnter)
213
- .text(d => d.text)
214
- .style('transform', labelTransform)
215
- .attr('fill', d => getColor(fullParams.labelTextColorType, fullChartParams))
216
- .attr('font-size', fullChartParams.styles.textSize)
217
- .attr('x', rectX + 6)
218
- .attr('y', rectY)
219
- textUpdate.exit().remove()
220
- })
221
-
222
- return axisLabelSelection
223
- }
224
-
225
- function removeLabel (selection: d3.Selection<any, unknown, any, unknown>) {
226
- const gUpdate = selection
227
- .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
228
- .data([])
229
-
230
- gUpdate.exit().remove()
231
- }
232
-
233
- export const GroupAux = defineGridPlugin(pluginName, DEFAULT_GROUP_AREA_PARAMS)(({ selection, rootSelection, name, subject, observer }) => {
234
- const destroy$ = new Subject()
235
-
236
- let isLabelMouseover = false
237
-
238
- const rootRectSelection: d3.Selection<SVGRectElement, any, any, any> = rootSelection
239
- .insert('rect', 'g')
240
- .classed(getClassName(pluginName, 'rect'), true)
241
- .attr('opacity', 0)
242
-
243
- // const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
244
- // .append('g')
245
-
246
- const {
247
- seriesSelection$,
248
- axesSelection$,
249
- defsSelection$,
250
- graphicGSelection$
251
- } = gridSelectionsObservable({
252
- selection,
253
- pluginName,
254
- clipPathID: 'test',
255
- seriesLabels$: observer.seriesLabels$,
256
- gridContainerPosition$: observer.gridContainerPosition$,
257
- gridAxesTransform$: observer.gridAxesTransform$,
258
- gridGraphicTransform$: observer.gridGraphicTransform$
259
- })
260
-
261
- observer.layout$.pipe(
262
- takeUntil(destroy$),
263
- ).subscribe(d => {
264
- rootRectSelection
265
- .attr('width', d.rootWidth)
266
- .attr('height', d.rootHeight)
267
- })
268
-
269
- // observer.gridAxesTransform$
270
- // .pipe(
271
- // takeUntil(destroy$),
272
- // map(d => d.value),
273
- // distinctUntilChanged()
274
- // ).subscribe(d => {
275
- // axisSelection
276
- // .style('transform', d)
277
- // })
278
-
279
- // const visibleComputedData$ = observer.computedData$.pipe(
280
- // takeUntil(destroy$),
281
- // map(data => {
282
- // const visibleComputedData = data
283
- // .map(d => {
284
- // return d.filter(_d => {
285
- // return _d.visible == true
286
- // })
287
- // })
288
- // .filter(d => d.length)
289
- // // console.log('visibleComputedData', visibleComputedData)
290
- // return visibleComputedData
291
- // })
292
- // )
293
-
294
- // const SeriesDataMap$ = visibleComputedData$.pipe(
295
- // map(d => makeGridSeriesDataMap(d))
296
- // )
297
-
298
- // const GroupDataMap$ = visibleComputedData$.pipe(
299
- // map(d => makeGridGroupDataMap(d))
300
- // )
301
-
302
- // const contentTransform$: Observable<string> = new Observable(subscriber => {
303
- // combineLatest({
304
- // fullParams: observer.fullParams$,
305
- // gridAxesTransform: observer.gridAxesTransform$
306
- // }).pipe(
307
- // takeUntil(destroy$),
308
- // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
309
- // switchMap(async (d) => d),
310
- // ).subscribe(data => {
311
-
312
- // const transformData = Object.assign({}, data.gridAxesTransform)
313
-
314
- // // const value = getAxesTransformValue({
315
- // // translate: [0, 0],
316
- // // scale: [transformData.scale[0] * -1, transformData.scale[1] * -1],
317
- // // rotate: transformData.rotate * -1,
318
- // // rotateX: transformData.rotateX * -1,
319
- // // rotateY: transformData.rotateY * -1
320
- // // })
321
-
322
- // subscriber.next(transformData.value)
323
- // })
324
- // })
325
- // const reverseTransform$: Observable<TransformData> = observer.gridAxesTransform$.pipe(
326
- // takeUntil(destroy$),
327
- // map(d => {
328
- // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
329
- // const scale: [number, number] = [d.scale[0] * -1, d.scale[1] * -1]
330
- // const rotate = d.rotate * -1
331
- // const rotateX = d.rotateX * -1
332
- // const rotateY = d.rotateY * -1
333
- // return {
334
- // translate,
335
- // scale,
336
- // rotate,
337
- // rotateX,
338
- // rotateY,
339
- // value: ''
340
- // }
341
- // }),
342
- // )
343
- // const contentTransform$ = combineLatest({
344
- // fullParams: observer.fullParams$,
345
- // reverseTransform: reverseTransform$
346
- // }).pipe(
347
- // takeUntil(destroy$),
348
- // switchMap(async data => {
349
- // const translate = [0, 0]
350
- // return `translate(${translate[0]}px, ${translate[1]}px) rotate(${data.reverseTransform.rotate}deg) rotateX(${data.reverseTransform.rotateX}deg) rotateY(${data.reverseTransform.rotateY}deg)`
351
- // }),
352
- // distinctUntilChanged()
353
- // )
354
-
355
- const groupScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
356
- combineLatest({
357
- fullDataFormatter: observer.fullDataFormatter$,
358
- gridAxesSize: observer.gridAxesSize$,
359
- computedData: observer.computedData$
360
- }).pipe(
361
- takeUntil(destroy$),
362
- switchMap(async (d) => d),
363
- ).subscribe(data => {
364
- const groupMin = 0
365
- const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
366
- const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
367
- ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
368
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
369
- const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
370
- ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
371
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
372
-
373
- const groupingLength = data.computedData[0]
374
- ? data.computedData[0].length
375
- : 0
376
-
377
- let _labels = data.fullDataFormatter.grid.seriesDirection === 'row'
378
- // ? data.fullDataFormatter.grid.columnLabels
379
- // : data.fullDataFormatter.grid.rowLabels
380
- ? (data.computedData[0] ?? []).map(d => d.groupLabel)
381
- : data.computedData.map(d => d[0].groupLabel)
382
-
383
- const axisLabels = new Array(groupingLength).fill(0)
384
- .map((d, i) => {
385
- return _labels[i] != null
386
- ? _labels[i]
387
- : String(i) // 沒有label則用序列號填充
388
- })
389
- .filter((d, i) => {
390
- return i >= groupScaleDomainMin && i <= groupScaleDomainMax
391
- })
392
-
393
-
394
- const padding = data.fullDataFormatter.grid.groupAxis.scalePadding
395
-
396
- const groupScale = createAxisPointScale({
397
- axisLabels,
398
- axisWidth: data.gridAxesSize.width,
399
- padding
400
- })
401
-
402
- subscriber.next(groupScale)
403
- })
404
- })
405
-
406
- // 取得事件座標的group資料
407
- const gridGroupPositionFn$ = gridGroupPositionFnObservable({
408
- fullDataFormatter$: observer.fullDataFormatter$,
409
- gridAxesSize$: observer.gridAxesSize$,
410
- computedData$: observer.computedData$,
411
- fullChartParams$: observer.fullChartParams$,
412
- })
413
-
414
- const highlightTarget$ = observer.fullChartParams$.pipe(
415
- takeUntil(destroy$),
416
- map(d => d.highlightTarget),
417
- distinctUntilChanged()
418
- )
419
-
420
- // combineLatest({
421
- // computedData: observer.computedData$,
422
- // gridAxesSize: observer.gridAxesSize$,
423
- // fullParams: observer.fullParams$,
424
- // fullChartParams: observer.fullChartParams$,
425
- // highlightTarget: highlightTarget$,
426
- // SeriesDataMap: observer.SeriesDataMap$,
427
- // GroupDataMap: observer.GroupDataMap$,
428
- // gridGroupPositionFn: gridGroupPositionFn$,
429
- // groupScale: groupScale$,
430
- // }).pipe(
431
- // takeUntil(destroy$),
432
- // switchMap(async (d) => d),
433
- // ).subscribe(data => {
434
-
435
- // // store.selection
436
- // rootSelection
437
- // .on('mouseover', (event, datum) => {
438
- // // event.stopPropagation()
439
-
440
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
441
-
442
- // subject.event$.next({
443
- // type: 'grid',
444
- // pluginName: name,
445
- // eventName: 'mouseover',
446
- // highlightTarget: data.highlightTarget,
447
- // datum: null,
448
- // gridIndex: 0, // @Q@ 暫不處理
449
- // series: [],
450
- // seriesIndex: -1,
451
- // seriesLabel: '',
452
- // groups: data.GroupDataMap.get(groupLabel) ?? [],
453
- // // groups: [],
454
- // groupIndex,
455
- // groupLabel,
456
- // event,
457
- // data: data.computedData
458
- // })
459
- // })
460
- // .on('mousemove', (event, datum) => {
461
- // // event.stopPropagation()
462
-
463
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
464
-
465
- // subject.event$.next({
466
- // type: 'grid',
467
- // pluginName: name,
468
- // eventName: 'mousemove',
469
- // highlightTarget: data.highlightTarget,
470
- // datum: null,
471
- // gridIndex: 0, // @Q@ 暫不處理
472
- // series: [],
473
- // seriesIndex: -1,
474
- // seriesLabel: '',
475
- // groups: data.GroupDataMap.get(groupLabel) ?? [],
476
- // // groups: [],
477
- // groupIndex,
478
- // groupLabel,
479
- // event,
480
- // data: data.computedData
481
- // })
482
- // })
483
- // .on('mouseout', (event, datum) => {
484
- // // event.stopPropagation()
485
-
486
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
487
-
488
- // subject.event$.next({
489
- // type: 'grid',
490
- // pluginName: name,
491
- // eventName: 'mouseout',
492
- // highlightTarget: data.highlightTarget,
493
- // datum: null,
494
- // gridIndex: 0, // @Q@ 暫不處理
495
- // series: [],
496
- // seriesIndex: -1,
497
- // seriesLabel: '',
498
- // groups: data.GroupDataMap.get(groupLabel) ?? [],
499
- // // groups: [],
500
- // groupIndex,
501
- // groupLabel,
502
- // event,
503
- // data: data.computedData
504
- // })
505
- // })
506
- // .on('click', (event, datum) => {
507
- // event.stopPropagation()
508
-
509
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
510
-
511
- // subject.event$.next({
512
- // type: 'grid',
513
- // pluginName: name,
514
- // eventName: 'click',
515
- // highlightTarget: data.highlightTarget,
516
- // datum: null,
517
- // gridIndex: 0, // @Q@ 暫不處理
518
- // series: [],
519
- // seriesIndex: -1,
520
- // seriesLabel: '',
521
- // // groups: data.GroupDataMap.get(groupLabel) ?? [],
522
- // groups: [],
523
- // groupIndex,
524
- // groupLabel,
525
- // event,
526
- // data: data.computedData
527
- // })
528
- // })
529
-
530
- // // barSelection$.next(barSelection!)
531
- // })
532
-
533
- const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove').pipe(
534
- takeUntil(destroy$),
535
- )
536
-
537
-
538
- // const mousemoveGroupLabel$ = combineLatest({
539
- // rootMousemove: rootMousemove$,
540
- // gridGroupPositionFn: gridGroupPositionFn$,
541
- // }).pipe(
542
- // takeUntil(destroy$),
543
- // switchMap(async d => d),
544
- // map(data => {
545
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(data.rootMousemove)
546
- // return { groupIndex, groupLabel }
547
- // }),
548
- // shareReplay(1)
549
- // )
550
-
551
- const labelTransform$ = combineLatest({
552
- fullParams: observer.fullParams$,
553
- fullDataFormatter: observer.fullDataFormatter$,
554
- gridAxesReverseTransform: observer.gridAxesReverseTransform$,
555
- gridContainerPosition: observer.gridContainerPosition$
556
- }).pipe(
557
- takeUntil(destroy$),
558
- switchMap(async d => d),
559
- map(data => {
560
- const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
561
- const axisReverseRotateValue = `rotate(${data.gridAxesReverseTransform.rotate}deg) rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
562
- const containerScaleReverseScaleValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
563
- const tickTextRotateDeg = (data.fullDataFormatter.grid.groupAxis.position === 'left' && data.fullDataFormatter.grid.valueAxis.position === 'top')
564
- || (data.fullDataFormatter.grid.groupAxis.position === 'right' && data.fullDataFormatter.grid.valueAxis.position === 'bottom')
565
- // ? data.fullParams.tickTextRotate + 180 // 修正文字倒轉
566
- // : data.fullParams.tickTextRotate
567
- ? 180 // 修正文字倒轉
568
- : 0
569
-
570
- const textRotateValue = `rotate(${tickTextRotateDeg}deg)`
571
-
572
- // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
573
- return `${axisReverseTranslateValue} ${axisReverseRotateValue} ${containerScaleReverseScaleValue} ${textRotateValue}`
574
- }),
575
- distinctUntilChanged()
576
- )
577
-
578
- const columnAmount$ = observer.gridContainerPosition$.pipe(
579
- takeUntil(destroy$),
580
- map(gridContainerPosition => {
581
- const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
582
- return current.columnIndex > acc ? current.columnIndex : acc
583
- }, 0)
584
- return maxColumnIndex + 1
585
- }),
586
- distinctUntilChanged()
587
- )
588
-
589
- const rowAmount$ = observer.gridContainerPosition$.pipe(
590
- takeUntil(destroy$),
591
- map(gridContainerPosition => {
592
- const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
593
- return current.rowIndex > acc ? current.rowIndex : acc
594
- }, 0)
595
- return maxRowIndex + 1
596
- }),
597
- distinctUntilChanged()
598
- )
599
-
600
- combineLatest({
601
- axesSelection: axesSelection$,
602
- columnAmount: columnAmount$,
603
- rowAmount: rowAmount$,
604
- layout: observer.layout$,
605
- rootMousemove: rootMousemove$,
606
- gridGroupPositionFn: gridGroupPositionFn$,
607
- computedData: observer.computedData$,
608
- groupScale: groupScale$,
609
- gridAxesSize: observer.gridAxesSize$,
610
- fullParams: observer.fullParams$,
611
- fullDataFormatter: observer.fullDataFormatter$,
612
- fullChartParams: observer.fullChartParams$,
613
- highlightTarget: highlightTarget$,
614
- // gridAxesReverseTransform: observer.gridAxesReverseTransform$,
615
- labelTransform: labelTransform$,
616
- GroupDataMap: observer.GroupDataMap$,
617
- textSizePx: observer.textSizePx$
618
- }).subscribe(data => {
619
- // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
620
- const eventData = {
621
- offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
622
- offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
623
- }
624
- // 依event的座標取得group資料
625
- const { groupIndex, groupLabel } = data.gridGroupPositionFn(eventData)
626
-
627
- const axisX = data.groupScale(groupLabel) ?? 0
628
-
629
- const lineData = createLineData({
630
- groupLabel: groupLabel,
631
- axisX,
632
- axisHeight: data.gridAxesSize.height,
633
- fullParams: data.fullParams,
634
- })
635
- renderLine({
636
- // selection: axisSelection,
637
- selection: data.axesSelection,
638
- pluginName: name,
639
- lineData,
640
- fullParams: data.fullParams,
641
- fullChartParams: data.fullChartParams
642
- })
643
- const labelData = createLabelData({
644
- groupLabel: groupLabel,
645
- axisX,
646
- fullParams: data.fullParams
647
- })
648
- const labelSelection = renderLabel({
649
- // selection: axisSelection,
650
- selection: data.axesSelection,
651
- labelData,
652
- fullParams: data.fullParams,
653
- fullDataFormatter: data.fullDataFormatter,
654
- fullChartParams: data.fullChartParams,
655
- // gridAxesReverseTransformValue: data.gridAxesReverseTransform.value,
656
- labelTransform: data.labelTransform,
657
- textSizePx: data.textSizePx
658
- })
659
-
660
- // label的事件
661
- labelSelection
662
- .on('mouseover', (event, datum) => {
663
- event.stopPropagation()
664
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
665
-
666
- isLabelMouseover = true
667
-
668
- subject.event$.next({
669
- type: 'grid',
670
- pluginName: name,
671
- eventName: 'mouseover',
672
- highlightTarget: data.highlightTarget,
673
- datum: null,
674
- gridIndex: 0, // @Q@ 暫不處理
675
- series: [],
676
- seriesIndex: -1,
677
- seriesLabel: '',
678
- groups: data.GroupDataMap.get(groupLabel) ?? [],
679
- groupIndex,
680
- groupLabel,
681
- event,
682
- data: data.computedData
683
- })
684
- })
685
- .on('mousemove', (event, datum) => {
686
- event.stopPropagation()
687
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
688
-
689
- subject.event$.next({
690
- type: 'grid',
691
- pluginName: name,
692
- eventName: 'mousemove',
693
- highlightTarget: data.highlightTarget,
694
- datum: null,
695
- gridIndex: 0, // @Q@ 暫不處理
696
- series: [],
697
- seriesIndex: -1,
698
- seriesLabel: '',
699
- groups: data.GroupDataMap.get(groupLabel) ?? [],
700
- groupIndex,
701
- groupLabel,
702
- event,
703
- data: data.computedData
704
- })
705
- })
706
- .on('mouseout', (event, datum) => {
707
- event.stopPropagation()
708
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
709
-
710
- isLabelMouseover = false
711
-
712
- subject.event$.next({
713
- type: 'grid',
714
- pluginName: name,
715
- eventName: 'mouseout',
716
- highlightTarget: data.highlightTarget,
717
- datum: null,
718
- gridIndex: 0, // @Q@ 暫不處理
719
- series: [],
720
- seriesIndex: -1,
721
- seriesLabel: '',
722
- groups: data.GroupDataMap.get(groupLabel) ?? [],
723
- groupIndex,
724
- groupLabel,
725
- event,
726
- data: data.computedData
727
- })
728
- })
729
- .on('click', (event, datum) => {
730
- event.stopPropagation()
731
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
732
-
733
- subject.event$.next({
734
- type: 'grid',
735
- pluginName: name,
736
- eventName: 'click',
737
- highlightTarget: data.highlightTarget,
738
- datum: null,
739
- gridIndex: 0, // @Q@ 暫不處理
740
- series: [],
741
- seriesIndex: -1,
742
- seriesLabel: '',
743
- groups: data.GroupDataMap.get(groupLabel) ?? [],
744
- groupIndex,
745
- groupLabel,
746
- event,
747
- data: data.computedData
748
- })
749
- })
750
-
751
- })
752
-
753
- // // -- highlight(無論highlightTarget設定為何,一律依從groupLabel來顯示) --
754
- // combineLatest({
755
- // event: subject.event$.pipe(
756
- // filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove')
757
- // ),
758
- // computedData: observer.computedData$,
759
- // groupScale: groupScale$,
760
- // gridAxesSize: observer.gridAxesSize$,
761
- // fullParams: observer.fullParams$,
762
- // fullChartParams: observer.fullChartParams$,
763
- // highlightTarget: highlightTarget$,
764
- // gridAxesReverseTransform: observer.gridAxesReverseTransform$,
765
- // GroupDataMap: observer.GroupDataMap$,
766
- // gridGroupPositionFn: gridGroupPositionFn$,
767
- // textSizePx: observer.textSizePx$
768
- // }).pipe(
769
- // takeUntil(destroy$),
770
- // switchMap(async d => d)
771
- // ).subscribe(data => {
772
- // // const groups = data.event.eventName === 'mouseover' || data.event.eventName === 'mousemove'
773
- // // ? data.event.groups
774
- // // : []
775
-
776
- // // const groupLabel = data.event.eventName === 'mouseover' || data.event.eventName === 'mousemove'
777
- // // ? data.event.groupLabel
778
- // // : ''
779
- // const axisX = data.groupScale(data.event.groupLabel) ?? 0
780
-
781
- // const lineData = createLineData({
782
- // groupLabel: data.event.groupLabel,
783
- // axisX,
784
- // axisHeight: data.gridAxesSize.height,
785
- // fullParams: data.fullParams,
786
- // })
787
- // renderLine({
788
- // selection: axisSelection,
789
- // pluginName: name,
790
- // lineData,
791
- // fullParams: data.fullParams,
792
- // fullChartParams: data.fullChartParams
793
- // })
794
- // const labelData = createLabelData({
795
- // groupLabel: data.event.groupLabel,
796
- // axisX,
797
- // fullParams: data.fullParams
798
- // })
799
- // const labelSelection = renderLabel({
800
- // selection: axisSelection,
801
- // labelData,
802
- // fullParams: data.fullParams,
803
- // fullChartParams: data.fullChartParams,
804
- // gridAxesReverseTransformValue: data.gridAxesReverseTransform.value,
805
- // textSizePx: data.textSizePx
806
- // })
807
-
808
- // // label的事件
809
- // labelSelection
810
- // .on('mouseover', (event, datum) => {
811
-
812
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
813
-
814
- // subject.event$.next({
815
- // type: 'grid',
816
- // pluginName: name,
817
- // eventName: 'mouseover',
818
- // highlightTarget: data.highlightTarget,
819
- // datum: null,
820
- // gridIndex: 0, // @Q@ 暫不處理
821
- // series: [],
822
- // seriesIndex: -1,
823
- // seriesLabel: '',
824
- // groups: data.event.groups,
825
- // groupIndex,
826
- // groupLabel,
827
- // event,
828
- // data: data.computedData
829
- // })
830
- // })
831
- // .on('mousemove', (event, datum) => {
832
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
833
-
834
- // subject.event$.next({
835
- // type: 'grid',
836
- // pluginName: name,
837
- // eventName: 'mousemove',
838
- // highlightTarget: data.highlightTarget,
839
- // datum: null,
840
- // gridIndex: 0, // @Q@ 暫不處理
841
- // series: [],
842
- // seriesIndex: -1,
843
- // seriesLabel: '',
844
- // groups: data.event.groups,
845
- // groupIndex,
846
- // groupLabel,
847
- // event,
848
- // data: data.computedData
849
- // })
850
- // })
851
- // .on('mouseout', (event, datum) => {
852
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
853
-
854
- // subject.event$.next({
855
- // type: 'grid',
856
- // pluginName: name,
857
- // eventName: 'mouseout',
858
- // highlightTarget: data.highlightTarget,
859
- // datum: null,
860
- // gridIndex: 0, // @Q@ 暫不處理
861
- // series: [],
862
- // seriesIndex: -1,
863
- // seriesLabel: '',
864
- // groups: data.event.groups,
865
- // groupIndex,
866
- // groupLabel,
867
- // event,
868
- // data: data.computedData
869
- // })
870
- // })
871
- // .on('click', (event, datum) => {
872
- // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
873
-
874
- // subject.event$.next({
875
- // type: 'grid',
876
- // pluginName: name,
877
- // eventName: 'click',
878
- // highlightTarget: data.highlightTarget,
879
- // datum: null,
880
- // gridIndex: 0, // @Q@ 暫不處理
881
- // series: [],
882
- // seriesIndex: -1,
883
- // seriesLabel: '',
884
- // groups: data.event.groups,
885
- // groupIndex,
886
- // groupLabel,
887
- // event,
888
- // data: data.computedData
889
- // })
890
- // })
891
- // })
892
-
893
-
894
-
895
- const rootRectMouseout$ = d3EventObservable(rootRectSelection, 'mouseout').pipe(
896
- takeUntil(destroy$),
897
- )
898
-
899
-
900
- combineLatest({
901
- rootRectMouseout: rootRectMouseout$,
902
- axesSelection: axesSelection$,
903
- }).pipe(
904
- takeUntil(destroy$),
905
- switchMap(async d => d)
906
- ).subscribe(data => {
907
-
908
- setTimeout(() => {
909
- // @Q@ workaround - 不知為何和 label 會有衝突,當滑鼠移動到 label 上時,會觸發 mouseout 事件
910
- if (isLabelMouseover == true) {
911
- return
912
- }
913
-
914
- removeLine(data.axesSelection)
915
- removeLabel(data.axesSelection)
916
- })
917
- })
918
-
919
- return () => {
920
- destroy$.next(undefined)
921
- rootRectSelection.remove()
922
- }
1
+ import * as d3 from 'd3'
2
+ import {
3
+ // of,
4
+ iif,
5
+ EMPTY,
6
+ combineLatest,
7
+ switchMap,
8
+ map,
9
+ filter,
10
+ first,
11
+ takeUntil,
12
+ distinctUntilChanged,
13
+ shareReplay,
14
+ Subject,
15
+ Observable } from 'rxjs'
16
+ import {
17
+ defineGridPlugin } from '@orbcharts/core'
18
+ import type {
19
+ TransformData,
20
+ DataFormatterGrid,
21
+ ChartParams } from '@orbcharts/core'
22
+ import { DEFAULT_GROUP_AREA_PARAMS } from '../defaults'
23
+ import { parseTickFormatValue } from '../../utils/d3Utils'
24
+ import { measureTextWidth } from '../../utils/commonUtils'
25
+ import { getColor, getClassName, getUniID } from '../../utils/orbchartsUtils'
26
+ import { d3EventObservable } from '../../utils/observables'
27
+ import { gridGroupPosition } from '../gridObservables'
28
+ import { createAxisPointScale } from '@orbcharts/core'
29
+ import type { GroupAuxParams } from '../types'
30
+ import { gridSelectionsObservable } from '../gridObservables'
31
+
32
+ interface LineDatum {
33
+ id: string
34
+ x1: number
35
+ x2: number
36
+ y1: number
37
+ y2: number
38
+ }
39
+
40
+ interface LabelDatum {
41
+ id: string
42
+ text: string
43
+ x: number
44
+ y: number
45
+ }
46
+
47
+ const pluginName = 'GroupAux'
48
+ const labelClassName = getClassName(pluginName, 'label-box')
49
+
50
+ function createLineData ({ groupLabel, axisX, axisHeight, fullParams }: {
51
+ groupLabel: string
52
+ axisX: number
53
+ axisHeight: number
54
+ fullParams: GroupAuxParams
55
+ }): LineDatum[] {
56
+ return fullParams.showLine && groupLabel
57
+ ? [{
58
+ id: groupLabel,
59
+ x1: axisX,
60
+ x2: axisX,
61
+ y1: 0,
62
+ y2: axisHeight
63
+ }]
64
+ : []
65
+ }
66
+
67
+ function renderLine ({ selection, pluginName, lineData, fullParams, fullChartParams }: {
68
+ selection: d3.Selection<any, string, any, unknown>
69
+ pluginName: string
70
+ lineData: LineDatum[]
71
+ fullParams: GroupAuxParams
72
+ fullChartParams: ChartParams
73
+ }) {
74
+ const gClassName = getClassName(pluginName, 'auxline')
75
+ const update = selection
76
+ .selectAll<SVGLineElement, LineDatum>(`line.${gClassName}`)
77
+ .data(lineData)
78
+ const enter = update
79
+ .enter()
80
+ .append('line')
81
+ .classed(gClassName, true)
82
+ // .style('stroke', '#E4E7ED')
83
+ .style('stroke', d => getColor(fullParams.lineColorType, fullChartParams))
84
+ .style('stroke-width', 1)
85
+ .style('stroke-dasharray', fullParams.lineDashArray ?? 'none')
86
+ .style('pointer-events', 'none')
87
+ // .attr('opacity', 0)
88
+ const auxLineSelection = update.merge(enter)
89
+ // .attr('opacity', (d) => {
90
+ // return d.active == true ? 1 : 0
91
+ // })
92
+ update.exit().remove()
93
+ enter
94
+ .attr('x1', d => d.x1)
95
+ .attr('y1', d => d.y1)
96
+ .attr('x2', d => d.x2)
97
+ .attr('y2', d => d.y2)
98
+ update
99
+ .transition()
100
+ .duration(50)
101
+ .attr('x1', d => d.x1)
102
+ .attr('y1', d => d.y1)
103
+ .attr('x2', d => d.x2)
104
+ .attr('y2', d => d.y2)
105
+
106
+ return auxLineSelection
107
+ }
108
+
109
+ function removeLine (selection: d3.Selection<any, string, any, unknown>) {
110
+ const update = selection
111
+ .selectAll<SVGLineElement, LineDatum>('line')
112
+ .data([])
113
+
114
+ update.exit().remove()
115
+ }
116
+
117
+ function createLabelData ({ groupLabel, axisX, fullParams }: {
118
+ groupLabel: string
119
+ axisX: number
120
+ fullParams: GroupAuxParams
121
+ }) {
122
+ return fullParams.showLabel && groupLabel
123
+ ? [{
124
+ id: groupLabel,
125
+ x: axisX,
126
+ y: - fullParams.labelPadding,
127
+ text: parseTickFormatValue(groupLabel, fullParams.labelTextFormat)
128
+ }]
129
+ : []
130
+ }
131
+
132
+ function renderLabel ({ selection, labelData, fullParams, fullDataFormatter, fullChartParams, labelTransform, textSizePx }: {
133
+ selection: d3.Selection<any, string, any, unknown>
134
+ labelData: LabelDatum[]
135
+ fullParams: GroupAuxParams
136
+ fullDataFormatter: DataFormatterGrid
137
+ fullChartParams: ChartParams
138
+ // gridAxesReverseTransformValue: string
139
+ labelTransform: string
140
+ textSizePx: number
141
+ }) {
142
+ const rectHeight = textSizePx + 4
143
+
144
+ const gUpdate = selection
145
+ .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
146
+ .data(labelData)
147
+ const gEnter = gUpdate
148
+ .enter()
149
+ .append('g')
150
+ .classed(labelClassName, true)
151
+ .style('cursor', 'pointer')
152
+ const axisLabelSelection = gEnter.merge(gUpdate)
153
+ gEnter
154
+ .attr("transform", (d, i) => {
155
+ return `translate(${d.x}, ${d.y})`
156
+ })
157
+ gUpdate
158
+ .transition()
159
+ .duration(50)
160
+ .attr("transform", (d, i) => {
161
+ return `translate(${d.x}, ${d.y})`
162
+ })
163
+ gUpdate.exit().remove()
164
+
165
+ axisLabelSelection.each((datum, i, n) => {
166
+ const rectWidth = measureTextWidth(datum.text, textSizePx) + 12
167
+ // -- label偏移位置 --
168
+ let rectX = - rectWidth / 2
169
+ let rectY = -2
170
+ if (fullDataFormatter.grid.groupAxis.position === 'bottom') {
171
+ rectX = fullParams.labelRotate
172
+ ? - rectWidth
173
+ : - rectWidth / 2
174
+ rectY = 2
175
+ } else if (fullDataFormatter.grid.groupAxis.position === 'left') {
176
+ rectX = - rectWidth + 2
177
+ rectY = - rectHeight / 2
178
+ } else if (fullDataFormatter.grid.groupAxis.position === 'right') {
179
+ rectX = - 2
180
+ rectY = - rectHeight / 2
181
+ } else if (fullDataFormatter.grid.groupAxis.position === 'top') {
182
+ rectX = fullParams.labelRotate
183
+ ? - rectWidth
184
+ : - rectWidth / 2
185
+ rectY = - rectHeight + 2
186
+ }
187
+
188
+ const rectUpdate = d3.select(n[i])
189
+ .selectAll<SVGRectElement, LabelDatum>('rect')
190
+ .data([datum])
191
+ const rectEnter = rectUpdate
192
+ .enter()
193
+ .append('rect')
194
+ .attr('height', `${rectHeight}px`)
195
+ .attr('fill', d => getColor(fullParams.labelColorType, fullChartParams))
196
+ .attr('x', rectX)
197
+ .attr('y', rectY)
198
+ .attr('rx', 5)
199
+ .attr('ry', 5)
200
+ .style('cursor', 'pointer')
201
+ // .style('pointer-events', 'none')
202
+ const rect = rectUpdate.merge(rectEnter)
203
+ .attr('width', d => `${rectWidth}px`)
204
+ .style('transform', labelTransform)
205
+ rectUpdate.exit().remove()
206
+
207
+ const textUpdate = d3.select(n[i])
208
+ .selectAll<SVGTextElement, LabelDatum>('text')
209
+ .data([datum])
210
+ const textEnter = textUpdate
211
+ .enter()
212
+ .append('text')
213
+ .style('dominant-baseline', 'hanging')
214
+ .style('cursor', 'pointer')
215
+ // .style('pointer-events', 'none')
216
+ const text = textUpdate.merge(textEnter)
217
+ .text(d => d.text)
218
+ .style('transform', labelTransform)
219
+ .attr('fill', d => getColor(fullParams.labelTextColorType, fullChartParams))
220
+ .attr('font-size', fullChartParams.styles.textSize)
221
+ .attr('x', rectX + 6)
222
+ .attr('y', rectY)
223
+ textUpdate.exit().remove()
224
+ })
225
+
226
+ return axisLabelSelection
227
+ }
228
+
229
+ function removeLabel (selection: d3.Selection<any, string, any, unknown>) {
230
+ const gUpdate = selection
231
+ .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
232
+ .data([])
233
+
234
+ gUpdate.exit().remove()
235
+ }
236
+
237
+ export const GroupAux = defineGridPlugin(pluginName, DEFAULT_GROUP_AREA_PARAMS)(({ selection, rootSelection, name, subject, observer }) => {
238
+ const destroy$ = new Subject()
239
+
240
+ let isLabelMouseover = false
241
+
242
+ const rootRectSelection: d3.Selection<SVGRectElement, any, any, any> = rootSelection
243
+ .insert('rect', 'g')
244
+ .classed(getClassName(pluginName, 'rect'), true)
245
+ .attr('opacity', 0)
246
+
247
+ // const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
248
+ // .append('g')
249
+
250
+ const {
251
+ seriesSelection$,
252
+ axesSelection$,
253
+ defsSelection$,
254
+ graphicGSelection$
255
+ } = gridSelectionsObservable({
256
+ selection,
257
+ pluginName,
258
+ clipPathID: 'test',
259
+ seriesLabels$: observer.seriesLabels$,
260
+ gridContainerPosition$: observer.gridContainerPosition$,
261
+ gridAxesTransform$: observer.gridAxesTransform$,
262
+ gridGraphicTransform$: observer.gridGraphicTransform$
263
+ })
264
+
265
+ observer.layout$.pipe(
266
+ takeUntil(destroy$),
267
+ ).subscribe(d => {
268
+ rootRectSelection
269
+ .attr('width', d.rootWidth)
270
+ .attr('height', d.rootHeight)
271
+ })
272
+
273
+ // observer.gridAxesTransform$
274
+ // .pipe(
275
+ // takeUntil(destroy$),
276
+ // map(d => d.value),
277
+ // distinctUntilChanged()
278
+ // ).subscribe(d => {
279
+ // axisSelection
280
+ // .style('transform', d)
281
+ // })
282
+
283
+ // const visibleComputedData$ = observer.computedData$.pipe(
284
+ // takeUntil(destroy$),
285
+ // map(data => {
286
+ // const visibleComputedData = data
287
+ // .map(d => {
288
+ // return d.filter(_d => {
289
+ // return _d.visible == true
290
+ // })
291
+ // })
292
+ // .filter(d => d.length)
293
+ // // console.log('visibleComputedData', visibleComputedData)
294
+ // return visibleComputedData
295
+ // })
296
+ // )
297
+
298
+ // const SeriesDataMap$ = visibleComputedData$.pipe(
299
+ // map(d => makeGridSeriesDataMap(d))
300
+ // )
301
+
302
+ // const GroupDataMap$ = visibleComputedData$.pipe(
303
+ // map(d => makeGridGroupDataMap(d))
304
+ // )
305
+
306
+ // const contentTransform$: Observable<string> = new Observable(subscriber => {
307
+ // combineLatest({
308
+ // fullParams: observer.fullParams$,
309
+ // gridAxesTransform: observer.gridAxesTransform$
310
+ // }).pipe(
311
+ // takeUntil(destroy$),
312
+ // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
313
+ // switchMap(async (d) => d),
314
+ // ).subscribe(data => {
315
+
316
+ // const transformData = Object.assign({}, data.gridAxesTransform)
317
+
318
+ // // const value = getAxesTransformValue({
319
+ // // translate: [0, 0],
320
+ // // scale: [transformData.scale[0] * -1, transformData.scale[1] * -1],
321
+ // // rotate: transformData.rotate * -1,
322
+ // // rotateX: transformData.rotateX * -1,
323
+ // // rotateY: transformData.rotateY * -1
324
+ // // })
325
+
326
+ // subscriber.next(transformData.value)
327
+ // })
328
+ // })
329
+ // const reverseTransform$: Observable<TransformData> = observer.gridAxesTransform$.pipe(
330
+ // takeUntil(destroy$),
331
+ // map(d => {
332
+ // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
333
+ // const scale: [number, number] = [d.scale[0] * -1, d.scale[1] * -1]
334
+ // const rotate = d.rotate * -1
335
+ // const rotateX = d.rotateX * -1
336
+ // const rotateY = d.rotateY * -1
337
+ // return {
338
+ // translate,
339
+ // scale,
340
+ // rotate,
341
+ // rotateX,
342
+ // rotateY,
343
+ // value: ''
344
+ // }
345
+ // }),
346
+ // )
347
+ // const contentTransform$ = combineLatest({
348
+ // fullParams: observer.fullParams$,
349
+ // reverseTransform: reverseTransform$
350
+ // }).pipe(
351
+ // takeUntil(destroy$),
352
+ // switchMap(async data => {
353
+ // const translate = [0, 0]
354
+ // return `translate(${translate[0]}px, ${translate[1]}px) rotate(${data.reverseTransform.rotate}deg) rotateX(${data.reverseTransform.rotateX}deg) rotateY(${data.reverseTransform.rotateY}deg)`
355
+ // }),
356
+ // distinctUntilChanged()
357
+ // )
358
+
359
+ // const groupScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
360
+ // combineLatest({
361
+ // fullDataFormatter: observer.fullDataFormatter$,
362
+ // gridAxesSize: observer.gridAxesSize$,
363
+ // computedData: observer.computedData$
364
+ // }).pipe(
365
+ // takeUntil(destroy$),
366
+ // switchMap(async (d) => d),
367
+ // ).subscribe(data => {
368
+ // const groupMin = 0
369
+ // const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
370
+ // const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
371
+ // ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
372
+ // : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
373
+ // const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
374
+ // ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
375
+ // : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
376
+
377
+ // const groupingLength = data.computedData[0]
378
+ // ? data.computedData[0].length
379
+ // : 0
380
+
381
+ // let _labels = data.fullDataFormatter.grid.seriesDirection === 'row'
382
+ // // ? data.fullDataFormatter.grid.columnLabels
383
+ // // : data.fullDataFormatter.grid.rowLabels
384
+ // ? (data.computedData[0] ?? []).map(d => d.groupLabel)
385
+ // : data.computedData.map(d => d[0].groupLabel)
386
+
387
+ // const axisLabels = new Array(groupingLength).fill(0)
388
+ // .map((d, i) => {
389
+ // return _labels[i] != null
390
+ // ? _labels[i]
391
+ // : String(i) // 沒有label則用序列號填充
392
+ // })
393
+ // .filter((d, i) => {
394
+ // return i >= groupScaleDomainMin && i <= groupScaleDomainMax
395
+ // })
396
+
397
+
398
+ // const padding = data.fullDataFormatter.grid.groupAxis.scalePadding
399
+
400
+ // const groupScale = createAxisPointScale({
401
+ // axisLabels,
402
+ // axisWidth: data.gridAxesSize.width,
403
+ // padding
404
+ // })
405
+
406
+ // subscriber.next(groupScale)
407
+ // })
408
+ // })
409
+
410
+ const groupScaleDomain$ = combineLatest({
411
+ fullDataFormatter: observer.fullDataFormatter$,
412
+ gridAxesSize: observer.gridAxesSize$,
413
+ computedData: observer.computedData$
414
+ }).pipe(
415
+ takeUntil(destroy$),
416
+ switchMap(async (d) => d),
417
+ map(data => {
418
+ const groupMin = 0
419
+ const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
420
+ const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
421
+ ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
422
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
423
+ const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
424
+ ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
425
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
426
+
427
+ return [groupScaleDomainMin, groupScaleDomainMax]
428
+ }),
429
+ shareReplay(1)
430
+ )
431
+
432
+ const groupScale$ = combineLatest({
433
+ groupScaleDomain: groupScaleDomain$,
434
+ gridAxesSize: observer.gridAxesSize$
435
+ }).pipe(
436
+ takeUntil(destroy$),
437
+ switchMap(async (d) => d),
438
+ map(data => {
439
+ const groupScale: d3.ScaleLinear<number, number> = d3.scaleLinear()
440
+ .domain(data.groupScaleDomain)
441
+ .range([0, data.gridAxesSize.width])
442
+ return groupScale
443
+ })
444
+ )
445
+
446
+ // // 取得事件座標的group資料
447
+ // const gridGroupPositionFn$ = gridGroupPositionFnObservable({
448
+ // fullDataFormatter$: observer.fullDataFormatter$,
449
+ // gridAxesSize$: observer.gridAxesSize$,
450
+ // computedData$: observer.computedData$,
451
+ // fullChartParams$: observer.fullChartParams$,
452
+ // })
453
+
454
+ const highlightTarget$ = observer.fullChartParams$.pipe(
455
+ takeUntil(destroy$),
456
+ map(d => d.highlightTarget),
457
+ distinctUntilChanged()
458
+ )
459
+
460
+ // combineLatest({
461
+ // computedData: observer.computedData$,
462
+ // gridAxesSize: observer.gridAxesSize$,
463
+ // fullParams: observer.fullParams$,
464
+ // fullChartParams: observer.fullChartParams$,
465
+ // highlightTarget: highlightTarget$,
466
+ // SeriesDataMap: observer.SeriesDataMap$,
467
+ // GroupDataMap: observer.GroupDataMap$,
468
+ // gridGroupPositionFn: gridGroupPositionFn$,
469
+ // groupScale: groupScale$,
470
+ // }).pipe(
471
+ // takeUntil(destroy$),
472
+ // switchMap(async (d) => d),
473
+ // ).subscribe(data => {
474
+
475
+ // // store.selection
476
+ // rootSelection
477
+ // .on('mouseover', (event, datum) => {
478
+ // // event.stopPropagation()
479
+
480
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
481
+
482
+ // subject.event$.next({
483
+ // type: 'grid',
484
+ // pluginName: name,
485
+ // eventName: 'mouseover',
486
+ // highlightTarget: data.highlightTarget,
487
+ // datum: null,
488
+ // gridIndex: 0, // @Q@ 暫不處理
489
+ // series: [],
490
+ // seriesIndex: -1,
491
+ // seriesLabel: '',
492
+ // groups: data.GroupDataMap.get(groupLabel) ?? [],
493
+ // // groups: [],
494
+ // groupIndex,
495
+ // groupLabel,
496
+ // event,
497
+ // data: data.computedData
498
+ // })
499
+ // })
500
+ // .on('mousemove', (event, datum) => {
501
+ // // event.stopPropagation()
502
+
503
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
504
+
505
+ // subject.event$.next({
506
+ // type: 'grid',
507
+ // pluginName: name,
508
+ // eventName: 'mousemove',
509
+ // highlightTarget: data.highlightTarget,
510
+ // datum: null,
511
+ // gridIndex: 0, // @Q@ 暫不處理
512
+ // series: [],
513
+ // seriesIndex: -1,
514
+ // seriesLabel: '',
515
+ // groups: data.GroupDataMap.get(groupLabel) ?? [],
516
+ // // groups: [],
517
+ // groupIndex,
518
+ // groupLabel,
519
+ // event,
520
+ // data: data.computedData
521
+ // })
522
+ // })
523
+ // .on('mouseout', (event, datum) => {
524
+ // // event.stopPropagation()
525
+
526
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
527
+
528
+ // subject.event$.next({
529
+ // type: 'grid',
530
+ // pluginName: name,
531
+ // eventName: 'mouseout',
532
+ // highlightTarget: data.highlightTarget,
533
+ // datum: null,
534
+ // gridIndex: 0, // @Q@ 暫不處理
535
+ // series: [],
536
+ // seriesIndex: -1,
537
+ // seriesLabel: '',
538
+ // groups: data.GroupDataMap.get(groupLabel) ?? [],
539
+ // // groups: [],
540
+ // groupIndex,
541
+ // groupLabel,
542
+ // event,
543
+ // data: data.computedData
544
+ // })
545
+ // })
546
+ // .on('click', (event, datum) => {
547
+ // event.stopPropagation()
548
+
549
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
550
+
551
+ // subject.event$.next({
552
+ // type: 'grid',
553
+ // pluginName: name,
554
+ // eventName: 'click',
555
+ // highlightTarget: data.highlightTarget,
556
+ // datum: null,
557
+ // gridIndex: 0, // @Q@ 暫不處理
558
+ // series: [],
559
+ // seriesIndex: -1,
560
+ // seriesLabel: '',
561
+ // // groups: data.GroupDataMap.get(groupLabel) ?? [],
562
+ // groups: [],
563
+ // groupIndex,
564
+ // groupLabel,
565
+ // event,
566
+ // data: data.computedData
567
+ // })
568
+ // })
569
+
570
+ // // barSelection$.next(barSelection!)
571
+ // })
572
+
573
+ const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove').pipe(
574
+ takeUntil(destroy$),
575
+ )
576
+
577
+
578
+ // const mousemoveGroupLabel$ = combineLatest({
579
+ // rootMousemove: rootMousemove$,
580
+ // gridGroupPositionFn: gridGroupPositionFn$,
581
+ // }).pipe(
582
+ // takeUntil(destroy$),
583
+ // switchMap(async d => d),
584
+ // map(data => {
585
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(data.rootMousemove)
586
+ // return { groupIndex, groupLabel }
587
+ // }),
588
+ // shareReplay(1)
589
+ // )
590
+
591
+ const labelTransform$ = combineLatest({
592
+ fullParams: observer.fullParams$,
593
+ fullDataFormatter: observer.fullDataFormatter$,
594
+ gridAxesReverseTransform: observer.gridAxesReverseTransform$,
595
+ gridContainerPosition: observer.gridContainerPosition$
596
+ }).pipe(
597
+ takeUntil(destroy$),
598
+ switchMap(async d => d),
599
+ map(data => {
600
+ const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
601
+ const axisReverseRotateValue = `rotate(${data.gridAxesReverseTransform.rotate}deg) rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
602
+ const containerScaleReverseScaleValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
603
+ const tickTextRotateDeg = (data.fullDataFormatter.grid.groupAxis.position === 'left' && data.fullDataFormatter.grid.valueAxis.position === 'top')
604
+ || (data.fullDataFormatter.grid.groupAxis.position === 'right' && data.fullDataFormatter.grid.valueAxis.position === 'bottom')
605
+ ? data.fullParams.labelRotate + 180 // 修正文字倒轉
606
+ : data.fullParams.labelRotate
607
+ // ? 180 // 修正文字倒轉
608
+ // : 0
609
+
610
+ const textRotateValue = `rotate(${tickTextRotateDeg}deg)`
611
+
612
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
613
+ return `${axisReverseTranslateValue} ${axisReverseRotateValue} ${containerScaleReverseScaleValue} ${textRotateValue}`
614
+ }),
615
+ distinctUntilChanged()
616
+ )
617
+
618
+ const columnAmount$ = observer.gridContainerPosition$.pipe(
619
+ takeUntil(destroy$),
620
+ map(gridContainerPosition => {
621
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
622
+ return current.columnIndex > acc ? current.columnIndex : acc
623
+ }, 0)
624
+ return maxColumnIndex + 1
625
+ }),
626
+ distinctUntilChanged()
627
+ )
628
+
629
+ const rowAmount$ = observer.gridContainerPosition$.pipe(
630
+ takeUntil(destroy$),
631
+ map(gridContainerPosition => {
632
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
633
+ return current.rowIndex > acc ? current.rowIndex : acc
634
+ }, 0)
635
+ return maxRowIndex + 1
636
+ }),
637
+ distinctUntilChanged()
638
+ )
639
+
640
+ const gridGroupPosition$ = gridGroupPosition({
641
+ rootSelection,
642
+ fullDataFormatter$: observer.fullDataFormatter$,
643
+ gridAxesSize$: observer.gridAxesSize$,
644
+ computedData$: observer.computedData$,
645
+ fullChartParams$: observer.fullChartParams$,
646
+ gridContainerPosition$: observer.gridContainerPosition$,
647
+ layout$: observer.layout$
648
+ }).pipe(
649
+ takeUntil(destroy$)
650
+ )
651
+
652
+ combineLatest({
653
+ axesSelection: axesSelection$,
654
+ columnAmount: columnAmount$,
655
+ rowAmount: rowAmount$,
656
+ layout: observer.layout$,
657
+ rootMousemove: rootMousemove$,
658
+ // gridGroupPositionFn: gridGroupPositionFn$,
659
+ gridGroupPosition: gridGroupPosition$,
660
+ computedData: observer.computedData$,
661
+ groupScale: groupScale$,
662
+ gridAxesSize: observer.gridAxesSize$,
663
+ fullParams: observer.fullParams$,
664
+ fullDataFormatter: observer.fullDataFormatter$,
665
+ fullChartParams: observer.fullChartParams$,
666
+ highlightTarget: highlightTarget$,
667
+ // gridAxesReverseTransform: observer.gridAxesReverseTransform$,
668
+ labelTransform: labelTransform$,
669
+ GroupDataMap: observer.GroupDataMap$,
670
+ textSizePx: observer.textSizePx$
671
+ }).subscribe(data => {
672
+ // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
673
+ // const eventData = {
674
+ // offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
675
+ // offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
676
+ // }
677
+ // 依event的座標取得group資料
678
+ const { groupIndex, groupLabel } = data.gridGroupPosition
679
+ // console.log('gridGroupPosition', groupIndex, groupLabel)
680
+ const axisX = data.groupScale(groupIndex) ?? 0
681
+ // console.log('axisX', axisX)
682
+ const lineData = createLineData({
683
+ groupLabel: groupLabel,
684
+ axisX,
685
+ axisHeight: data.gridAxesSize.height,
686
+ fullParams: data.fullParams,
687
+ })
688
+ // console.log('lineData', lineData)
689
+ renderLine({
690
+ // selection: axisSelection,
691
+ selection: data.axesSelection,
692
+ pluginName: name,
693
+ lineData,
694
+ fullParams: data.fullParams,
695
+ fullChartParams: data.fullChartParams
696
+ })
697
+ const labelData = createLabelData({
698
+ groupLabel: groupLabel,
699
+ axisX,
700
+ fullParams: data.fullParams
701
+ })
702
+ const labelSelection = renderLabel({
703
+ // selection: axisSelection,
704
+ selection: data.axesSelection,
705
+ labelData,
706
+ fullParams: data.fullParams,
707
+ fullDataFormatter: data.fullDataFormatter,
708
+ fullChartParams: data.fullChartParams,
709
+ // gridAxesReverseTransformValue: data.gridAxesReverseTransform.value,
710
+ labelTransform: data.labelTransform,
711
+ textSizePx: data.textSizePx
712
+ })
713
+
714
+ // label的事件
715
+ labelSelection
716
+ .on('mouseover', (event, datum) => {
717
+ event.stopPropagation()
718
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
719
+
720
+ isLabelMouseover = true
721
+
722
+ subject.event$.next({
723
+ type: 'grid',
724
+ pluginName: name,
725
+ eventName: 'mouseover',
726
+ highlightTarget: data.highlightTarget,
727
+ datum: null,
728
+ gridIndex: 0, // @Q@ 暫不處理
729
+ series: [],
730
+ seriesIndex: -1,
731
+ seriesLabel: '',
732
+ groups: data.GroupDataMap.get(groupLabel) ?? [],
733
+ groupIndex,
734
+ groupLabel,
735
+ event,
736
+ data: data.computedData
737
+ })
738
+ })
739
+ .on('mousemove', (event, datum) => {
740
+ event.stopPropagation()
741
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
742
+
743
+ subject.event$.next({
744
+ type: 'grid',
745
+ pluginName: name,
746
+ eventName: 'mousemove',
747
+ highlightTarget: data.highlightTarget,
748
+ datum: null,
749
+ gridIndex: 0, // @Q@ 暫不處理
750
+ series: [],
751
+ seriesIndex: -1,
752
+ seriesLabel: '',
753
+ groups: data.GroupDataMap.get(groupLabel) ?? [],
754
+ groupIndex,
755
+ groupLabel,
756
+ event,
757
+ data: data.computedData
758
+ })
759
+ })
760
+ // .on('mouseout', (event, datum) => {
761
+ // event.stopPropagation()
762
+ // // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
763
+
764
+ // isLabelMouseover = false
765
+
766
+ // subject.event$.next({
767
+ // type: 'grid',
768
+ // pluginName: name,
769
+ // eventName: 'mouseout',
770
+ // highlightTarget: data.highlightTarget,
771
+ // datum: null,
772
+ // gridIndex: 0, // @Q@ 暫不處理
773
+ // series: [],
774
+ // seriesIndex: -1,
775
+ // seriesLabel: '',
776
+ // groups: data.GroupDataMap.get(groupLabel) ?? [],
777
+ // groupIndex,
778
+ // groupLabel,
779
+ // event,
780
+ // data: data.computedData
781
+ // })
782
+ // })
783
+ .on('click', (event, datum) => {
784
+ event.stopPropagation()
785
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
786
+
787
+ subject.event$.next({
788
+ type: 'grid',
789
+ pluginName: name,
790
+ eventName: 'click',
791
+ highlightTarget: data.highlightTarget,
792
+ datum: null,
793
+ gridIndex: 0, // @Q@ 暫不處理
794
+ series: [],
795
+ seriesIndex: -1,
796
+ seriesLabel: '',
797
+ groups: data.GroupDataMap.get(groupLabel) ?? [],
798
+ groupIndex,
799
+ groupLabel,
800
+ event,
801
+ data: data.computedData
802
+ })
803
+ })
804
+
805
+ })
806
+
807
+ // // -- highlight(無論highlightTarget設定為何,一律依從groupLabel來顯示) --
808
+ // combineLatest({
809
+ // event: subject.event$.pipe(
810
+ // filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove')
811
+ // ),
812
+ // computedData: observer.computedData$,
813
+ // groupScale: groupScale$,
814
+ // gridAxesSize: observer.gridAxesSize$,
815
+ // fullParams: observer.fullParams$,
816
+ // fullChartParams: observer.fullChartParams$,
817
+ // highlightTarget: highlightTarget$,
818
+ // gridAxesReverseTransform: observer.gridAxesReverseTransform$,
819
+ // GroupDataMap: observer.GroupDataMap$,
820
+ // gridGroupPositionFn: gridGroupPositionFn$,
821
+ // textSizePx: observer.textSizePx$
822
+ // }).pipe(
823
+ // takeUntil(destroy$),
824
+ // switchMap(async d => d)
825
+ // ).subscribe(data => {
826
+ // // const groups = data.event.eventName === 'mouseover' || data.event.eventName === 'mousemove'
827
+ // // ? data.event.groups
828
+ // // : []
829
+
830
+ // // const groupLabel = data.event.eventName === 'mouseover' || data.event.eventName === 'mousemove'
831
+ // // ? data.event.groupLabel
832
+ // // : ''
833
+ // const axisX = data.groupScale(data.event.groupLabel) ?? 0
834
+
835
+ // const lineData = createLineData({
836
+ // groupLabel: data.event.groupLabel,
837
+ // axisX,
838
+ // axisHeight: data.gridAxesSize.height,
839
+ // fullParams: data.fullParams,
840
+ // })
841
+ // renderLine({
842
+ // selection: axisSelection,
843
+ // pluginName: name,
844
+ // lineData,
845
+ // fullParams: data.fullParams,
846
+ // fullChartParams: data.fullChartParams
847
+ // })
848
+ // const labelData = createLabelData({
849
+ // groupLabel: data.event.groupLabel,
850
+ // axisX,
851
+ // fullParams: data.fullParams
852
+ // })
853
+ // const labelSelection = renderLabel({
854
+ // selection: axisSelection,
855
+ // labelData,
856
+ // fullParams: data.fullParams,
857
+ // fullChartParams: data.fullChartParams,
858
+ // gridAxesReverseTransformValue: data.gridAxesReverseTransform.value,
859
+ // textSizePx: data.textSizePx
860
+ // })
861
+
862
+ // // label的事件
863
+ // labelSelection
864
+ // .on('mouseover', (event, datum) => {
865
+
866
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
867
+
868
+ // subject.event$.next({
869
+ // type: 'grid',
870
+ // pluginName: name,
871
+ // eventName: 'mouseover',
872
+ // highlightTarget: data.highlightTarget,
873
+ // datum: null,
874
+ // gridIndex: 0, // @Q@ 暫不處理
875
+ // series: [],
876
+ // seriesIndex: -1,
877
+ // seriesLabel: '',
878
+ // groups: data.event.groups,
879
+ // groupIndex,
880
+ // groupLabel,
881
+ // event,
882
+ // data: data.computedData
883
+ // })
884
+ // })
885
+ // .on('mousemove', (event, datum) => {
886
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
887
+
888
+ // subject.event$.next({
889
+ // type: 'grid',
890
+ // pluginName: name,
891
+ // eventName: 'mousemove',
892
+ // highlightTarget: data.highlightTarget,
893
+ // datum: null,
894
+ // gridIndex: 0, // @Q@ 暫不處理
895
+ // series: [],
896
+ // seriesIndex: -1,
897
+ // seriesLabel: '',
898
+ // groups: data.event.groups,
899
+ // groupIndex,
900
+ // groupLabel,
901
+ // event,
902
+ // data: data.computedData
903
+ // })
904
+ // })
905
+ // .on('mouseout', (event, datum) => {
906
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
907
+
908
+ // subject.event$.next({
909
+ // type: 'grid',
910
+ // pluginName: name,
911
+ // eventName: 'mouseout',
912
+ // highlightTarget: data.highlightTarget,
913
+ // datum: null,
914
+ // gridIndex: 0, // @Q@ 暫不處理
915
+ // series: [],
916
+ // seriesIndex: -1,
917
+ // seriesLabel: '',
918
+ // groups: data.event.groups,
919
+ // groupIndex,
920
+ // groupLabel,
921
+ // event,
922
+ // data: data.computedData
923
+ // })
924
+ // })
925
+ // .on('click', (event, datum) => {
926
+ // const { groupIndex, groupLabel } = data.gridGroupPositionFn(event)
927
+
928
+ // subject.event$.next({
929
+ // type: 'grid',
930
+ // pluginName: name,
931
+ // eventName: 'click',
932
+ // highlightTarget: data.highlightTarget,
933
+ // datum: null,
934
+ // gridIndex: 0, // @Q@ 暫不處理
935
+ // series: [],
936
+ // seriesIndex: -1,
937
+ // seriesLabel: '',
938
+ // groups: data.event.groups,
939
+ // groupIndex,
940
+ // groupLabel,
941
+ // event,
942
+ // data: data.computedData
943
+ // })
944
+ // })
945
+ // })
946
+
947
+
948
+
949
+ const rootRectMouseout$ = d3EventObservable(rootRectSelection, 'mouseout').pipe(
950
+ takeUntil(destroy$),
951
+ )
952
+
953
+
954
+ combineLatest({
955
+ rootRectMouseout: rootRectMouseout$,
956
+ axesSelection: axesSelection$,
957
+ }).pipe(
958
+ takeUntil(destroy$),
959
+ switchMap(async d => d)
960
+ ).subscribe(data => {
961
+
962
+ setTimeout(() => {
963
+ // @Q@ workaround - 不知為何和 label 會有衝突,當滑鼠移動到 label 上時,會觸發 mouseout 事件
964
+ if (isLabelMouseover == true) {
965
+ return
966
+ }
967
+
968
+ removeLine(data.axesSelection)
969
+ removeLabel(data.axesSelection)
970
+ })
971
+ })
972
+
973
+ return () => {
974
+ destroy$.next(undefined)
975
+ rootRectSelection.remove()
976
+ }
923
977
  })