@orbcharts/plugins-basic 3.0.0-alpha.60 → 3.0.0-alpha.62

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +1 -1
  3. package/dist/orbcharts-plugins-basic.umd.js +1 -1
  4. package/package.json +42 -42
  5. package/src/base/BaseBarStack.ts +778 -778
  6. package/src/base/BaseBars.ts +764 -764
  7. package/src/base/BaseBarsTriangle.ts +672 -672
  8. package/src/base/BaseDots.ts +513 -513
  9. package/src/base/BaseGroupAxis.ts +558 -558
  10. package/src/base/BaseLegend.ts +641 -641
  11. package/src/base/BaseLineAreas.ts +628 -628
  12. package/src/base/BaseLines.ts +704 -704
  13. package/src/base/BaseValueAxis.ts +480 -478
  14. package/src/base/types.ts +2 -2
  15. package/src/grid/defaults.ts +128 -128
  16. package/src/grid/gridObservables.ts +541 -541
  17. package/src/grid/index.ts +15 -15
  18. package/src/grid/plugins/BarStack.ts +43 -43
  19. package/src/grid/plugins/Bars.ts +44 -44
  20. package/src/grid/plugins/BarsPN.ts +41 -41
  21. package/src/grid/plugins/BarsTriangle.ts +42 -42
  22. package/src/grid/plugins/Dots.ts +37 -37
  23. package/src/grid/plugins/GridLegend.ts +59 -59
  24. package/src/grid/plugins/GroupAux.ts +976 -976
  25. package/src/grid/plugins/GroupAxis.ts +35 -35
  26. package/src/grid/plugins/LineAreas.ts +40 -40
  27. package/src/grid/plugins/Lines.ts +40 -40
  28. package/src/grid/plugins/ScalingArea.ts +173 -173
  29. package/src/grid/plugins/ValueAxis.ts +36 -36
  30. package/src/grid/plugins/ValueStackAxis.ts +38 -38
  31. package/src/grid/types.ts +123 -123
  32. package/src/index.ts +9 -9
  33. package/src/multiGrid/defaults.ts +158 -158
  34. package/src/multiGrid/index.ts +13 -13
  35. package/src/multiGrid/multiGridObservables.ts +49 -49
  36. package/src/multiGrid/plugins/MultiBarStack.ts +78 -78
  37. package/src/multiGrid/plugins/MultiBars.ts +77 -77
  38. package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -77
  39. package/src/multiGrid/plugins/MultiDots.ts +65 -65
  40. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
  41. package/src/multiGrid/plugins/MultiGroupAxis.ts +69 -69
  42. package/src/multiGrid/plugins/MultiLineAreas.ts +77 -77
  43. package/src/multiGrid/plugins/MultiLines.ts +77 -77
  44. package/src/multiGrid/plugins/MultiValueAxis.ts +69 -69
  45. package/src/multiGrid/plugins/MultiValueStackAxis.ts +69 -69
  46. package/src/multiGrid/plugins/OverlappingValueAxes.ts +167 -167
  47. package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +168 -168
  48. package/src/multiGrid/types.ts +72 -72
  49. package/src/noneData/defaults.ts +102 -102
  50. package/src/noneData/index.ts +3 -3
  51. package/src/noneData/plugins/Container.ts +10 -10
  52. package/src/noneData/plugins/Tooltip.ts +310 -310
  53. package/src/noneData/types.ts +26 -26
  54. package/src/series/defaults.ts +144 -144
  55. package/src/series/index.ts +9 -9
  56. package/src/series/plugins/Bubbles.ts +545 -545
  57. package/src/series/plugins/Pie.ts +576 -576
  58. package/src/series/plugins/PieEventTexts.ts +262 -262
  59. package/src/series/plugins/PieLabels.ts +304 -304
  60. package/src/series/plugins/Rose.ts +472 -472
  61. package/src/series/plugins/RoseLabels.ts +362 -362
  62. package/src/series/plugins/SeriesLegend.ts +59 -59
  63. package/src/series/seriesObservables.ts +145 -145
  64. package/src/series/seriesUtils.ts +51 -51
  65. package/src/series/types.ts +83 -83
  66. package/src/tree/defaults.ts +23 -23
  67. package/src/tree/index.ts +3 -3
  68. package/src/tree/plugins/TreeLegend.ts +59 -59
  69. package/src/tree/plugins/TreeMap.ts +305 -305
  70. package/src/tree/types.ts +23 -23
  71. package/src/utils/commonUtils.ts +21 -21
  72. package/src/utils/d3Graphics.ts +124 -124
  73. package/src/utils/d3Utils.ts +73 -73
  74. package/src/utils/observables.ts +14 -14
  75. package/src/utils/orbchartsUtils.ts +100 -100
  76. package/tsconfig.base.json +13 -13
  77. package/tsconfig.json +2 -2
  78. package/vite.config.js +22 -22
