@orbcharts/plugins-basic 3.0.0-alpha.45 → 3.0.0-alpha.47

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +826 -791
  3. package/dist/orbcharts-plugins-basic.umd.js +7 -7
  4. package/dist/src/index.d.ts +5 -1
  5. package/dist/{orbcharts-plugins-basic/src → src}/series/seriesObservables.d.ts +4 -4
  6. package/package.json +42 -42
  7. package/src/base/BaseBarStack.ts +778 -778
  8. package/src/base/BaseBars.ts +764 -764
  9. package/src/base/BaseBarsTriangle.ts +672 -672
  10. package/src/base/BaseDots.ts +502 -502
  11. package/src/base/BaseGroupAxis.ts +496 -496
  12. package/src/base/BaseLegend.ts +641 -641
  13. package/src/base/BaseLineAreas.ts +625 -625
  14. package/src/base/BaseLines.ts +699 -699
  15. package/src/base/BaseValueAxis.ts +478 -478
  16. package/src/base/types.ts +2 -2
  17. package/src/grid/defaults.ts +121 -121
  18. package/src/grid/gridObservables.ts +247 -247
  19. package/src/grid/index.ts +15 -15
  20. package/src/grid/plugins/BarStack.ts +50 -50
  21. package/src/grid/plugins/Bars.ts +51 -51
  22. package/src/grid/plugins/BarsDiverging.ts +41 -41
  23. package/src/grid/plugins/BarsTriangle.ts +50 -50
  24. package/src/grid/plugins/Dots.ts +37 -37
  25. package/src/grid/plugins/GridLegend.ts +59 -59
  26. package/src/grid/plugins/GroupAux.ts +645 -645
  27. package/src/grid/plugins/GroupAxis.ts +42 -42
  28. package/src/grid/plugins/LineAreas.ts +39 -39
  29. package/src/grid/plugins/Lines.ts +38 -38
  30. package/src/grid/plugins/ScalingArea.ts +173 -173
  31. package/src/grid/plugins/ValueAxis.ts +43 -43
  32. package/src/grid/plugins/ValueStackAxis.ts +79 -79
  33. package/src/grid/types.ts +120 -120
  34. package/src/index.ts +9 -9
  35. package/src/multiGrid/defaults.ts +147 -147
  36. package/src/multiGrid/index.ts +11 -11
  37. package/src/multiGrid/multiGridObservables.ts +42 -42
  38. package/src/multiGrid/plugins/MultiBarStack.ts +78 -74
  39. package/src/multiGrid/plugins/MultiBars.ts +77 -73
  40. package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -73
  41. package/src/multiGrid/plugins/MultiDots.ts +65 -60
  42. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
  43. package/src/multiGrid/plugins/MultiGroupAxis.ts +69 -65
  44. package/src/multiGrid/plugins/MultiLineAreas.ts +67 -62
  45. package/src/multiGrid/plugins/MultiLines.ts +66 -61
  46. package/src/multiGrid/plugins/MultiValueAxis.ts +69 -65
  47. package/src/multiGrid/plugins/OverlappingValueAxes.ts +173 -169
  48. package/src/multiGrid/types.ts +67 -67
  49. package/src/noneData/defaults.ts +64 -64
  50. package/src/noneData/index.ts +3 -3
  51. package/src/noneData/plugins/Container.ts +10 -10
  52. package/src/noneData/plugins/Tooltip.ts +310 -310
  53. package/src/noneData/types.ts +26 -26
  54. package/src/series/defaults.ts +109 -109
  55. package/src/series/index.ts +6 -6
  56. package/src/series/plugins/Bubbles.ts +602 -571
  57. package/src/series/plugins/Pie.ts +563 -548
  58. package/src/series/plugins/PieEventTexts.ts +262 -258
  59. package/src/series/plugins/PieLabels.ts +339 -335
  60. package/src/series/plugins/SeriesLegend.ts +59 -59
  61. package/src/series/seriesObservables.ts +145 -145
  62. package/src/series/seriesUtils.ts +50 -50
  63. package/src/series/types.ts +67 -67
  64. package/src/tree/defaults.ts +22 -22
  65. package/src/tree/index.ts +3 -3
  66. package/src/tree/plugins/TreeLegend.ts +59 -59
  67. package/src/tree/plugins/TreeMap.ts +305 -305
  68. package/src/tree/types.ts +23 -23
  69. package/src/utils/commonUtils.ts +21 -21
  70. package/src/utils/d3Graphics.ts +124 -124
  71. package/src/utils/d3Utils.ts +73 -73
  72. package/src/utils/observables.ts +14 -14
  73. package/src/utils/orbchartsUtils.ts +100 -100
  74. package/tsconfig.dev.json +16 -16
  75. package/tsconfig.json +13 -16
  76. package/tsconfig.prod.json +13 -13
  77. package/vite.config.js +49 -49
  78. package/dist/orbcharts-plugins-basic/src/index.d.ts +0 -5
  79. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseBarStack.d.ts +0 -0
  80. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseBars.d.ts +0 -0
  81. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseBarsTriangle.d.ts +0 -0
  82. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseDots.d.ts +0 -0
  83. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseGroupArea.d.ts +0 -0
  84. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseGroupAxis.d.ts +0 -0
  85. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseLegend.d.ts +0 -0
  86. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseLineAreas.d.ts +0 -0
  87. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseLines.d.ts +0 -0
  88. /package/dist/{orbcharts-plugins-basic/src → src}/base/BaseValueAxis.d.ts +0 -0
  89. /package/dist/{orbcharts-plugins-basic/src → src}/base/types.d.ts +0 -0
  90. /package/dist/{orbcharts-plugins-basic/src → src}/grid/defaults.d.ts +0 -0
  91. /package/dist/{orbcharts-plugins-basic/src → src}/grid/gridObservables.d.ts +0 -0
  92. /package/dist/{orbcharts-plugins-basic/src → src}/grid/index.d.ts +0 -0
  93. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/BarStack.d.ts +0 -0
  94. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/Bars.d.ts +0 -0
  95. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/BarsDiverging.d.ts +0 -0
  96. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/BarsTriangle.d.ts +0 -0
  97. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/Dots.d.ts +0 -0
  98. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/GridLegend.d.ts +0 -0
  99. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/GroupAux.d.ts +0 -0
  100. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/GroupAxis.d.ts +0 -0
  101. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/LineAreas.d.ts +0 -0
  102. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/Lines.d.ts +0 -0
  103. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/Ranking.d.ts +0 -0
  104. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/RankingAxis.d.ts +0 -0
  105. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/ScalingArea.d.ts +0 -0
  106. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/ValueAxis.d.ts +0 -0
  107. /package/dist/{orbcharts-plugins-basic/src → src}/grid/plugins/ValueStackAxis.d.ts +0 -0
  108. /package/dist/{orbcharts-plugins-basic/src → src}/grid/types.d.ts +0 -0
  109. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/defaults.d.ts +0 -0
  110. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/index.d.ts +0 -0
  111. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/multiGridObservables.d.ts +0 -0
  112. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiBarStack.d.ts +0 -0
  113. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiBars.d.ts +0 -0
  114. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiBarsTriangle.d.ts +0 -0
  115. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiDots.d.ts +0 -0
  116. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiGridLegend.d.ts +0 -0
  117. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiGroupAxis.d.ts +0 -0
  118. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiLineAreas.d.ts +0 -0
  119. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiLines.d.ts +0 -0
  120. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/MultiValueAxis.d.ts +0 -0
  121. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/plugins/OverlappingValueAxes.d.ts +0 -0
  122. /package/dist/{orbcharts-plugins-basic/src → src}/multiGrid/types.d.ts +0 -0
  123. /package/dist/{orbcharts-plugins-basic/src → src}/multiValue/index.d.ts +0 -0
  124. /package/dist/{orbcharts-plugins-basic/src → src}/multiValue/plugins/Scatter.d.ts +0 -0
  125. /package/dist/{orbcharts-plugins-basic/src → src}/multiValue/plugins/ScatterAxes.d.ts +0 -0
  126. /package/dist/{orbcharts-plugins-basic/src → src}/noneData/defaults.d.ts +0 -0
  127. /package/dist/{orbcharts-plugins-basic/src → src}/noneData/index.d.ts +0 -0
  128. /package/dist/{orbcharts-plugins-basic/src → src}/noneData/plugins/Container.d.ts +0 -0
  129. /package/dist/{orbcharts-plugins-basic/src → src}/noneData/plugins/Tooltip.d.ts +0 -0
  130. /package/dist/{orbcharts-plugins-basic/src → src}/noneData/types.d.ts +0 -0
  131. /package/dist/{orbcharts-plugins-basic/src → src}/relationship/index.d.ts +0 -0
  132. /package/dist/{orbcharts-plugins-basic/src → src}/relationship/plugins/Relationship.d.ts +0 -0
  133. /package/dist/{orbcharts-plugins-basic/src → src}/series/defaults.d.ts +0 -0
  134. /package/dist/{orbcharts-plugins-basic/src → src}/series/index.d.ts +0 -0
  135. /package/dist/{orbcharts-plugins-basic/src → src}/series/plugins/Bubbles.d.ts +0 -0
  136. /package/dist/{orbcharts-plugins-basic/src → src}/series/plugins/Pie.d.ts +0 -0
  137. /package/dist/{orbcharts-plugins-basic/src → src}/series/plugins/PieEventTexts.d.ts +0 -0
  138. /package/dist/{orbcharts-plugins-basic/src → src}/series/plugins/PieLabels.d.ts +0 -0
  139. /package/dist/{orbcharts-plugins-basic/src → src}/series/plugins/SeriesLegend.d.ts +0 -0
  140. /package/dist/{orbcharts-plugins-basic/src → src}/series/plugins/Waffle.d.ts +0 -0
  141. /package/dist/{orbcharts-plugins-basic/src → src}/series/seriesUtils.d.ts +0 -0
  142. /package/dist/{orbcharts-plugins-basic/src → src}/series/types.d.ts +0 -0
  143. /package/dist/{orbcharts-plugins-basic/src → src}/tree/defaults.d.ts +0 -0
  144. /package/dist/{orbcharts-plugins-basic/src → src}/tree/index.d.ts +0 -0
  145. /package/dist/{orbcharts-plugins-basic/src → src}/tree/plugins/TreeLegend.d.ts +0 -0
  146. /package/dist/{orbcharts-plugins-basic/src → src}/tree/plugins/TreeMap.d.ts +0 -0
  147. /package/dist/{orbcharts-plugins-basic/src → src}/tree/types.d.ts +0 -0
  148. /package/dist/{orbcharts-plugins-basic/src → src}/utils/commonUtils.d.ts +0 -0
  149. /package/dist/{orbcharts-plugins-basic/src → src}/utils/d3Graphics.d.ts +0 -0
  150. /package/dist/{orbcharts-plugins-basic/src → src}/utils/d3Utils.d.ts +0 -0
  151. /package/dist/{orbcharts-plugins-basic/src → src}/utils/observables.d.ts +0 -0
  152. /package/dist/{orbcharts-plugins-basic/src → src}/utils/orbchartsUtils.d.ts +0 -0
  153. /package/dist/{orbcharts-plugins-basic/vite.config.d.ts → vite.config.d.ts} +0 -0
