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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +7064 -7067
  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 -167
  52. package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +168 -168
  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
  })