@@ -1,362 +1,362 @@
1
- import * as d3 from 'd3'
2
- import {
3
- combineLatest,
4
- switchMap,
5
- first,
6
- map,
7
- takeUntil,
8
- Observable,
9
- distinctUntilChanged,
10
- Subject,
11
- BehaviorSubject } from 'rxjs'
12
- import {
13
- defineSeriesPlugin } from '@orbcharts/core'
14
- import type {
15
- ComputedDatumSeries,
16
- SeriesContainerPosition,
17
- EventSeries,
18
- ChartParams } from '@orbcharts/core'
19
- import type { RoseLabelsParams } from '../types'
20
- import type { PieDatum } from '../seriesUtils'
21
- import { DEFAULT_ROSE_LABELS_PARAMS } from '../defaults'
22
- // import { makePieData } from '../seriesUtils'
23
- import { makeD3Arc } from '../../utils/d3Utils'
24
- import { getDatumColor, getClassName } from '../../utils/orbchartsUtils'
25
- import { seriesCenterSelectionObservable } from '../seriesObservables'
26
-
27
- interface RenderDatum {
28
- pieDatum: PieDatum
29
- arcIndex: number
30
- arcLabel: string
31
- x: number
32
- y: number
33
- mouseoverX: number
34
- mouseoverY: number
35
- }
36
-
37
- const pluginName = 'RoseLabels'
38
- const textClassName = getClassName(pluginName, 'text')
39
-
40
- function makeRenderData ({ pieData, centroid, arcScaleType, maxValue, axisWidth, outerRadius }: {
41
- pieData: PieDatum[]
42
- // arc: d3.Arc<any, d3.DefaultArcObject>
43
- centroid: number
44
- arcScaleType: 'area' | 'radius'
45
- maxValue: number
46
- axisWidth: number
47
- outerRadius: number
48
- }): RenderDatum[] {
49
-
50
- const outerRadiusWidth = (axisWidth / 2) * outerRadius
51
-
52
- const exponent = arcScaleType === 'area'
53
- ? 0.5 // 比例映射面積(0.5為取平方根)
54
- : 1 // 比例映射半徑
55
-
56
- const arcScale = d3.scalePow()
57
- .domain([0, maxValue])
58
- .range([0, outerRadiusWidth])
59
- .exponent(exponent)
60
-
61
- return pieData
62
- .map((d, i) => {
63
- const eachOuterRadius = arcScale(d.value)
64
-
65
- const arc = d3.arc()
66
- .innerRadius(0)
67
- .outerRadius(eachOuterRadius)
68
- .padAngle(0)
69
- .padRadius(eachOuterRadius)
70
- .cornerRadius(0)
71
-
72
- const [_x, _y] = arc!.centroid(d as any)
73
- const [_mouseoverX, _mouseoverY] = [_x, _y]
74
- return {
75
- pieDatum: d,
76
- arcIndex: i,
77
- arcLabel: d.data.label,
78
- x: _x * centroid!,
79
- y: _y * centroid!,
80
- mouseoverX: _mouseoverX * centroid!,
81
- mouseoverY: _mouseoverY * centroid!
82
- }
83
- })
84
- .filter(d => d.pieDatum.data.visible)
85
- }
86
-
87
- // 繪製圓餅圖
88
- function renderLabel (selection: d3.Selection<SVGGElement, undefined, any, any>, data: RenderDatum[], pluginParams: RoseLabelsParams, fullChartParams: ChartParams) {
89
- // console.log(data)
90
- // let update = this.gSelection.selectAll('g').data(pieData)
91
- let update: d3.Selection<SVGPathElement, RenderDatum, any, any> = selection
92
- .selectAll<SVGPathElement, RenderDatum>('text')
93
- .data(data, d => d.pieDatum.id)
94
- let enter = update.enter()
95
- .append<SVGPathElement>('text')
96
- .classed(textClassName, true)
97
- let exit = update.exit()
98
-
99
- enter
100
- .append('text')
101
-
102
- const labelSelection = update.merge(enter)
103
- labelSelection
104
- .attr('font-weight', 'bold')
105
- .attr('text-anchor', 'middle')
106
- .style('dominant-baseline', 'middle')
107
- // .style('pointer-events', 'none')
108
- .style('cursor', d => fullChartParams.highlightTarget && fullChartParams.highlightTarget != 'none'
109
- ? 'pointer'
110
- : 'none')
111
- // .text((d, i) => d.arcLabel)
112
- .text(d => pluginParams.labelFn(d.pieDatum.data))
113
- .attr('font-size', fullChartParams.styles.textSize)
114
- .attr('fill', (d, i) => getDatumColor({ datum: d.pieDatum.data, colorType: pluginParams.labelColorType, fullChartParams }))
115
- .transition()
116
- .attr('transform', (d) => {
117
- return 'translate(' + d.x + ',' + d.y + ')'
118
- })
119
- // .on('end', () => initHighlight({ labelSelection, data, fullChartParams }))
120
- exit.remove()
121
-
122
- // 如無新增資料則不用等動畫
123
- // if (enter.size() == 0) {
124
- // this.initHighlight()
125
- // }
126
-
127
- return labelSelection
128
- }
129
-
130
- // function initHighlight ({ labelSelection, data, fullChartParams }: {
131
- // labelSelection: (d3.Selection<SVGPathElement, RenderDatum, any, any>)
132
- // data: RenderDatum[]
133
- // fullChartParams: ChartParams
134
- // }) {
135
- // removeHighlight({ labelSelection })
136
- // // if (fullParams.highlightSeriesId || fullParams.highlightDatumId) {
137
- // highlight({
138
- // labelSelection,
139
- // data,
140
- // id: fullChartParams.highlightDefault,
141
- // label: fullChartParams.highlightDefault,
142
- // fullChartParams
143
- // })
144
- // // }
145
- // }
146
-
147
- function highlight ({ labelSelection, ids, fullChartParams }: {
148
- labelSelection: (d3.Selection<SVGPathElement, RenderDatum, any, any>)
149
- ids: string[]
150
- fullChartParams: ChartParams
151
- }) {
152
- labelSelection.interrupt('highlight')
153
-
154
- if (!ids.length) {
155
- labelSelection
156
- .transition()
157
- .duration(200)
158
- .attr('transform', (d) => {
159
- return 'translate(' + d.x + ',' + d.y + ')'
160
- })
161
- .style('opacity', 1)
162
- return
163
- }
164
-
165
- labelSelection.each((d, i, n) => {
166
- const segment = d3.select<SVGPathElement, RenderDatum>(n[i])
167
-
168
- if (ids.includes(d.pieDatum.data.id)) {
169
- segment
170
- .style('opacity', 1)
171
- .transition()
172
- .duration(200)
173
- .attr('transform', (d) => {
174
- return 'translate(' + d.mouseoverX + ',' + d.mouseoverY + ')'
175
- })
176
- } else {
177
- segment
178
- .style('opacity', fullChartParams.styles.unhighlightedOpacity)
179
- .transition()
180
- .duration(200)
181
- .attr('transform', (d) => {
182
- return 'translate(' + d.x + ',' + d.y + ')'
183
- })
184
- }
185
- })
186
- }
187
-
188
-
189
- function createEachPieLabel (pluginName: string, context: {
190
- containerSelection: d3.Selection<SVGGElement, any, any, unknown>
191
- // computedData$: Observable<ComputedDatumSeries[][]>
192
- visibleComputedLayoutData$: Observable<ComputedDatumSeries[][]>
193
- containerVisibleComputedLayoutData$: Observable<ComputedDatumSeries[]>
194
- // SeriesDataMap$: Observable<Map<string, ComputedDatumSeries[]>>
195
- fullParams$: Observable<RoseLabelsParams>
196
- fullChartParams$: Observable<ChartParams>
197
- seriesHighlight$: Observable<ComputedDatumSeries[]>
198
- seriesContainerPosition$: Observable<SeriesContainerPosition>
199
- event$: Subject<EventSeries>
200
- }) {
201
- const destroy$ = new Subject()
202
-
203
- let labelSelection$: Subject<d3.Selection<SVGPathElement, RenderDatum, any, any>> = new Subject()
204
- let renderData: RenderDatum[] = []
205
-
206
- const shorterSideWith$ = context.seriesContainerPosition$.pipe(
207
- takeUntil(destroy$),
208
- map(d => d.width < d.height ? d.width : d.height),
209
- distinctUntilChanged()
210
- )
211
-
212
- const maxValue$ = context.visibleComputedLayoutData$.pipe(
213
- map(data => Math.max(...data.flat().map(d => d.value))),
214
- distinctUntilChanged()
215
- )
216
-
217
- combineLatest({
218
- // layout: context.seriesContainerPosition$,
219
- shorterSideWith: shorterSideWith$,
220
- containerVisibleComputedLayoutData: context.containerVisibleComputedLayoutData$,
221
- maxValue: maxValue$,
222
- fullParams: context.fullParams$,
223
- fullChartParams: context.fullChartParams$,
224
- }).pipe(
225
- takeUntil(destroy$),
226
- switchMap(async (d) => d),
227
- ).subscribe(data => {
228
-
229
- // const shorterSideWith = data.layout.width < data.layout.height ? data.layout.width : data.layout.height
230
-
231
- // // 弧產生器 (d3.arc())
232
- // const arc = makeD3Arc({
233
- // axisWidth: shorterSideWith,
234
- // innerRadius: 0,
235
- // outerRadius: data.fullParams.outerRadius,
236
- // padAngle: 0,
237
- // cornerRadius: 0
238
- // })
239
-
240
- // const arcMouseover = makeD3Arc({
241
- // axisWidth: shorterSideWith,
242
- // innerRadius: 0,
243
- // outerRadius: data.fullParams.outerRadiusWhileHighlight, // 外半徑變化
244
- // padAngle: 0,
245
- // cornerRadius: 0
246
- // })
247
-
248
- // const pieData = makePieData({
249
- // data: data.containerVisibleComputedLayoutData,
250
- // startAngle: data.fullParams.startAngle,
251
- // endAngle: data.fullParams.endAngle
252
- // })
253
-
254
- const eachAngle = Math.PI * 2 / data.containerVisibleComputedLayoutData.length
255
-
256
- const pieData = data.containerVisibleComputedLayoutData.map((d, i) => {
257
- return {
258
- id: d.id,
259
- data: d,
260
- index: i,
261
- value: d.value,
262
- startAngle: eachAngle * i,
263
- endAngle: eachAngle * (i + 1),
264
- padAngle: 0,
265
- // prevValue: lastPieData[i] ? lastPieData[i].value : 0
266
- }
267
- })
268
-
269
- renderData = makeRenderData({
270
- pieData,
271
- centroid: data.fullParams.labelCentroid,
272
- arcScaleType: data.fullParams.arcScaleType,
273
- maxValue: data.maxValue,
274
- axisWidth: data.shorterSideWith,
275
- outerRadius: data.fullParams.outerRadius
276
- })
277
-
278
- const labelSelection = renderLabel(context.containerSelection, renderData, data.fullParams, data.fullChartParams)
279
-
280
- labelSelection$.next(labelSelection)
281
-
282
- })
283
-
284
- combineLatest({
285
- labelSelection: labelSelection$,
286
- highlight: context.seriesHighlight$.pipe(
287
- map(data => data.map(d => d.id))
288
- ),
289
- fullChartParams: context.fullChartParams$,
290
- }).pipe(
291
- takeUntil(destroy$),
292
- switchMap(async d => d)
293
- ).subscribe(data => {
294
- highlight({
295
- labelSelection: data.labelSelection,
296
- ids: data.highlight,
297
- fullChartParams: data.fullChartParams,
298
- })
299
- })
300
-
301
- return () => {
302
- destroy$.next(undefined)
303
- }
304
- }
305
-
306
-
307
- export const RoseLabels = defineSeriesPlugin(pluginName, DEFAULT_ROSE_LABELS_PARAMS)(({ selection, observer, subject }) => {
308
-
309
- const destroy$ = new Subject()
310
-
311
- const { seriesCenterSelection$ } = seriesCenterSelectionObservable({
312
- selection: selection,
313
- pluginName,
314
- separateSeries$: observer.separateSeries$,
315
- seriesLabels$: observer.seriesLabels$,
316
- seriesContainerPosition$: observer.seriesContainerPosition$
317
- })
318
-
319
- const unsubscribeFnArr: (() => void)[] = []
320
-
321
- seriesCenterSelection$
322
- .pipe(
323
- takeUntil(destroy$)
324
- )
325
- .subscribe(seriesCenterSelection => {
326
- // 每次重新計算時,清除之前的訂閱
327
- unsubscribeFnArr.forEach(fn => fn())
328
-
329
- seriesCenterSelection.each((d, containerIndex, g) => {
330
-
331
- const containerSelection = d3.select(g[containerIndex])
332
-
333
- const containerVisibleComputedLayoutData$ = observer.visibleComputedLayoutData$.pipe(
334
- takeUntil(destroy$),
335
- map(data => JSON.parse(JSON.stringify(data[containerIndex] ?? data[0])))
336
- )
337
-
338
- const containerPosition$ = observer.seriesContainerPosition$.pipe(
339
- takeUntil(destroy$),
340
- map(data => JSON.parse(JSON.stringify(data[containerIndex] ?? data[0])))
341
- )
342
-
343
- unsubscribeFnArr[containerIndex] = createEachPieLabel(pluginName, {
344
- containerSelection: containerSelection,
345
- // computedData$: observer.computedData$,
346
- visibleComputedLayoutData$: observer.visibleComputedLayoutData$,
347
- containerVisibleComputedLayoutData$: containerVisibleComputedLayoutData$,
348
- // SeriesDataMap$: observer.SeriesDataMap$,
349
- fullParams$: observer.fullParams$,
350
- fullChartParams$: observer.fullChartParams$,
351
- seriesHighlight$: observer.seriesHighlight$,
352
- seriesContainerPosition$: containerPosition$,
353
- event$: subject.event$,
354
- })
355
-
356
- })
357
- })
358
-
359
- return () => {
360
- destroy$.next(undefined)
361
- }
362
- })
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ switchMap,
5
+ first,
6
+ map,
7
+ takeUntil,
8
+ Observable,
9
+ distinctUntilChanged,
10
+ Subject,
11
+ BehaviorSubject } from 'rxjs'
12
+ import {
13
+ defineSeriesPlugin } from '@orbcharts/core'
14
+ import type {
15
+ ComputedDatumSeries,
16
+ SeriesContainerPosition,
17
+ EventSeries,
18
+ ChartParams } from '@orbcharts/core'
19
+ import type { RoseLabelsParams } from '../types'
20
+ import type { PieDatum } from '../seriesUtils'
21
+ import { DEFAULT_ROSE_LABELS_PARAMS } from '../defaults'
22
+ // import { makePieData } from '../seriesUtils'
23
+ import { makeD3Arc } from '../../utils/d3Utils'
24
+ import { getDatumColor, getClassName } from '../../utils/orbchartsUtils'
25
+ import { seriesCenterSelectionObservable } from '../seriesObservables'
26
+
27
+ interface RenderDatum {
28
+ pieDatum: PieDatum
29
+ arcIndex: number
30
+ arcLabel: string
31
+ x: number
32
+ y: number
33
+ mouseoverX: number
34
+ mouseoverY: number
35
+ }
36
+
37
+ const pluginName = 'RoseLabels'
38
+ const textClassName = getClassName(pluginName, 'text')
39
+
40
+ function makeRenderData ({ pieData, centroid, arcScaleType, maxValue, axisWidth, outerRadius }: {
41
+ pieData: PieDatum[]
42
+ // arc: d3.Arc<any, d3.DefaultArcObject>
43
+ centroid: number
44
+ arcScaleType: 'area' | 'radius'
45
+ maxValue: number
46
+ axisWidth: number
47
+ outerRadius: number
48
+ }): RenderDatum[] {
49
+
50
+ const outerRadiusWidth = (axisWidth / 2) * outerRadius
51
+
52
+ const exponent = arcScaleType === 'area'
53
+ ? 0.5 // 比例映射面積(0.5為取平方根)
54
+ : 1 // 比例映射半徑
55
+
56
+ const arcScale = d3.scalePow()
57
+ .domain([0, maxValue])
58
+ .range([0, outerRadiusWidth])
59
+ .exponent(exponent)
60
+
61
+ return pieData
62
+ .map((d, i) => {
63
+ const eachOuterRadius = arcScale(d.value)
64
+
65
+ const arc = d3.arc()
66
+ .innerRadius(0)
67
+ .outerRadius(eachOuterRadius)
68
+ .padAngle(0)
69
+ .padRadius(eachOuterRadius)
70
+ .cornerRadius(0)
71
+
72
+ const [_x, _y] = arc!.centroid(d as any)
73
+ const [_mouseoverX, _mouseoverY] = [_x, _y]
74
+ return {
75
+ pieDatum: d,
76
+ arcIndex: i,
77
+ arcLabel: d.data.label,
78
+ x: _x * centroid!,
79
+ y: _y * centroid!,
80
+ mouseoverX: _mouseoverX * centroid!,
81
+ mouseoverY: _mouseoverY * centroid!
82
+ }
83
+ })
84
+ .filter(d => d.pieDatum.data.visible)
85
+ }
86
+
87
+ // 繪製圓餅圖
88
+ function renderLabel (selection: d3.Selection<SVGGElement, undefined, any, any>, data: RenderDatum[], pluginParams: RoseLabelsParams, fullChartParams: ChartParams) {
89
+ // console.log(data)
90
+ // let update = this.gSelection.selectAll('g').data(pieData)
91
+ let update: d3.Selection<SVGPathElement, RenderDatum, any, any> = selection
92
+ .selectAll<SVGPathElement, RenderDatum>('text')
93
+ .data(data, d => d.pieDatum.id)
94
+ let enter = update.enter()
95
+ .append<SVGPathElement>('text')
96
+ .classed(textClassName, true)
97
+ let exit = update.exit()
98
+
99
+ enter
100
+ .append('text')
101
+
102
+ const labelSelection = update.merge(enter)
103
+ labelSelection
104
+ .attr('font-weight', 'bold')
105
+ .attr('text-anchor', 'middle')
106
+ .style('dominant-baseline', 'middle')
107
+ // .style('pointer-events', 'none')
108
+ .style('cursor', d => fullChartParams.highlightTarget && fullChartParams.highlightTarget != 'none'
109
+ ? 'pointer'
110
+ : 'none')
111
+ // .text((d, i) => d.arcLabel)
112
+ .text(d => pluginParams.labelFn(d.pieDatum.data))
113
+ .attr('font-size', fullChartParams.styles.textSize)
114
+ .attr('fill', (d, i) => getDatumColor({ datum: d.pieDatum.data, colorType: pluginParams.labelColorType, fullChartParams }))
115
+ .transition()
116
+ .attr('transform', (d) => {
117
+ return 'translate(' + d.x + ',' + d.y + ')'
118
+ })
119
+ // .on('end', () => initHighlight({ labelSelection, data, fullChartParams }))
120
+ exit.remove()
121
+
122
+ // 如無新增資料則不用等動畫
123
+ // if (enter.size() == 0) {
124
+ // this.initHighlight()
125
+ // }
126
+
127
+ return labelSelection
128
+ }
129
+
130
+ // function initHighlight ({ labelSelection, data, fullChartParams }: {
131
+ // labelSelection: (d3.Selection<SVGPathElement, RenderDatum, any, any>)
132
+ // data: RenderDatum[]
133
+ // fullChartParams: ChartParams
134
+ // }) {
135
+ // removeHighlight({ labelSelection })
136
+ // // if (fullParams.highlightSeriesId || fullParams.highlightDatumId) {
137
+ // highlight({
138
+ // labelSelection,
139
+ // data,
140
+ // id: fullChartParams.highlightDefault,
141
+ // label: fullChartParams.highlightDefault,
142
+ // fullChartParams
143
+ // })
144
+ // // }
145
+ // }
146
+
147
+ function highlight ({ labelSelection, ids, fullChartParams }: {
148
+ labelSelection: (d3.Selection<SVGPathElement, RenderDatum, any, any>)
149
+ ids: string[]
150
+ fullChartParams: ChartParams
151
+ }) {
152
+ labelSelection.interrupt('highlight')
153
+
154
+ if (!ids.length) {
155
+ labelSelection
156
+ .transition()
157
+ .duration(200)
158
+ .attr('transform', (d) => {
159
+ return 'translate(' + d.x + ',' + d.y + ')'
160
+ })
161
+ .style('opacity', 1)
162
+ return
163
+ }
164
+
165
+ labelSelection.each((d, i, n) => {
166
+ const segment = d3.select<SVGPathElement, RenderDatum>(n[i])
167
+
168
+ if (ids.includes(d.pieDatum.data.id)) {
169
+ segment
170
+ .style('opacity', 1)
171
+ .transition()
172
+ .duration(200)
173
+ .attr('transform', (d) => {
174
+ return 'translate(' + d.mouseoverX + ',' + d.mouseoverY + ')'
175
+ })
176
+ } else {
177
+ segment
178
+ .style('opacity', fullChartParams.styles.unhighlightedOpacity)
179
+ .transition()
180
+ .duration(200)
181
+ .attr('transform', (d) => {
182
+ return 'translate(' + d.x + ',' + d.y + ')'
183
+ })
184
+ }
185
+ })
186
+ }
187
+
188
+
189
+ function createEachPieLabel (pluginName: string, context: {
190
+ containerSelection: d3.Selection<SVGGElement, any, any, unknown>
191
+ // computedData$: Observable<ComputedDatumSeries[][]>
192
+ visibleComputedLayoutData$: Observable<ComputedDatumSeries[][]>
193
+ containerVisibleComputedLayoutData$: Observable<ComputedDatumSeries[]>
194
+ // SeriesDataMap$: Observable<Map<string, ComputedDatumSeries[]>>
195
+ fullParams$: Observable<RoseLabelsParams>
196
+ fullChartParams$: Observable<ChartParams>
197
+ seriesHighlight$: Observable<ComputedDatumSeries[]>
198
+ seriesContainerPosition$: Observable<SeriesContainerPosition>
199
+ event$: Subject<EventSeries>
200
+ }) {
201
+ const destroy$ = new Subject()
202
+
203
+ let labelSelection$: Subject<d3.Selection<SVGPathElement, RenderDatum, any, any>> = new Subject()
204
+ let renderData: RenderDatum[] = []
205
+
206
+ const shorterSideWith$ = context.seriesContainerPosition$.pipe(
207
+ takeUntil(destroy$),
208
+ map(d => d.width < d.height ? d.width : d.height),
209
+ distinctUntilChanged()
210
+ )
211
+
212
+ const maxValue$ = context.visibleComputedLayoutData$.pipe(
213
+ map(data => Math.max(...data.flat().map(d => d.value))),
214
+ distinctUntilChanged()
215
+ )
216
+
217
+ combineLatest({
218
+ // layout: context.seriesContainerPosition$,
219
+ shorterSideWith: shorterSideWith$,
220
+ containerVisibleComputedLayoutData: context.containerVisibleComputedLayoutData$,
221
+ maxValue: maxValue$,
222
+ fullParams: context.fullParams$,
223
+ fullChartParams: context.fullChartParams$,
224
+ }).pipe(
225
+ takeUntil(destroy$),
226
+ switchMap(async (d) => d),
227
+ ).subscribe(data => {
228
+
229
+ // const shorterSideWith = data.layout.width < data.layout.height ? data.layout.width : data.layout.height
230
+
231
+ // // 弧產生器 (d3.arc())
232
+ // const arc = makeD3Arc({
233
+ // axisWidth: shorterSideWith,
234
+ // innerRadius: 0,
235
+ // outerRadius: data.fullParams.outerRadius,
236
+ // padAngle: 0,
237
+ // cornerRadius: 0
238
+ // })
239
+
240
+ // const arcMouseover = makeD3Arc({
241
+ // axisWidth: shorterSideWith,
242
+ // innerRadius: 0,
243
+ // outerRadius: data.fullParams.outerRadiusWhileHighlight, // 外半徑變化
244
+ // padAngle: 0,
245
+ // cornerRadius: 0
246
+ // })
247
+
248
+ // const pieData = makePieData({
249
+ // data: data.containerVisibleComputedLayoutData,
250
+ // startAngle: data.fullParams.startAngle,
251
+ // endAngle: data.fullParams.endAngle
252
+ // })
253
+
254
+ const eachAngle = Math.PI * 2 / data.containerVisibleComputedLayoutData.length
255
+
256
+ const pieData = data.containerVisibleComputedLayoutData.map((d, i) => {
257
+ return {
258
+ id: d.id,
259
+ data: d,
260
+ index: i,
261
+ value: d.value,
262
+ startAngle: eachAngle * i,
263
+ endAngle: eachAngle * (i + 1),
264
+ padAngle: 0,
265
+ // prevValue: lastPieData[i] ? lastPieData[i].value : 0
266
+ }
267
+ })
268
+
269
+ renderData = makeRenderData({
270
+ pieData,
271
+ centroid: data.fullParams.labelCentroid,
272
+ arcScaleType: data.fullParams.arcScaleType,
273
+ maxValue: data.maxValue,
274
+ axisWidth: data.shorterSideWith,
275
+ outerRadius: data.fullParams.outerRadius
276
+ })
277
+
278
+ const labelSelection = renderLabel(context.containerSelection, renderData, data.fullParams, data.fullChartParams)
279
+
280
+ labelSelection$.next(labelSelection)
281
+
282
+ })
283
+
284
+ combineLatest({
285
+ labelSelection: labelSelection$,
286
+ highlight: context.seriesHighlight$.pipe(
287
+ map(data => data.map(d => d.id))
288
+ ),
289
+ fullChartParams: context.fullChartParams$,
290
+ }).pipe(
291
+ takeUntil(destroy$),
292
+ switchMap(async d => d)
293
+ ).subscribe(data => {
294
+ highlight({
295
+ labelSelection: data.labelSelection,
296
+ ids: data.highlight,
297
+ fullChartParams: data.fullChartParams,
298
+ })
299
+ })
300
+
301
+ return () => {
302
+ destroy$.next(undefined)
303
+ }
304
+ }
305
+
306
+
307
+ export const RoseLabels = defineSeriesPlugin(pluginName, DEFAULT_ROSE_LABELS_PARAMS)(({ selection, observer, subject }) => {
308
+
309
+ const destroy$ = new Subject()
310
+
311
+ const { seriesCenterSelection$ } = seriesCenterSelectionObservable({
312
+ selection: selection,
313
+ pluginName,
314
+ separateSeries$: observer.separateSeries$,
315
+ seriesLabels$: observer.seriesLabels$,
316
+ seriesContainerPosition$: observer.seriesContainerPosition$
317
+ })
318
+
319
+ const unsubscribeFnArr: (() => void)[] = []
320
+
321
+ seriesCenterSelection$
322
+ .pipe(
323
+ takeUntil(destroy$)
324
+ )
325
+ .subscribe(seriesCenterSelection => {
326
+ // 每次重新計算時,清除之前的訂閱
327
+ unsubscribeFnArr.forEach(fn => fn())
328
+
329
+ seriesCenterSelection.each((d, containerIndex, g) => {
330
+
331
+ const containerSelection = d3.select(g[containerIndex])
332
+
333
+ const containerVisibleComputedLayoutData$ = observer.visibleComputedLayoutData$.pipe(
334
+ takeUntil(destroy$),
335
+ map(data => JSON.parse(JSON.stringify(data[containerIndex] ?? data[0])))
336
+ )
337
+
338
+ const containerPosition$ = observer.seriesContainerPosition$.pipe(
339
+ takeUntil(destroy$),
340
+ map(data => JSON.parse(JSON.stringify(data[containerIndex] ?? data[0])))
341
+ )
342
+
343
+ unsubscribeFnArr[containerIndex] = createEachPieLabel(pluginName, {
344
+ containerSelection: containerSelection,
345
+ // computedData$: observer.computedData$,
346
+ visibleComputedLayoutData$: observer.visibleComputedLayoutData$,
347
+ containerVisibleComputedLayoutData$: containerVisibleComputedLayoutData$,
348
+ // SeriesDataMap$: observer.SeriesDataMap$,
349
+ fullParams$: observer.fullParams$,
350
+ fullChartParams$: observer.fullChartParams$,
351
+ seriesHighlight$: observer.seriesHighlight$,
352
+ seriesContainerPosition$: containerPosition$,
353
+ event$: subject.event$,
354
+ })
355
+
356
+ })
357
+ })
358
+
359
+ return () => {
360
+ destroy$.next(undefined)
361
+ }
362
+ })