@@ -1,549 +1,564 @@
1
- import * as d3 from 'd3'
2
- import {
3
- combineLatest,
4
- map,
5
- switchMap,
6
- takeUntil,
7
- distinctUntilChanged,
8
- shareReplay,
9
- Observable,
10
- Subject } from 'rxjs'
11
- import type {
12
- ComputedDataSeries,
13
- ComputedDatumSeries,
14
- SeriesContainerPosition,
15
- ChartParams,
16
- EventSeries,
17
- Layout } from '@orbcharts/core'
18
- import type { PieDatum } from '../seriesUtils'
19
- import type { PieParams } from '../types'
20
- import {
21
- defineSeriesPlugin } from '@orbcharts/core'
22
- import { DEFAULT_PIE_PARAMS } from '../defaults'
23
- import { makePieData } from '../seriesUtils'
24
- import { getD3TransitionEase, makeD3Arc } from '../../utils/d3Utils'
25
- import { getClassName } from '../../utils/orbchartsUtils'
26
- import { seriesCenterSelectionObservable } from '../seriesObservables'
27
-
28
-
29
- const pluginName = 'Pie'
30
-
31
-
32
- function makeTweenPieRenderDataFn ({ enter, exit, data, lastTweenData, fullParams }: {
33
- enter: d3.Selection<d3.EnterElement, PieDatum, any, any>
34
- exit: d3.Selection<SVGPathElement, unknown, any, any>
35
- data: PieDatum[]
36
- lastTweenData: PieDatum[]
37
- fullParams: PieParams
38
- }): (t: number) => PieDatum[] {
39
- // 無更新資料項目則只計算資料變化 (新資料 * t + 舊資料 * (1 - t))
40
- if (!enter.size() && !exit.size()) {
41
- return (t: number) => {
42
- const tweenData: PieDatum[] = data.map((_d, _i) => {
43
- const lastDatum = lastTweenData[_i] ?? {
44
- startAngle: 0,
45
- endAngle: 0,
46
- value: 0
47
- }
48
- return {
49
- ..._d,
50
- startAngle: (_d.startAngle * t) + (lastDatum.startAngle * (1 - t)),
51
- endAngle: (_d.endAngle * t) + (lastDatum.endAngle * (1 - t)),
52
- value: (_d.value * t) + (lastDatum.value * (1 - t))
53
- }
54
- })
55
-
56
- return makePieRenderData(
57
- tweenData,
58
- fullParams.startAngle!,
59
- fullParams.endAngle!,
60
- 1
61
- )
62
- }
63
- // 有更新資料則重新繪圖
64
- } else {
65
- return (t: number) => {
66
- return makePieRenderData(
67
- data,
68
- fullParams.startAngle!,
69
- fullParams.endAngle!,
70
- t
71
- )
72
- }
73
- }
74
- }
75
-
76
- function makePieRenderData (data: PieDatum[], startAngle: number, endAngle: number, t: number): PieDatum[] {
77
- return data.map((d, i) => {
78
- const _startAngle = startAngle + (d.startAngle - startAngle) * t
79
- const _endAngle = _startAngle + (d.endAngle - d.startAngle) * t
80
- return {
81
- ...d,
82
- startAngle: _startAngle,
83
- endAngle: _endAngle
84
- }
85
- })
86
- }
87
-
88
- function renderPie ({ selection, data, arc, pathClassName }: {
89
- selection: d3.Selection<SVGGElement, unknown, any, unknown>
90
- data: PieDatum[]
91
- arc: d3.Arc<any, d3.DefaultArcObject>
92
- pathClassName: string
93
- }): d3.Selection<SVGPathElement, PieDatum, any, any> {
94
- // console.log('data', data)
95
- const pathSelection: d3.Selection<SVGPathElement, PieDatum, any, any> = selection
96
- .selectAll<SVGPathElement, PieDatum>('path')
97
- .data(data, d => d.id)
98
- .join('path')
99
- .classed(pathClassName, true)
100
- .style('cursor', 'pointer')
101
- .attr('fill', (d, i) => d.data.color)
102
- .attr('d', (d, i) => {
103
- return arc!(d as any)
104
- })
105
-
106
- return pathSelection
107
- }
108
-
109
- function highlight ({ pathSelection, ids, fullChartParams, arc, arcMouseover }: {
110
- pathSelection: d3.Selection<SVGPathElement, PieDatum, any, any>
111
- ids: string[]
112
- fullChartParams: ChartParams
113
- arc: d3.Arc<any, d3.DefaultArcObject>
114
- arcMouseover: d3.Arc<any, d3.DefaultArcObject>
115
- }) {
116
- pathSelection.interrupt('highlight')
117
-
118
- if (!ids.length) {
119
- // 取消放大
120
- pathSelection
121
- .transition('highlight')
122
- .style('opacity', 1)
123
- .attr('d', (d) => {
124
- return arc!(d as any)
125
- })
126
- return
127
- }
128
-
129
- pathSelection.each((d, i, n) => {
130
- const segment = d3.select(n[i])
131
-
132
- if (ids.includes(d.data.id)) {
133
- segment
134
- .style('opacity', 1)
135
- .transition('highlight')
136
- .ease(d3.easeElastic)
137
- .duration(500)
138
- .attr('d', (d: any) => {
139
- return arcMouseover!(d)
140
- })
141
- // .on('interrupt', () => {
142
- // // this.pathSelection!.select('path').attr('d', (d) => {
143
- // // return this.arc!(d as any)
144
- // // })
145
- // this.initHighlight()
146
- // })
147
- } else {
148
- // 取消放大
149
- segment
150
- .style('opacity', fullChartParams.styles.unhighlightedOpacity)
151
- .transition('highlight')
152
- .attr('d', (d) => {
153
- return arc!(d as any)
154
- })
155
- }
156
- })
157
- }
158
-
159
- // 各別的pie
160
- function createEachPie (pluginName: string, context: {
161
- containerSelection: d3.Selection<SVGGElement, any, any, unknown>
162
- computedData$: Observable<ComputedDatumSeries[][]>
163
- containerComputedLayoutData$: Observable<ComputedDatumSeries[]>
164
- SeriesDataMap$: Observable<Map<string, ComputedDatumSeries[]>>
165
- fullParams$: Observable<PieParams>
166
- fullChartParams$: Observable<ChartParams>
167
- seriesHighlight$: Observable<ComputedDatumSeries[]>
168
- seriesContainerPosition$: Observable<SeriesContainerPosition>
169
- event$: Subject<EventSeries>
170
- }) {
171
- const destroy$ = new Subject()
172
-
173
- const pathClassName = getClassName(pluginName, 'path')
174
-
175
- let lastTweenData: PieDatum[] = [] // 紀錄補間動畫前次的資料
176
- let tweenData: PieDatum[] = [] // 紀錄補間動畫用的資料
177
- // let originHighlight: Highlight | null = null
178
-
179
- // context.layout$
180
- // .pipe(
181
- // first()
182
- // )
183
- // .subscribe(size => {
184
- // selection
185
- // .attr('transform', `translate(${size.width / 2}, ${size.height / 2})`)
186
- // context.layout$
187
- // .pipe(
188
- // takeUntil(destroy$)
189
- // )
190
- // .subscribe(size => {
191
- // selection
192
- // .transition()
193
- // .attr('transform', `translate(${size.width / 2}, ${size.height / 2})`)
194
- // })
195
- // })
196
-
197
-
198
- const shorterSideWith$ = context.seriesContainerPosition$.pipe(
199
- takeUntil(destroy$),
200
- map(d => d.width < d.height ? d.width : d.height)
201
- )
202
-
203
- const pieData$: Observable<PieDatum[]> = new Observable(subscriber => {
204
- combineLatest({
205
- containerComputedLayoutData: context.containerComputedLayoutData$,
206
- fullParams: context.fullParams$,
207
- }).pipe(
208
- takeUntil(destroy$),
209
- switchMap(async (d) => d),
210
- ).subscribe(data => {
211
- // console.log('pieData', data)
212
- const pieData: PieDatum[] = makePieData({
213
- data: data.containerComputedLayoutData,
214
- startAngle: data.fullParams.startAngle,
215
- endAngle: data.fullParams.endAngle
216
- })
217
- // console.log('pieData', pieData)
218
- subscriber.next(pieData)
219
- })
220
- })
221
-
222
- // const SeriesDataMap$ = context.computedData$.pipe(
223
- // takeUntil(destroy$),
224
- // map(d => makeSeriesDataMap(d))
225
- // )
226
-
227
- const arc$: Observable<d3.Arc<any, d3.DefaultArcObject>> = new Observable(subscriber => {
228
- combineLatest({
229
- shorterSideWith: shorterSideWith$,
230
- fullParams: context.fullParams$,
231
- }).pipe(
232
- takeUntil(destroy$),
233
- switchMap(async (d) => d),
234
- ).subscribe(data => {
235
- const arc = makeD3Arc({
236
- axisWidth: data.shorterSideWith,
237
- innerRadius: data.fullParams.innerRadius,
238
- outerRadius: data.fullParams.outerRadius,
239
- padAngle: data.fullParams.padAngle,
240
- cornerRadius: data.fullParams.cornerRadius
241
- })
242
- subscriber.next(arc)
243
- })
244
- })
245
-
246
- const arcMouseover$: Observable<d3.Arc<any, d3.DefaultArcObject>> = new Observable(subscriber => {
247
- combineLatest({
248
- shorterSideWith: shorterSideWith$,
249
- fullParams: context.fullParams$,
250
- }).pipe(
251
- takeUntil(destroy$),
252
- switchMap(async (d) => d),
253
- ).subscribe(data => {
254
- const arcMouseover = makeD3Arc({
255
- axisWidth: data.shorterSideWith,
256
- innerRadius: data.fullParams.innerRadius,
257
- outerRadius: data.fullParams.outerMouseoverRadius, // 外半徑變化
258
- padAngle: data.fullParams.padAngle,
259
- cornerRadius: data.fullParams.cornerRadius
260
- })
261
- subscriber.next(arcMouseover)
262
- })
263
- })
264
-
265
- const highlightTarget$ = context.fullChartParams$.pipe(
266
- takeUntil(destroy$),
267
- map(d => d.highlightTarget),
268
- distinctUntilChanged()
269
- )
270
-
271
- const pathSelection$ = new Observable<d3.Selection<SVGPathElement, PieDatum, any, any>>(subscriber => {
272
- combineLatest({
273
- pieData: pieData$,
274
- arc: arc$,
275
- computedData: context.computedData$,
276
- fullParams: context.fullParams$,
277
- fullChartParams: context.fullChartParams$,
278
- highlightTarget: highlightTarget$
279
- }).pipe(
280
- takeUntil(destroy$),
281
- switchMap(async d => d)
282
- ).subscribe(data => {
283
- context.containerSelection.interrupt('graphicMove')
284
- // console.log('graphic', data)
285
- let update: d3.Selection<SVGPathElement, PieDatum, any, any> = context.containerSelection
286
- .selectAll<SVGPathElement, PieDatum>('path')
287
- .data(data.pieData, d => d.id)
288
- let enter = update.enter()
289
- let exit = update.exit()
290
-
291
- const makeTweenPieRenderData = makeTweenPieRenderDataFn({
292
- enter,
293
- exit,
294
- data: data.pieData,
295
- lastTweenData,
296
- fullParams: data.fullParams
297
- })
298
-
299
- // -- enter資料使用補間動畫 --
300
- enter
301
- .transition('graphicMove')
302
- .duration(data.fullChartParams.transitionDuration)
303
- .ease(getD3TransitionEase(data.fullChartParams.transitionEase))
304
- .tween('move', (self, t) => {
305
- return (t) => {
306
- tweenData = makeTweenPieRenderData(t)
307
-
308
- const pathSelection = renderPie({
309
- selection: context.containerSelection,
310
- data: tweenData,
311
- arc: data.arc,
312
- pathClassName
313
- })
314
-
315
- context.event$.next({
316
- type: 'series',
317
- pluginName,
318
- eventName: 'transitionMove',
319
- event: undefined,
320
- highlightTarget: data.highlightTarget,
321
- datum: null,
322
- series: [],
323
- seriesIndex: -1,
324
- seriesLabel: '',
325
- data: data.computedData
326
- })
327
- // const callbackData = makeEnterDurationCallbackData(data.computedData, )
328
- // enterDurationCallback(callbackData, t)
329
- }
330
- })
331
- .on('end', (self, t) => {
332
- tweenData = makePieRenderData(
333
- data.pieData,
334
- data.fullParams.startAngle,
335
- data.fullParams.endAngle,
336
- 1
337
- )
338
- // console.log('tweenData', tweenData)
339
- const pathSelection = renderPie({
340
- selection: context.containerSelection,
341
- data: tweenData,
342
- arc: data.arc,
343
- pathClassName
344
- })
345
-
346
- // if (data.fullParams.highlightTarget && data.fullParams.highlightTarget != 'none') {
347
- // if (data.fullChartParams.highlightTarget && data.fullChartParams.highlightTarget != 'none') {
348
- // pathSelection!.style('cursor', 'pointer')
349
- // }
350
-
351
- subscriber.next(pathSelection)
352
-
353
- // pathSelection && setPathEvent({
354
- // pathSelection,
355
- // pluginName: name,
356
- // data: data.computedData,
357
- // fullChartParams: data.fullChartParams,
358
- // arc: data.arc,
359
- // arcMouseover: data.arcMouseover,
360
- // SeriesDataMap: data.SeriesDataMap,
361
- // event$: store.event$
362
- // })
363
-
364
- // 渲染完後紀錄為前次的資料
365
- lastTweenData = Object.assign([], data.pieData)
366
-
367
- context.event$.next({
368
- type: 'series',
369
- pluginName,
370
- eventName: 'transitionEnd',
371
- event: undefined,
372
- highlightTarget: data.highlightTarget,
373
- datum: null,
374
- series: [],
375
- seriesIndex: -1,
376
- seriesLabel: '',
377
- data: data.computedData
378
- })
379
-
380
-
381
- })
382
-
383
- // -- 更新資料 --
384
- if (!enter.size() && update.size() > 0) {
385
- // console.log('test')
386
- const pathSelection = renderPie({
387
- selection: context.containerSelection,
388
- data: data.pieData,
389
- arc: data.arc,
390
- pathClassName
391
- })
392
- subscriber.next(pathSelection)
393
- }
394
- })
395
- })
396
-
397
- combineLatest({
398
- pathSelection: pathSelection$,
399
- SeriesDataMap: context.SeriesDataMap$,
400
- computedData: context.computedData$,
401
- highlightTarget: highlightTarget$
402
- }).pipe(
403
- takeUntil(destroy$),
404
- switchMap(async d => d)
405
- ).subscribe(data => {
406
- data.pathSelection
407
- .on('mouseover', (event, pieDatum) => {
408
- event.stopPropagation()
409
-
410
- context.event$.next({
411
- type: 'series',
412
- eventName: 'mouseover',
413
- pluginName,
414
- highlightTarget: data.highlightTarget,
415
- datum: pieDatum.data,
416
- series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
417
- seriesIndex: pieDatum.data.seriesIndex,
418
- seriesLabel: pieDatum.data.seriesLabel,
419
- event,
420
- data: data.computedData
421
- })
422
- })
423
- .on('mousemove', (event, pieDatum) => {
424
- event.stopPropagation()
425
-
426
- context.event$.next({
427
- type: 'series',
428
- eventName: 'mousemove',
429
- pluginName,
430
- highlightTarget: data.highlightTarget,
431
- datum: pieDatum.data,
432
- series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
433
- seriesIndex: pieDatum.data.seriesIndex,
434
- seriesLabel: pieDatum.data.seriesLabel,
435
- event,
436
- data: data.computedData,
437
- })
438
- })
439
- .on('mouseout', (event, pieDatum) => {
440
- event.stopPropagation()
441
-
442
- context.event$.next({
443
- type: 'series',
444
- eventName: 'mouseout',
445
- pluginName,
446
- highlightTarget: data.highlightTarget,
447
- datum: pieDatum.data,
448
- series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
449
- seriesIndex: pieDatum.data.seriesIndex,
450
- seriesLabel: pieDatum.data.seriesLabel,
451
- event,
452
- data: data.computedData,
453
- })
454
- })
455
- .on('click', (event, pieDatum) => {
456
- event.stopPropagation()
457
-
458
- context.event$.next({
459
- type: 'series',
460
- eventName: 'click',
461
- pluginName,
462
- highlightTarget: data.highlightTarget,
463
- datum: pieDatum.data,
464
- series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
465
- seriesIndex: pieDatum.data.seriesIndex,
466
- seriesLabel: pieDatum.data.seriesLabel,
467
- event,
468
- data: data.computedData,
469
- })
470
- })
471
- })
472
-
473
- combineLatest({
474
- pathSelection: pathSelection$,
475
- highlight: context.seriesHighlight$.pipe(
476
- map(data => data.map(d => d.id))
477
- ),
478
- fullChartParams: context.fullChartParams$,
479
- arc: arc$,
480
- arcMouseover: arcMouseover$
481
- }).pipe(
482
- takeUntil(destroy$),
483
- switchMap(async d => d)
484
- ).subscribe(data => {
485
- highlight({
486
- pathSelection: data.pathSelection,
487
- ids: data.highlight,
488
- fullChartParams: data.fullChartParams,
489
- arc: data.arc,
490
- arcMouseover: data.arcMouseover
491
- })
492
- })
493
-
494
- return () => {
495
- destroy$.next(undefined)
496
- }
497
- }
498
-
499
- export const Pie = defineSeriesPlugin(pluginName, DEFAULT_PIE_PARAMS)(({ selection, name, subject, observer }) => {
500
- const destroy$ = new Subject()
501
-
502
- const { seriesCenterSelection$ } = seriesCenterSelectionObservable({
503
- selection: selection,
504
- pluginName,
505
- seriesSeparate$: observer.seriesSeparate$,
506
- seriesLabels$: observer.seriesLabels$,
507
- seriesContainerPosition$: observer.seriesContainerPosition$
508
- })
509
-
510
- const unsubscribeFnArr: (() => void)[] = []
511
-
512
- seriesCenterSelection$.subscribe(seriesCenterSelection => {
513
- // 每次重新計算時,清除之前的訂閱
514
- unsubscribeFnArr.forEach(fn => fn())
515
-
516
- seriesCenterSelection.each((d, containerIndex, g) => {
517
-
518
- const containerSelection = d3.select(g[containerIndex])
519
-
520
- const containerComputedLayoutData$ = observer.computedLayoutData$.pipe(
521
- takeUntil(destroy$),
522
- map(data => data[containerIndex] ?? data[0])
523
- )
524
-
525
- const containerPosition$ = observer.seriesContainerPosition$.pipe(
526
- takeUntil(destroy$),
527
- map(data => data[containerIndex] ?? data[0])
528
- )
529
-
530
- unsubscribeFnArr[containerIndex] = createEachPie(pluginName, {
531
- containerSelection: containerSelection,
532
- computedData$: observer.computedData$,
533
- containerComputedLayoutData$: containerComputedLayoutData$,
534
- SeriesDataMap$: observer.SeriesDataMap$,
535
- fullParams$: observer.fullParams$,
536
- fullChartParams$: observer.fullChartParams$,
537
- seriesHighlight$: observer.seriesHighlight$,
538
- seriesContainerPosition$: containerPosition$,
539
- event$: subject.event$,
540
- })
541
-
542
- })
543
- })
544
-
545
- return () => {
546
- destroy$.next(undefined)
547
- unsubscribeFnArr.forEach(fn => fn())
548
- }
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ switchMap,
6
+ takeUntil,
7
+ distinctUntilChanged,
8
+ shareReplay,
9
+ Observable,
10
+ Subject } from 'rxjs'
11
+ import type {
12
+ ComputedDataSeries,
13
+ ComputedDatumSeries,
14
+ SeriesContainerPosition,
15
+ ChartParams,
16
+ EventSeries,
17
+ Layout } from '@orbcharts/core'
18
+ import type { PieDatum } from '../seriesUtils'
19
+ import type { PieParams } from '../types'
20
+ import {
21
+ defineSeriesPlugin } from '@orbcharts/core'
22
+ import { DEFAULT_PIE_PARAMS } from '../defaults'
23
+ import { makePieData } from '../seriesUtils'
24
+ import { getD3TransitionEase, makeD3Arc } from '../../utils/d3Utils'
25
+ import { getClassName } from '../../utils/orbchartsUtils'
26
+ import { seriesCenterSelectionObservable } from '../seriesObservables'
27
+
28
+
29
+ const pluginName = 'Pie'
30
+
31
+
32
+ function makeTweenPieRenderDataFn ({ enter, exit, data, lastTweenData, fullParams }: {
33
+ enter: d3.Selection<d3.EnterElement, PieDatum, any, any>
34
+ exit: d3.Selection<SVGPathElement, unknown, any, any>
35
+ data: PieDatum[]
36
+ lastTweenData: PieDatum[]
37
+ fullParams: PieParams
38
+ }): (t: number) => PieDatum[] {
39
+ // 無更新資料項目則只計算資料變化 (新資料 * t + 舊資料 * (1 - t))
40
+ if (!enter.size() && !exit.size()) {
41
+ // console.log('case1')
42
+ return (t: number) => {
43
+ const tweenData: PieDatum[] = data.map((_d, _i) => {
44
+ const lastDatum = lastTweenData[_i] ?? {
45
+ startAngle: 0,
46
+ endAngle: 0,
47
+ value: 0
48
+ }
49
+ return {
50
+ ..._d,
51
+ startAngle: (_d.startAngle * t) + (lastDatum.startAngle * (1 - t)),
52
+ endAngle: (_d.endAngle * t) + (lastDatum.endAngle * (1 - t)),
53
+ value: (_d.value * t) + (lastDatum.value * (1 - t))
54
+ }
55
+ })
56
+
57
+ return makePieRenderData(
58
+ tweenData,
59
+ fullParams.startAngle!,
60
+ fullParams.endAngle!,
61
+ 1
62
+ )
63
+ }
64
+ // 有更新資料則重新繪圖
65
+ } else {
66
+ // console.log('case2')
67
+ return (t: number) => {
68
+ return makePieRenderData(
69
+ data,
70
+ fullParams.startAngle!,
71
+ fullParams.endAngle!,
72
+ t
73
+ )
74
+ }
75
+ }
76
+ }
77
+
78
+ function makePieRenderData (data: PieDatum[], startAngle: number, endAngle: number, t: number): PieDatum[] {
79
+ return data.map((d, i) => {
80
+ const _startAngle = startAngle + (d.startAngle - startAngle) * t
81
+ const _endAngle = _startAngle + (d.endAngle - d.startAngle) * t
82
+ return {
83
+ ...d,
84
+ startAngle: _startAngle,
85
+ endAngle: _endAngle
86
+ }
87
+ })
88
+ }
89
+
90
+ function renderPie ({ selection, data, arc, pathClassName }: {
91
+ selection: d3.Selection<SVGGElement, unknown, any, unknown>
92
+ data: PieDatum[]
93
+ arc: d3.Arc<any, d3.DefaultArcObject>
94
+ pathClassName: string
95
+ }): d3.Selection<SVGPathElement, PieDatum, any, any> {
96
+ // console.log('data', data)
97
+ const pathSelection: d3.Selection<SVGPathElement, PieDatum, any, any> = selection
98
+ .selectAll<SVGPathElement, PieDatum>('path')
99
+ .data(data, d => d.id)
100
+ .join('path')
101
+ .classed(pathClassName, true)
102
+ .style('cursor', 'pointer')
103
+ .attr('fill', (d, i) => d.data.color)
104
+ .attr('d', (d, i) => {
105
+ return arc!(d as any)
106
+ })
107
+
108
+ return pathSelection
109
+ }
110
+
111
+ function highlight ({ pathSelection, ids, fullChartParams, arc, arcMouseover }: {
112
+ pathSelection: d3.Selection<SVGPathElement, PieDatum, any, any>
113
+ ids: string[]
114
+ fullChartParams: ChartParams
115
+ arc: d3.Arc<any, d3.DefaultArcObject>
116
+ arcMouseover: d3.Arc<any, d3.DefaultArcObject>
117
+ }) {
118
+ pathSelection.interrupt('highlight')
119
+
120
+ if (!ids.length) {
121
+ // 取消放大
122
+ pathSelection
123
+ .transition('highlight')
124
+ .style('opacity', 1)
125
+ .attr('d', (d) => {
126
+ return arc!(d as any)
127
+ })
128
+ return
129
+ }
130
+
131
+ pathSelection.each((d, i, n) => {
132
+ const segment = d3.select(n[i])
133
+
134
+ if (ids.includes(d.data.id)) {
135
+ segment
136
+ .style('opacity', 1)
137
+ .transition('highlight')
138
+ .ease(d3.easeElastic)
139
+ .duration(500)
140
+ .attr('d', (d: any) => {
141
+ return arcMouseover!(d)
142
+ })
143
+ // .on('interrupt', () => {
144
+ // // this.pathSelection!.select('path').attr('d', (d) => {
145
+ // // return this.arc!(d as any)
146
+ // // })
147
+ // this.initHighlight()
148
+ // })
149
+ } else {
150
+ // 取消放大
151
+ segment
152
+ .style('opacity', fullChartParams.styles.unhighlightedOpacity)
153
+ .transition('highlight')
154
+ .attr('d', (d) => {
155
+ return arc!(d as any)
156
+ })
157
+ }
158
+ })
159
+ }
160
+
161
+ // 各別的pie
162
+ function createEachPie (pluginName: string, context: {
163
+ containerSelection: d3.Selection<SVGGElement, any, any, unknown>
164
+ computedData$: Observable<ComputedDatumSeries[][]>
165
+ containerComputedLayoutData$: Observable<ComputedDatumSeries[]>
166
+ SeriesDataMap$: Observable<Map<string, ComputedDatumSeries[]>>
167
+ fullParams$: Observable<PieParams>
168
+ fullChartParams$: Observable<ChartParams>
169
+ seriesHighlight$: Observable<ComputedDatumSeries[]>
170
+ seriesContainerPosition$: Observable<SeriesContainerPosition>
171
+ event$: Subject<EventSeries>
172
+ }) {
173
+ const destroy$ = new Subject()
174
+
175
+ const pathClassName = getClassName(pluginName, 'path')
176
+
177
+ let lastTweenData: PieDatum[] = [] // 紀錄補間動畫前次的資料
178
+ let tweenData: PieDatum[] = [] // 紀錄補間動畫用的資料
179
+ // let originHighlight: Highlight | null = null
180
+
181
+ // context.layout$
182
+ // .pipe(
183
+ // first()
184
+ // )
185
+ // .subscribe(size => {
186
+ // selection
187
+ // .attr('transform', `translate(${size.width / 2}, ${size.height / 2})`)
188
+ // context.layout$
189
+ // .pipe(
190
+ // takeUntil(destroy$)
191
+ // )
192
+ // .subscribe(size => {
193
+ // selection
194
+ // .transition()
195
+ // .attr('transform', `translate(${size.width / 2}, ${size.height / 2})`)
196
+ // })
197
+ // })
198
+
199
+
200
+ const shorterSideWith$ = context.seriesContainerPosition$.pipe(
201
+ takeUntil(destroy$),
202
+ map(d => d.width < d.height ? d.width : d.height)
203
+ )
204
+
205
+ const pieData$: Observable<PieDatum[]> = new Observable(subscriber => {
206
+ combineLatest({
207
+ containerComputedLayoutData: context.containerComputedLayoutData$,
208
+ fullParams: context.fullParams$,
209
+ }).pipe(
210
+ takeUntil(destroy$),
211
+ switchMap(async (d) => d),
212
+ ).subscribe(data => {
213
+ // console.log('pieData', data)
214
+ const pieData: PieDatum[] = makePieData({
215
+ data: data.containerComputedLayoutData,
216
+ startAngle: data.fullParams.startAngle,
217
+ endAngle: data.fullParams.endAngle
218
+ })
219
+ // console.log('pieData', pieData)
220
+ subscriber.next(pieData)
221
+ })
222
+ })
223
+
224
+ // const SeriesDataMap$ = context.computedData$.pipe(
225
+ // takeUntil(destroy$),
226
+ // map(d => makeSeriesDataMap(d))
227
+ // )
228
+
229
+ const arc$: Observable<d3.Arc<any, d3.DefaultArcObject>> = new Observable(subscriber => {
230
+ combineLatest({
231
+ shorterSideWith: shorterSideWith$,
232
+ fullParams: context.fullParams$,
233
+ }).pipe(
234
+ takeUntil(destroy$),
235
+ switchMap(async (d) => d),
236
+ ).subscribe(data => {
237
+ const arc = makeD3Arc({
238
+ axisWidth: data.shorterSideWith,
239
+ innerRadius: data.fullParams.innerRadius,
240
+ outerRadius: data.fullParams.outerRadius,
241
+ padAngle: data.fullParams.padAngle,
242
+ cornerRadius: data.fullParams.cornerRadius
243
+ })
244
+ subscriber.next(arc)
245
+ })
246
+ })
247
+
248
+ const arcMouseover$: Observable<d3.Arc<any, d3.DefaultArcObject>> = new Observable(subscriber => {
249
+ combineLatest({
250
+ shorterSideWith: shorterSideWith$,
251
+ fullParams: context.fullParams$,
252
+ }).pipe(
253
+ takeUntil(destroy$),
254
+ switchMap(async (d) => d),
255
+ ).subscribe(data => {
256
+ const arcMouseover = makeD3Arc({
257
+ axisWidth: data.shorterSideWith,
258
+ innerRadius: data.fullParams.innerRadius,
259
+ outerRadius: data.fullParams.outerMouseoverRadius, // 外半徑變化
260
+ padAngle: data.fullParams.padAngle,
261
+ cornerRadius: data.fullParams.cornerRadius
262
+ })
263
+ subscriber.next(arcMouseover)
264
+ })
265
+ })
266
+
267
+ const highlightTarget$ = context.fullChartParams$.pipe(
268
+ takeUntil(destroy$),
269
+ map(d => d.highlightTarget),
270
+ distinctUntilChanged()
271
+ )
272
+
273
+ const pathSelection$ = new Observable<d3.Selection<SVGPathElement, PieDatum, any, any>>(subscriber => {
274
+ combineLatest({
275
+ pieData: pieData$,
276
+ arc: arc$,
277
+ computedData: context.computedData$,
278
+ fullParams: context.fullParams$,
279
+ fullChartParams: context.fullChartParams$,
280
+ highlightTarget: highlightTarget$
281
+ }).pipe(
282
+ takeUntil(destroy$),
283
+ switchMap(async d => d)
284
+ ).subscribe(data => {
285
+ context.containerSelection.interrupt('graphicMove')
286
+ // console.log('graphic', data)
287
+ const update: d3.Selection<SVGPathElement, PieDatum, any, any> = context.containerSelection
288
+ .selectAll<SVGPathElement, PieDatum>('path')
289
+ .data(data.pieData, d => d.id)
290
+ const enter = update.enter()
291
+ const exit = update.exit()
292
+
293
+ const makeTweenPieRenderData = makeTweenPieRenderDataFn({
294
+ enter,
295
+ exit,
296
+ data: data.pieData,
297
+ lastTweenData,
298
+ fullParams: data.fullParams
299
+ })
300
+
301
+ // -- 使用補間動畫 --
302
+ context.containerSelection
303
+ .transition('graphicMove')
304
+ .duration(data.fullChartParams.transitionDuration)
305
+ // .ease(getD3TransitionEase(data.fullChartParams.transitionEase))
306
+ .tween('move', (self, t) => {
307
+ return (t) => {
308
+ tweenData = makeTweenPieRenderData(t)
309
+
310
+ const pathSelection = renderPie({
311
+ selection: context.containerSelection,
312
+ data: tweenData,
313
+ arc: data.arc,
314
+ pathClassName
315
+ })
316
+
317
+ // @Q@ 想盡量減清效能負擔所以取消掉
318
+ // context.event$.next({
319
+ // type: 'series',
320
+ // pluginName,
321
+ // eventName: 'transitionMove',
322
+ // event: undefined,
323
+ // highlightTarget: data.highlightTarget,
324
+ // datum: null,
325
+ // series: [],
326
+ // seriesIndex: -1,
327
+ // seriesLabel: '',
328
+ // data: data.computedData
329
+ // })
330
+
331
+ // const callbackData = makeEnterDurationCallbackData(data.computedData, )
332
+ // enterDurationCallback(callbackData, t)
333
+ }
334
+ })
335
+ .on('end', (self, t) => {
336
+ tweenData = makePieRenderData(
337
+ data.pieData,
338
+ data.fullParams.startAngle,
339
+ data.fullParams.endAngle,
340
+ 1
341
+ )
342
+ // console.log('tweenData', tweenData)
343
+ const pathSelection = renderPie({
344
+ selection: context.containerSelection,
345
+ data: tweenData,
346
+ arc: data.arc,
347
+ pathClassName
348
+ })
349
+
350
+ // if (data.fullParams.highlightTarget && data.fullParams.highlightTarget != 'none') {
351
+ // if (data.fullChartParams.highlightTarget && data.fullChartParams.highlightTarget != 'none') {
352
+ // pathSelection!.style('cursor', 'pointer')
353
+ // }
354
+
355
+ subscriber.next(pathSelection)
356
+
357
+ // pathSelection && setPathEvent({
358
+ // pathSelection,
359
+ // pluginName: name,
360
+ // data: data.computedData,
361
+ // fullChartParams: data.fullChartParams,
362
+ // arc: data.arc,
363
+ // arcMouseover: data.arcMouseover,
364
+ // SeriesDataMap: data.SeriesDataMap,
365
+ // event$: store.event$
366
+ // })
367
+
368
+ // 渲染完後紀錄為前次的資料
369
+ lastTweenData = Object.assign([], data.pieData)
370
+
371
+ context.event$.next({
372
+ type: 'series',
373
+ pluginName,
374
+ eventName: 'transitionEnd',
375
+ event: undefined,
376
+ highlightTarget: data.highlightTarget,
377
+ datum: null,
378
+ series: [],
379
+ seriesIndex: -1,
380
+ seriesLabel: '',
381
+ data: data.computedData
382
+ })
383
+
384
+
385
+ })
386
+
387
+ // -- 更新資料 --
388
+ if (!enter.size() && update.size() > 0) {
389
+ // console.log('test')
390
+ const pathSelection = renderPie({
391
+ selection: context.containerSelection,
392
+ data: data.pieData,
393
+ arc: data.arc,
394
+ pathClassName
395
+ })
396
+ subscriber.next(pathSelection)
397
+ }
398
+ })
399
+ })
400
+
401
+ combineLatest({
402
+ pathSelection: pathSelection$,
403
+ SeriesDataMap: context.SeriesDataMap$,
404
+ computedData: context.computedData$,
405
+ highlightTarget: highlightTarget$
406
+ }).pipe(
407
+ takeUntil(destroy$),
408
+ switchMap(async d => d)
409
+ ).subscribe(data => {
410
+ data.pathSelection
411
+ .on('mouseover', (event, pieDatum) => {
412
+ event.stopPropagation()
413
+
414
+ context.event$.next({
415
+ type: 'series',
416
+ eventName: 'mouseover',
417
+ pluginName,
418
+ highlightTarget: data.highlightTarget,
419
+ datum: pieDatum.data,
420
+ series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
421
+ seriesIndex: pieDatum.data.seriesIndex,
422
+ seriesLabel: pieDatum.data.seriesLabel,
423
+ event,
424
+ data: data.computedData
425
+ })
426
+ })
427
+ .on('mousemove', (event, pieDatum) => {
428
+ event.stopPropagation()
429
+
430
+ context.event$.next({
431
+ type: 'series',
432
+ eventName: 'mousemove',
433
+ pluginName,
434
+ highlightTarget: data.highlightTarget,
435
+ datum: pieDatum.data,
436
+ series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
437
+ seriesIndex: pieDatum.data.seriesIndex,
438
+ seriesLabel: pieDatum.data.seriesLabel,
439
+ event,
440
+ data: data.computedData,
441
+ })
442
+ })
443
+ .on('mouseout', (event, pieDatum) => {
444
+ event.stopPropagation()
445
+
446
+ context.event$.next({
447
+ type: 'series',
448
+ eventName: 'mouseout',
449
+ pluginName,
450
+ highlightTarget: data.highlightTarget,
451
+ datum: pieDatum.data,
452
+ series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
453
+ seriesIndex: pieDatum.data.seriesIndex,
454
+ seriesLabel: pieDatum.data.seriesLabel,
455
+ event,
456
+ data: data.computedData,
457
+ })
458
+ })
459
+ .on('click', (event, pieDatum) => {
460
+ event.stopPropagation()
461
+
462
+ context.event$.next({
463
+ type: 'series',
464
+ eventName: 'click',
465
+ pluginName,
466
+ highlightTarget: data.highlightTarget,
467
+ datum: pieDatum.data,
468
+ series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
469
+ seriesIndex: pieDatum.data.seriesIndex,
470
+ seriesLabel: pieDatum.data.seriesLabel,
471
+ event,
472
+ data: data.computedData,
473
+ })
474
+ })
475
+ })
476
+
477
+ combineLatest({
478
+ pathSelection: pathSelection$,
479
+ highlight: context.seriesHighlight$.pipe(
480
+ map(data => data.map(d => d.id))
481
+ ),
482
+ fullChartParams: context.fullChartParams$,
483
+ arc: arc$,
484
+ arcMouseover: arcMouseover$
485
+ }).pipe(
486
+ takeUntil(destroy$),
487
+ switchMap(async d => d)
488
+ ).subscribe(data => {
489
+ highlight({
490
+ pathSelection: data.pathSelection,
491
+ ids: data.highlight,
492
+ fullChartParams: data.fullChartParams,
493
+ arc: data.arc,
494
+ arcMouseover: data.arcMouseover
495
+ })
496
+ })
497
+
498
+ return () => {
499
+ destroy$.next(undefined)
500
+ }
501
+ }
502
+
503
+ export const Pie = defineSeriesPlugin(pluginName, DEFAULT_PIE_PARAMS)(({ selection, name, subject, observer }) => {
504
+ const destroy$ = new Subject()
505
+
506
+ const { seriesCenterSelection$ } = seriesCenterSelectionObservable({
507
+ selection: selection,
508
+ pluginName,
509
+ separateSeries$: observer.separateSeries$,
510
+ seriesLabels$: observer.seriesLabels$,
511
+ seriesContainerPosition$: observer.seriesContainerPosition$
512
+ })
513
+
514
+ const unsubscribeFnArr: (() => void)[] = []
515
+
516
+ // @Q@ 在seriesCenterSelection$之後才訂閱會造成fullParams$訂閱不到最初次的值,還需找時間研究先workaround
517
+ observer.fullParams$.subscribe()
518
+
519
+ seriesCenterSelection$
520
+ .pipe(
521
+ takeUntil(destroy$)
522
+ )
523
+ .subscribe(seriesCenterSelection => {
524
+ // 每次重新計算時,清除之前的訂閱
525
+ unsubscribeFnArr.forEach(fn => fn())
526
+
527
+ // observer.fullParams$.subscribe(data => {
528
+ // console.log('observer.fullParams$', data)
529
+ // })
530
+
531
+ seriesCenterSelection.each((d, containerIndex, g) => {
532
+ // console.log('containerIndex', containerIndex)
533
+ const containerSelection = d3.select(g[containerIndex])
534
+
535
+ const containerComputedLayoutData$ = observer.computedLayoutData$.pipe(
536
+ takeUntil(destroy$),
537
+ map(data => data[containerIndex] ?? data[0])
538
+ )
539
+
540
+ const containerPosition$ = observer.seriesContainerPosition$.pipe(
541
+ takeUntil(destroy$),
542
+ map(data => data[containerIndex] ?? data[0])
543
+ )
544
+
545
+ unsubscribeFnArr[containerIndex] = createEachPie(pluginName, {
546
+ containerSelection: containerSelection,
547
+ computedData$: observer.computedData$,
548
+ containerComputedLayoutData$: containerComputedLayoutData$,
549
+ SeriesDataMap$: observer.SeriesDataMap$,
550
+ fullParams$: observer.fullParams$,
551
+ fullChartParams$: observer.fullChartParams$,
552
+ seriesHighlight$: observer.seriesHighlight$,
553
+ seriesContainerPosition$: containerPosition$,
554
+ event$: subject.event$,
555
+ })
556
+
557
+ })
558
+ })
559
+
560
+ return () => {
561
+ destroy$.next(undefined)
562
+ unsubscribeFnArr.forEach(fn => fn())
563
+ }
549
564
  })