@orbcharts/plugin-basic 4.0.0-pre-alpha.0

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 (208) hide show
  1. package/LICENSE +201 -0
  2. package/dist/orbcharts-plugin-basic.es.js +25335 -0
  3. package/dist/orbcharts-plugin-basic.umd.js +341 -0
  4. package/dist/plugin-basic/src/baseLayers/BaseBars.d.ts +38 -0
  5. package/dist/plugin-basic/src/baseLayers/BaseBarsTriangle.d.ts +37 -0
  6. package/dist/plugin-basic/src/baseLayers/BaseCategoryAxis.d.ts +42 -0
  7. package/dist/plugin-basic/src/baseLayers/BaseDots.d.ts +38 -0
  8. package/dist/plugin-basic/src/baseLayers/BaseLegend.d.ts +31 -0
  9. package/dist/plugin-basic/src/baseLayers/BaseLineAreas.d.ts +36 -0
  10. package/dist/plugin-basic/src/baseLayers/BaseLines.d.ts +36 -0
  11. package/dist/plugin-basic/src/baseLayers/BaseStackedBars.d.ts +41 -0
  12. package/dist/plugin-basic/src/baseLayers/BaseTooltip.d.ts +47 -0
  13. package/dist/plugin-basic/src/baseLayers/BaseValueAxis.d.ts +38 -0
  14. package/dist/plugin-basic/src/baseLayers/BaseXAxis.d.ts +25 -0
  15. package/dist/plugin-basic/src/baseLayers/BaseXZoom.d.ts +22 -0
  16. package/dist/plugin-basic/src/baseLayers/BaseYAxis.d.ts +23 -0
  17. package/dist/plugin-basic/src/baseLayers/types.d.ts +171 -0
  18. package/dist/plugin-basic/src/const/layerIndex.d.ts +10 -0
  19. package/dist/plugin-basic/src/const/sharedPluginParams.d.ts +6 -0
  20. package/dist/plugin-basic/src/index.d.ts +2 -0
  21. package/dist/plugin-basic/src/plugins/CompositionPlot/CompositionPlot.d.ts +22 -0
  22. package/dist/plugin-basic/src/plugins/CompositionPlot/contextObservables.d.ts +40 -0
  23. package/dist/plugin-basic/src/plugins/CompositionPlot/defaults.d.ts +10 -0
  24. package/dist/plugin-basic/src/plugins/CompositionPlot/index.d.ts +3 -0
  25. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/Bubbles.d.ts +16 -0
  26. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/Indicator.d.ts +0 -0
  27. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/Pie.d.ts +16 -0
  28. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/PieEventTexts.d.ts +16 -0
  29. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/PieLabels.d.ts +16 -0
  30. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/Rose.d.ts +16 -0
  31. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/RoseLabels.d.ts +16 -0
  32. package/dist/plugin-basic/src/plugins/CompositionPlot/layers/Waffle.d.ts +0 -0
  33. package/dist/plugin-basic/src/plugins/CompositionPlot/types.d.ts +110 -0
  34. package/dist/plugin-basic/src/plugins/CompositionPlot/utils.d.ts +19 -0
  35. package/dist/plugin-basic/src/plugins/HierarchyPlot/HierarchyPlot.d.ts +22 -0
  36. package/dist/plugin-basic/src/plugins/HierarchyPlot/contextObservables.d.ts +16 -0
  37. package/dist/plugin-basic/src/plugins/HierarchyPlot/defaults.d.ts +4 -0
  38. package/dist/plugin-basic/src/plugins/HierarchyPlot/index.d.ts +3 -0
  39. package/dist/plugin-basic/src/plugins/HierarchyPlot/layers/TreeMap.d.ts +16 -0
  40. package/dist/plugin-basic/src/plugins/HierarchyPlot/types.d.ts +29 -0
  41. package/dist/plugin-basic/src/plugins/Legend/Legend.d.ts +22 -0
  42. package/dist/plugin-basic/src/plugins/Legend/contextObservables.d.ts +9 -0
  43. package/dist/plugin-basic/src/plugins/Legend/defaults.d.ts +4 -0
  44. package/dist/plugin-basic/src/plugins/Legend/index.d.ts +3 -0
  45. package/dist/plugin-basic/src/plugins/Legend/layers/Legend.d.ts +16 -0
  46. package/dist/plugin-basic/src/plugins/Legend/types.d.ts +31 -0
  47. package/dist/plugin-basic/src/plugins/Legend/utils.d.ts +19 -0
  48. package/dist/plugin-basic/src/plugins/NetworkPlot/NetworkPlot.d.ts +22 -0
  49. package/dist/plugin-basic/src/plugins/NetworkPlot/contextObservables.d.ts +19 -0
  50. package/dist/plugin-basic/src/plugins/NetworkPlot/defaults.d.ts +5 -0
  51. package/dist/plugin-basic/src/plugins/NetworkPlot/index.d.ts +3 -0
  52. package/dist/plugin-basic/src/plugins/NetworkPlot/layers/ForceDirected.d.ts +16 -0
  53. package/dist/plugin-basic/src/plugins/NetworkPlot/layers/ForceDirectedBubbles.d.ts +16 -0
  54. package/dist/plugin-basic/src/plugins/NetworkPlot/types.d.ts +117 -0
  55. package/dist/plugin-basic/src/plugins/ScatterPlot/ScatterPlot.d.ts +22 -0
  56. package/dist/plugin-basic/src/plugins/ScatterPlot/contextObservables.d.ts +140 -0
  57. package/dist/plugin-basic/src/plugins/ScatterPlot/defaults.d.ts +8 -0
  58. package/dist/plugin-basic/src/plugins/ScatterPlot/index.d.ts +3 -0
  59. package/dist/plugin-basic/src/plugins/ScatterPlot/layers/Scatter.d.ts +16 -0
  60. package/dist/plugin-basic/src/plugins/ScatterPlot/layers/ScatterBubbles.d.ts +16 -0
  61. package/dist/plugin-basic/src/plugins/ScatterPlot/layers/XYAux.d.ts +16 -0
  62. package/dist/plugin-basic/src/plugins/ScatterPlot/layers/XYAxes.d.ts +16 -0
  63. package/dist/plugin-basic/src/plugins/ScatterPlot/layers/XZoom.d.ts +16 -0
  64. package/dist/plugin-basic/src/plugins/ScatterPlot/types.d.ts +146 -0
  65. package/dist/plugin-basic/src/plugins/SeriesPlot/SeriesPlot.d.ts +22 -0
  66. package/dist/plugin-basic/src/plugins/SeriesPlot/contextObservables.d.ts +77 -0
  67. package/dist/plugin-basic/src/plugins/SeriesPlot/defaults.d.ts +15 -0
  68. package/dist/plugin-basic/src/plugins/SeriesPlot/index.d.ts +3 -0
  69. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/Bars.d.ts +16 -0
  70. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/BarsPN.d.ts +16 -0
  71. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/BarsTriangle.d.ts +16 -0
  72. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/CategoryAux.d.ts +16 -0
  73. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/CategoryAxis.d.ts +16 -0
  74. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/CategoryZoom.d.ts +16 -0
  75. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/Dots.d.ts +16 -0
  76. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/LineAreas.d.ts +16 -0
  77. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/Lines.d.ts +16 -0
  78. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/StackedBars.d.ts +16 -0
  79. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/StackedValueAxis.d.ts +16 -0
  80. package/dist/plugin-basic/src/plugins/SeriesPlot/layers/ValueAxis.d.ts +16 -0
  81. package/dist/plugin-basic/src/plugins/SeriesPlot/types.d.ts +140 -0
  82. package/dist/plugin-basic/src/plugins/Tooltip/Tooltip.d.ts +22 -0
  83. package/dist/plugin-basic/src/plugins/Tooltip/contextObservables.d.ts +9 -0
  84. package/dist/plugin-basic/src/plugins/Tooltip/defaults.d.ts +4 -0
  85. package/dist/plugin-basic/src/plugins/Tooltip/index.d.ts +3 -0
  86. package/dist/plugin-basic/src/plugins/Tooltip/layers/Tooltip.d.ts +16 -0
  87. package/dist/plugin-basic/src/plugins/Tooltip/types.d.ts +35 -0
  88. package/dist/plugin-basic/src/plugins/Tooltip/utils.d.ts +19 -0
  89. package/dist/plugin-basic/src/plugins/index.d.ts +7 -0
  90. package/dist/plugin-basic/src/types/BaseLayer.d.ts +3 -0
  91. package/dist/plugin-basic/src/types/Common.d.ts +14 -0
  92. package/dist/plugin-basic/src/types/ComputedData.d.ts +27 -0
  93. package/dist/plugin-basic/src/types/PluginParams.d.ts +66 -0
  94. package/dist/plugin-basic/src/types/index.d.ts +3 -0
  95. package/dist/plugin-basic/src/utils/commonUtils.d.ts +3 -0
  96. package/dist/plugin-basic/src/utils/d3Graphics.d.ts +24 -0
  97. package/dist/plugin-basic/src/utils/d3Scale.d.ts +28 -0
  98. package/dist/plugin-basic/src/utils/d3Utils.d.ts +14 -0
  99. package/dist/plugin-basic/src/utils/graphObservables.d.ts +0 -0
  100. package/dist/plugin-basic/src/utils/gridObservables.d.ts +51 -0
  101. package/dist/plugin-basic/src/utils/multivariateObservables.d.ts +74 -0
  102. package/dist/plugin-basic/src/utils/observables.d.ts +34 -0
  103. package/dist/plugin-basic/src/utils/orbchartsUtils.d.ts +26 -0
  104. package/dist/plugin-basic/src/utils/seriesObservables.d.ts +22 -0
  105. package/dist/plugin-basic/vite.config.d.ts +2 -0
  106. package/dist/src/index.d.ts +1 -0
  107. package/package.json +62 -0
  108. package/src/baseLayers/BaseBars.ts +783 -0
  109. package/src/baseLayers/BaseBarsTriangle.ts +692 -0
  110. package/src/baseLayers/BaseCategoryAxis.ts +708 -0
  111. package/src/baseLayers/BaseDots.ts +495 -0
  112. package/src/baseLayers/BaseLegend.ts +684 -0
  113. package/src/baseLayers/BaseLineAreas.ts +644 -0
  114. package/src/baseLayers/BaseLines.ts +721 -0
  115. package/src/baseLayers/BaseStackedBars.ts +818 -0
  116. package/src/baseLayers/BaseTooltip.ts +435 -0
  117. package/src/baseLayers/BaseValueAxis.ts +612 -0
  118. package/src/baseLayers/BaseXAxis.ts +412 -0
  119. package/src/baseLayers/BaseXZoom.ts +250 -0
  120. package/src/baseLayers/BaseYAxis.ts +371 -0
  121. package/src/baseLayers/types.ts +174 -0
  122. package/src/const/layerIndex.ts +36 -0
  123. package/src/const/sharedPluginParams.ts +29 -0
  124. package/src/index.ts +3 -0
  125. package/src/plugins/CompositionPlot/CompositionPlot.ts +308 -0
  126. package/src/plugins/CompositionPlot/contextObservables.ts +251 -0
  127. package/src/plugins/CompositionPlot/defaults.ts +162 -0
  128. package/src/plugins/CompositionPlot/index.ts +3 -0
  129. package/src/plugins/CompositionPlot/layers/Bubbles.ts +808 -0
  130. package/src/plugins/CompositionPlot/layers/Indicator.ts +0 -0
  131. package/src/plugins/CompositionPlot/layers/Pie.ts +776 -0
  132. package/src/plugins/CompositionPlot/layers/PieEventTexts.ts +326 -0
  133. package/src/plugins/CompositionPlot/layers/PieLabels.ts +651 -0
  134. package/src/plugins/CompositionPlot/layers/Rose.ts +546 -0
  135. package/src/plugins/CompositionPlot/layers/RoseLabels.ts +616 -0
  136. package/src/plugins/CompositionPlot/layers/Waffle.ts +0 -0
  137. package/src/plugins/CompositionPlot/types.ts +129 -0
  138. package/src/plugins/CompositionPlot/utils.ts +53 -0
  139. package/src/plugins/HierarchyPlot/HierarchyPlot.ts +190 -0
  140. package/src/plugins/HierarchyPlot/contextObservables.ts +136 -0
  141. package/src/plugins/HierarchyPlot/defaults.ts +31 -0
  142. package/src/plugins/HierarchyPlot/index.ts +3 -0
  143. package/src/plugins/HierarchyPlot/layers/TreeMap.ts +371 -0
  144. package/src/plugins/HierarchyPlot/types.ts +36 -0
  145. package/src/plugins/Legend/Legend.ts +151 -0
  146. package/src/plugins/Legend/contextObservables.ts +55 -0
  147. package/src/plugins/Legend/defaults.ts +37 -0
  148. package/src/plugins/Legend/index.ts +3 -0
  149. package/src/plugins/Legend/layers/Legend.ts +114 -0
  150. package/src/plugins/Legend/types.ts +45 -0
  151. package/src/plugins/Legend/utils.ts +53 -0
  152. package/src/plugins/NetworkPlot/NetworkPlot.ts +228 -0
  153. package/src/plugins/NetworkPlot/contextObservables.ts +123 -0
  154. package/src/plugins/NetworkPlot/defaults.ts +147 -0
  155. package/src/plugins/NetworkPlot/index.ts +3 -0
  156. package/src/plugins/NetworkPlot/layers/ForceDirected.ts +1048 -0
  157. package/src/plugins/NetworkPlot/layers/ForceDirectedBubbles.ts +1318 -0
  158. package/src/plugins/NetworkPlot/types.ts +146 -0
  159. package/src/plugins/ScatterPlot/ScatterPlot.ts +569 -0
  160. package/src/plugins/ScatterPlot/contextObservables.ts +901 -0
  161. package/src/plugins/ScatterPlot/defaults.ts +212 -0
  162. package/src/plugins/ScatterPlot/index.ts +3 -0
  163. package/src/plugins/ScatterPlot/layers/Scatter.ts +518 -0
  164. package/src/plugins/ScatterPlot/layers/ScatterBubbles.ts +670 -0
  165. package/src/plugins/ScatterPlot/layers/XYAux.ts +686 -0
  166. package/src/plugins/ScatterPlot/layers/XYAxes.ts +205 -0
  167. package/src/plugins/ScatterPlot/layers/XZoom.ts +48 -0
  168. package/src/plugins/ScatterPlot/types.ts +179 -0
  169. package/src/plugins/SeriesPlot/SeriesPlot.ts +494 -0
  170. package/src/plugins/SeriesPlot/contextObservables.ts +726 -0
  171. package/src/plugins/SeriesPlot/defaults.ts +142 -0
  172. package/src/plugins/SeriesPlot/index.ts +3 -0
  173. package/src/plugins/SeriesPlot/layers/Bars.ts +84 -0
  174. package/src/plugins/SeriesPlot/layers/BarsPN.ts +85 -0
  175. package/src/plugins/SeriesPlot/layers/BarsTriangle.ts +89 -0
  176. package/src/plugins/SeriesPlot/layers/CategoryAux.ts +1131 -0
  177. package/src/plugins/SeriesPlot/layers/CategoryAxis.ts +92 -0
  178. package/src/plugins/SeriesPlot/layers/CategoryZoom.ts +233 -0
  179. package/src/plugins/SeriesPlot/layers/Dots.ts +91 -0
  180. package/src/plugins/SeriesPlot/layers/LineAreas.ts +82 -0
  181. package/src/plugins/SeriesPlot/layers/Lines.ts +75 -0
  182. package/src/plugins/SeriesPlot/layers/StackedBars.ts +85 -0
  183. package/src/plugins/SeriesPlot/layers/StackedValueAxis.ts +111 -0
  184. package/src/plugins/SeriesPlot/layers/ValueAxis.ts +111 -0
  185. package/src/plugins/SeriesPlot/types.ts +201 -0
  186. package/src/plugins/Tooltip/Tooltip.ts +159 -0
  187. package/src/plugins/Tooltip/contextObservables.ts +55 -0
  188. package/src/plugins/Tooltip/defaults.ts +458 -0
  189. package/src/plugins/Tooltip/index.ts +3 -0
  190. package/src/plugins/Tooltip/layers/Tooltip.ts +90 -0
  191. package/src/plugins/Tooltip/types.ts +55 -0
  192. package/src/plugins/Tooltip/utils.ts +53 -0
  193. package/src/plugins/index.ts +8 -0
  194. package/src/types/BaseLayer.ts +3 -0
  195. package/src/types/Common.ts +20 -0
  196. package/src/types/ComputedData.ts +55 -0
  197. package/src/types/PluginParams.ts +81 -0
  198. package/src/types/index.ts +3 -0
  199. package/src/utils/commonUtils.ts +31 -0
  200. package/src/utils/d3Graphics.ts +177 -0
  201. package/src/utils/d3Scale.ts +198 -0
  202. package/src/utils/d3Utils.ts +92 -0
  203. package/src/utils/graphObservables.ts +0 -0
  204. package/src/utils/gridObservables.ts +637 -0
  205. package/src/utils/multivariateObservables.ts +790 -0
  206. package/src/utils/observables.ts +357 -0
  207. package/src/utils/orbchartsUtils.ts +335 -0
  208. package/src/utils/seriesObservables.ts +172 -0
@@ -0,0 +1,776 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ switchMap,
6
+ takeUntil,
7
+ distinctUntilChanged,
8
+ shareReplay,
9
+ debounceTime,
10
+ Observable,
11
+ Subject } from 'rxjs'
12
+ import type { Theme, EventData } from '@orbcharts/core'
13
+ import type { CompositionPlotExtendContext, CompositionPlotPluginParams, PieParams } from "../types"
14
+ import type { PieDatum } from '../utils'
15
+ import { defineSVGLayer } from '@orbcharts/core'
16
+ import { validateObject } from '@orbcharts/core'
17
+ import { DEFAULT_PIE_PARAMS } from "../defaults"
18
+ import { seriesCenterSelectionObservable } from "../../../utils/seriesObservables"
19
+ import { getDatumColor } from '../../../utils/orbchartsUtils'
20
+ import { createClassName } from '../../../utils/orbchartsUtils'
21
+ import { makeD3Arc } from '../../../utils/d3Utils'
22
+ import { makePieData } from '../utils'
23
+ import type { ComputedDatumSeries } from '../../../types/ComputedData'
24
+ import type { ContainerPosition } from '../../../types/PluginParams'
25
+ import { LAYER_INDEX_OF_GRAPHIC } from '../../../const/layerIndex'
26
+
27
+ const pluginName = 'CompositionPlot'
28
+ const layerName = 'Pie'
29
+
30
+ function makeTweenPieRenderDataFn ({ enter, exit, data, lastTweenData, fullParams }: {
31
+ enter: d3.Selection<d3.EnterElement, PieDatum, any, any>
32
+ exit: d3.Selection<SVGPathElement, unknown, any, any>
33
+ data: PieDatum[]
34
+ lastTweenData: PieDatum[]
35
+ fullParams: PieParams
36
+ }): (t: number) => PieDatum[] {
37
+ // 無更新資料項目則只計算資料變化 (新資料 * t + 舊資料 * (1 - t))
38
+ if (!enter.size() && !exit.size()) {
39
+ // console.log('case1')
40
+ return (t: number) => {
41
+ const tweenData: PieDatum[] = data.map((_d, _i) => {
42
+ const lastDatum = lastTweenData[_i] ?? {
43
+ startAngle: 0,
44
+ endAngle: 0,
45
+ value: 0
46
+ }
47
+ return {
48
+ ..._d,
49
+ startAngle: (_d.startAngle * t) + (lastDatum.startAngle * (1 - t)),
50
+ endAngle: (_d.endAngle * t) + (lastDatum.endAngle * (1 - t)),
51
+ value: (_d.value * t) + (lastDatum.value * (1 - t))
52
+ }
53
+ })
54
+
55
+ return makePieRenderData(
56
+ tweenData,
57
+ fullParams.startAngle!,
58
+ fullParams.endAngle!,
59
+ 1
60
+ )
61
+ }
62
+ // 有更新資料則重新繪圖
63
+ } else {
64
+ // console.log('case2')
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, fullParams, theme }: {
89
+ selection: d3.Selection<SVGGElement, unknown, any, unknown>
90
+ data: PieDatum[]
91
+ arc: d3.Arc<any, d3.DefaultArcObject>
92
+ pathClassName: string
93
+ fullParams: PieParams
94
+ theme: Theme
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('stroke', (d, i) => getDatumColor({ datum: d.data, colorType: fullParams.strokeColorType, theme }))
105
+ .attr('stroke-width', fullParams.strokeWidth)
106
+ .attr('d', (d, i) => {
107
+ return arc!(d as any)
108
+ })
109
+
110
+ return pathSelection
111
+ }
112
+
113
+ // function renderGauge ({ selection, data, arc, pathClassName, fullParams, fullChartParams, axisWidth }: {
114
+ // selection: d3.Selection<SVGGElement, unknown, any, unknown>
115
+ // data: PieDatum[]
116
+ // arc: d3.Arc<any, d3.DefaultArcObject>
117
+ // pathClassName: string
118
+ // fullParams: PieParams
119
+ // fullChartParams: ChartParams
120
+ // axisWidth: number
121
+ // }) {
122
+ // const gaugeClassName = createClassName('Gauge', 'tick')
123
+ // const gaugeLabelClassName = createClassName('Gauge', 'label')
124
+
125
+ // // 計算總角度範圍
126
+ // const totalAngle = fullParams.endAngle - fullParams.startAngle
127
+ // const totalTicks = 20 // 總刻度數量
128
+ // const tickInterval = totalAngle / totalTicks
129
+
130
+ // // 計算刻度資料
131
+ // const tickData = Array.from({ length: totalTicks + 1 }, (_, i) => {
132
+ // const angle = fullParams.startAngle + (i * tickInterval)
133
+ // const isLongTick = i % 5 === 0 // 每5格一個長線
134
+ // return {
135
+ // angle,
136
+ // isLongTick,
137
+ // value: Math.round((i / totalTicks) * 100) // 0-100的數值
138
+ // }
139
+ // })
140
+
141
+ // // 計算實際像素半徑
142
+ // const arcScale = d3.scaleLinear()
143
+ // .domain([0, 1])
144
+ // .range([0, axisWidth / 2])
145
+
146
+ // const outerRadius = arcScale(fullParams.outerRadius)
147
+ // const innerRadius = arcScale(fullParams.innerRadius)
148
+ // const longTickLength = (outerRadius - innerRadius) * 0.3
149
+ // const shortTickLength = (outerRadius - innerRadius) * 0.15
150
+
151
+ // // 繪製刻度線
152
+ // const tickSelection = selection
153
+ // .selectAll(`line.${gaugeClassName}`)
154
+ // .data(tickData)
155
+ // .join('line')
156
+ // .classed(gaugeClassName, true)
157
+ // .attr('x1', d => {
158
+ // const radius = outerRadius
159
+ // return Math.cos(d.angle - Math.PI / 2) * radius
160
+ // })
161
+ // .attr('y1', d => {
162
+ // const radius = outerRadius
163
+ // return Math.sin(d.angle - Math.PI / 2) * radius
164
+ // })
165
+ // .attr('x2', d => {
166
+ // const radius = outerRadius - (d.isLongTick ? longTickLength : shortTickLength)
167
+ // return Math.cos(d.angle - Math.PI / 2) * radius
168
+ // })
169
+ // .attr('y2', d => {
170
+ // const radius = outerRadius - (d.isLongTick ? longTickLength : shortTickLength)
171
+ // return Math.sin(d.angle - Math.PI / 2) * radius
172
+ // })
173
+ // .attr('stroke', fullChartParams.colors[fullChartParams.colorScheme].primary)
174
+ // .attr('stroke-width', d => d.isLongTick ? 2 : 1)
175
+ // .attr('stroke-linecap', 'round')
176
+
177
+ // // 繪製數字標籤(只在長線上)
178
+ // const labelSelection = selection
179
+ // .selectAll(`text.${gaugeLabelClassName}`)
180
+ // .data(tickData.filter(d => d.isLongTick))
181
+ // .join('text')
182
+ // .classed(gaugeLabelClassName, true)
183
+ // .attr('x', d => {
184
+ // const radius = outerRadius + 15 // 稍微往外一點
185
+ // return Math.cos(d.angle - Math.PI / 2) * radius
186
+ // })
187
+ // .attr('y', d => {
188
+ // const radius = outerRadius + 15
189
+ // return Math.sin(d.angle - Math.PI / 2) * radius
190
+ // })
191
+ // .attr('text-anchor', 'middle')
192
+ // .attr('dominant-baseline', 'middle')
193
+ // .attr('fill', fullChartParams.colors[fullChartParams.colorScheme].primary)
194
+ // .attr('font-size', '12px')
195
+ // .text(d => d.value)
196
+
197
+ // return { tickSelection, labelSelection }
198
+ // }
199
+
200
+ function highlight ({ pathSelection, ids, styles, arc, arcHighlight }: {
201
+ pathSelection: d3.Selection<SVGPathElement, PieDatum, any, any>
202
+ ids: string[]
203
+ styles: CompositionPlotPluginParams['styles']
204
+ arc: d3.Arc<any, d3.DefaultArcObject>
205
+ arcHighlight: d3.Arc<any, d3.DefaultArcObject>
206
+ }) {
207
+ pathSelection.interrupt('highlight')
208
+
209
+ if (!ids.length) {
210
+ // 取消放大
211
+ pathSelection
212
+ .transition('highlight')
213
+ .style('opacity', 1)
214
+ .attr('d', (d) => {
215
+ return arc!(d as any)
216
+ })
217
+ return
218
+ }
219
+
220
+ pathSelection.each((d, i, n) => {
221
+ const segment = d3.select(n[i])
222
+
223
+ if (ids.includes(d.data.id)) {
224
+ segment
225
+ .style('opacity', 1)
226
+ .transition('highlight')
227
+ .ease(d3.easeElastic)
228
+ .duration(500)
229
+ .attr('d', (d: any) => {
230
+ return arcHighlight!(d)
231
+ })
232
+ // .on('interrupt', () => {
233
+ // // this.pathSelection!.select('path').attr('d', (d) => {
234
+ // // return this.arc!(d as any)
235
+ // // })
236
+ // this.initHighlight()
237
+ // })
238
+ } else {
239
+ // 取消放大
240
+ segment
241
+ .style('opacity', styles.unhighlightedOpacity)
242
+ .transition('highlight')
243
+ .attr('d', (d) => {
244
+ return arc!(d as any)
245
+ })
246
+ }
247
+ })
248
+ }
249
+
250
+ // 各別的pie
251
+ function createEachPie (context: {
252
+ containerSelection: d3.Selection<SVGGElement, any, any, unknown>
253
+ // computedData$: Observable<ComputedDatumSeries[][]>
254
+ containerVisibleComputedSortedData$: Observable<ComputedDatumSeries[]>
255
+ // SeriesDataMap$: Observable<Map<string, ComputedDatumSeries[]>>
256
+ fullParams$: Observable<PieParams>
257
+ // fullChartParams$: Observable<ChartParams>
258
+ theme$: Observable<Theme>
259
+ pluginParams$: Observable<CompositionPlotPluginParams>
260
+ seriesHighlight$: Observable<ComputedDatumSeries[]>
261
+ seriesContainerPosition$: Observable<ContainerPosition>
262
+ eventTrigger$: Subject<EventData<'series'>>
263
+ }) {
264
+ const destroy$ = new Subject()
265
+
266
+ const pathClassName = createClassName(pluginName, layerName, 'path')
267
+
268
+ let lastTweenData: PieDatum[] = [] // 紀錄補間動畫前次的資料
269
+ let tweenData: PieDatum[] = [] // 紀錄補間動畫用的資料
270
+ // let originHighlight: Highlight | null = null
271
+
272
+ // context.layout$
273
+ // .pipe(
274
+ // first()
275
+ // )
276
+ // .subscribe(size => {
277
+ // selection
278
+ // .attr('transform', `translate(${size.width / 2}, ${size.height / 2})`)
279
+ // context.layout$
280
+ // .pipe(
281
+ // takeUntil(destroy$)
282
+ // )
283
+ // .subscribe(size => {
284
+ // selection
285
+ // .transition()
286
+ // .attr('transform', `translate(${size.width / 2}, ${size.height / 2})`)
287
+ // })
288
+ // })
289
+
290
+
291
+ const shorterSideWith$ = context.seriesContainerPosition$.pipe(
292
+ takeUntil(destroy$),
293
+ map(d => d.width < d.height ? d.width : d.height),
294
+ distinctUntilChanged()
295
+ )
296
+
297
+ const pieData$: Observable<PieDatum[]> = new Observable(subscriber => {
298
+ combineLatest({
299
+ containerVisibleComputedSortedData: context.containerVisibleComputedSortedData$,
300
+ fullParams: context.fullParams$,
301
+ }).pipe(
302
+ takeUntil(destroy$),
303
+ debounceTime(0),
304
+ ).subscribe(data => {
305
+ // console.log('pieData', data)
306
+ const pieData: PieDatum[] = makePieData({
307
+ data: data.containerVisibleComputedSortedData,
308
+ startAngle: data.fullParams.startAngle,
309
+ endAngle: data.fullParams.endAngle
310
+ })
311
+ // console.log('pieData', pieData)
312
+ subscriber.next(pieData)
313
+ })
314
+ })
315
+
316
+ // const SeriesDataMap$ = context.computedData$.pipe(
317
+ // takeUntil(destroy$),
318
+ // map(d => makeSeriesDataMap(d))
319
+ // )
320
+
321
+ const arc$: Observable<d3.Arc<any, d3.DefaultArcObject>> = new Observable(subscriber => {
322
+ combineLatest({
323
+ shorterSideWith: shorterSideWith$,
324
+ fullParams: context.fullParams$,
325
+ }).pipe(
326
+ takeUntil(destroy$),
327
+ debounceTime(0),
328
+ ).subscribe(data => {
329
+ const arc = makeD3Arc({
330
+ axisWidth: data.shorterSideWith,
331
+ innerRadius: data.fullParams.innerRadius,
332
+ outerRadius: data.fullParams.outerRadius,
333
+ padAngle: data.fullParams.padAngle,
334
+ cornerRadius: data.fullParams.cornerRadius
335
+ })
336
+ subscriber.next(arc)
337
+ })
338
+ })
339
+
340
+ const arcHighlight$: Observable<d3.Arc<any, d3.DefaultArcObject>> = new Observable(subscriber => {
341
+ combineLatest({
342
+ shorterSideWith: shorterSideWith$,
343
+ fullParams: context.fullParams$,
344
+ }).pipe(
345
+ takeUntil(destroy$),
346
+ debounceTime(0),
347
+ ).subscribe(data => {
348
+ const arcHighlight = makeD3Arc({
349
+ axisWidth: data.shorterSideWith,
350
+ innerRadius: data.fullParams.innerRadius,
351
+ outerRadius: data.fullParams.outerRadiusWhileHighlight, // 外半徑變化
352
+ padAngle: data.fullParams.padAngle,
353
+ cornerRadius: data.fullParams.cornerRadius
354
+ })
355
+ subscriber.next(arcHighlight)
356
+ })
357
+ })
358
+
359
+ const highlightTarget$ = context.pluginParams$.pipe(
360
+ takeUntil(destroy$),
361
+ map(d => d.styles.highlightTarget),
362
+ distinctUntilChanged()
363
+ )
364
+
365
+ // highlight的對象(不做成observable是因為要避免觸發監聽)
366
+ let seriesHighlight: ComputedDatumSeries[] = []
367
+ context.seriesHighlight$
368
+ .pipe(
369
+ takeUntil(destroy$)
370
+ )
371
+ .subscribe(d => seriesHighlight = d)
372
+
373
+ const pathSelection$ = new Observable<d3.Selection<SVGPathElement, PieDatum, any, any>>(subscriber => {
374
+ combineLatest({
375
+ pieData: pieData$,
376
+ arc: arc$,
377
+ // computedData: context.computedData$,
378
+ fullParams: context.fullParams$,
379
+ styles: context.pluginParams$.pipe(map(d => d.styles)),
380
+ theme: context.theme$,
381
+ // highlightTarget: highlightTarget$
382
+ }).pipe(
383
+ takeUntil(destroy$),
384
+ debounceTime(0)
385
+ ).subscribe(data => {
386
+
387
+ context.containerSelection.interrupt('graphicMove')
388
+ // console.log('graphic', data)
389
+ const update: d3.Selection<SVGPathElement, PieDatum, any, any> = context.containerSelection
390
+ .selectAll<SVGPathElement, PieDatum>('path')
391
+ .data(data.pieData, d => d.id)
392
+ const enter = update.enter()
393
+ const exit = update.exit()
394
+
395
+ const makeTweenPieRenderData = makeTweenPieRenderDataFn({
396
+ enter,
397
+ exit,
398
+ data: data.pieData,
399
+ lastTweenData,
400
+ fullParams: data.fullParams
401
+ })
402
+
403
+ // -- 使用補間動畫 --
404
+ context.containerSelection
405
+ .transition('graphicMove')
406
+ .duration(data.styles.transitionDuration)
407
+ // .ease(getD3TransitionEase(data.fullChartParams.transitionEase))
408
+ .tween('move', (self, t) => {
409
+ return (t) => {
410
+ tweenData = makeTweenPieRenderData(t)
411
+
412
+ renderPie({
413
+ selection: context.containerSelection,
414
+ data: tweenData,
415
+ arc: data.arc,
416
+ pathClassName,
417
+ fullParams: data.fullParams,
418
+ theme: data.theme,
419
+ })
420
+
421
+ // renderGauge({
422
+ // selection: context.containerSelection,
423
+ // data: tweenData,
424
+ // arc: data.arc,
425
+ // pathClassName,
426
+ // fullParams: data.fullParams,
427
+ // fullChartParams: data.fullChartParams,
428
+ // axisWidth: 500
429
+ // })
430
+
431
+ // @Q@ 想盡量減清效能負擔所以取消掉
432
+ // context.eventTrigger$.next({
433
+ // type: 'series',
434
+ // pluginName,
435
+ // eventName: 'transitionMove',
436
+ // event: undefined,
437
+ // highlightTarget: data.highlightTarget,
438
+ // datum: null,
439
+ // series: [],
440
+ // seriesIndex: -1,
441
+ // seriesLabel: '',
442
+ // data: data.computedData
443
+ // })
444
+
445
+ // const callbackData = makeEnterDurationCallbackData(data.computedData, )
446
+ // enterDurationCallback(callbackData, t)
447
+ }
448
+ })
449
+ .on('end', (self, t) => {
450
+ tweenData = makePieRenderData(
451
+ data.pieData,
452
+ data.fullParams.startAngle,
453
+ data.fullParams.endAngle,
454
+ 1
455
+ )
456
+ // console.log('tweenData', tweenData)
457
+ const pathSelection = renderPie({
458
+ selection: context.containerSelection,
459
+ data: tweenData,
460
+ arc: data.arc,
461
+ pathClassName,
462
+ fullParams: data.fullParams,
463
+ theme: data.theme,
464
+ })
465
+
466
+ // if (data.fullParams.highlightTarget && data.fullParams.highlightTarget != 'none') {
467
+ // if (data.fullChartParams.highlightTarget && data.fullChartParams.highlightTarget != 'none') {
468
+ // pathSelection!.style('cursor', 'pointer')
469
+ // }
470
+
471
+ subscriber.next(pathSelection)
472
+
473
+ // pathSelection && setPathEvent({
474
+ // pathSelection,
475
+ // pluginName: name,
476
+ // data: data.computedData,
477
+ // fullChartParams: data.fullChartParams,
478
+ // arc: data.arc,
479
+ // arcHighlight: data.arcHighlight,
480
+ // SeriesDataMap: data.SeriesDataMap,
481
+ // eventTrigger$: store.eventTrigger$
482
+ // })
483
+
484
+ // 渲染完後紀錄為前次的資料
485
+ lastTweenData = Object.assign([], data.pieData)
486
+
487
+ context.eventTrigger$.next({
488
+ // type: 'series',
489
+ // pluginName,
490
+ // eventName: 'transitionEnd',
491
+ // event: undefined,
492
+ // highlightTarget: data.highlightTarget,
493
+ // data: data.computedData,
494
+ // series: [],
495
+ // seriesIndex: -1,
496
+ // seriesLabel: '',
497
+ // datum: null
498
+ eventName: 'transitionEnd',
499
+ pluginName,
500
+ layerName,
501
+ target: null,
502
+ event: undefined
503
+ })
504
+
505
+ })
506
+
507
+ // -- 更新資料 --
508
+ // if (!enter.size() && update.size() > 0) {
509
+ // // console.log('test')
510
+ // const pathSelection = renderPie({
511
+ // selection: context.containerSelection,
512
+ // data: data.pieData,
513
+ // arc: data.arc,
514
+ // pathClassName
515
+ // })
516
+ // subscriber.next(pathSelection)
517
+ // }
518
+ })
519
+ }).pipe(
520
+ shareReplay(1)
521
+ )
522
+
523
+ // pathSelection$.subscribe(data => {
524
+ // console.log('pathSelection', data)
525
+ // })
526
+ // context.SeriesDataMap$.subscribe(data => {
527
+ // console.log('SeriesDataMap', data)
528
+ // })
529
+ // context.computedData$.subscribe(data => {
530
+ // console.log('computedData', data)
531
+ // })
532
+ // highlightTarget$.subscribe(data => {
533
+ // console.log('highlightTarget', data)
534
+ // })
535
+
536
+ combineLatest({
537
+ pathSelection: pathSelection$,
538
+ // SeriesDataMap: context.SeriesDataMap$,
539
+ // computedData: context.computedData$,
540
+ highlightTarget: highlightTarget$
541
+ }).pipe(
542
+ takeUntil(destroy$),
543
+ debounceTime(0)
544
+ ).subscribe(data => {
545
+ data.pathSelection
546
+ .on('mouseover', (event, pieDatum) => {
547
+ // event.stopPropagation()
548
+ context.eventTrigger$.next({
549
+ // type: 'series',
550
+ // eventName: 'mouseover',
551
+ // pluginName,
552
+ // highlightTarget: data.highlightTarget,
553
+ // datum: pieDatum.data,
554
+ // series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
555
+ // seriesIndex: pieDatum.data.seriesIndex,
556
+ // seriesLabel: pieDatum.data.seriesLabel,
557
+ // event,
558
+ // data: data.computedData
559
+ eventName: 'mouseover',
560
+ pluginName,
561
+ layerName,
562
+ target: pieDatum.data,
563
+ event
564
+ })
565
+ })
566
+ .on('mousemove', (event, pieDatum) => {
567
+ event.stopPropagation()
568
+
569
+ context.eventTrigger$.next({
570
+ // type: 'series',
571
+ // eventName: 'mousemove',
572
+ // pluginName,
573
+ // highlightTarget: data.highlightTarget,
574
+ // datum: pieDatum.data,
575
+ // series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
576
+ // seriesIndex: pieDatum.data.seriesIndex,
577
+ // seriesLabel: pieDatum.data.seriesLabel,
578
+ // event,
579
+ // data: data.computedData,
580
+ eventName: 'mousemove',
581
+ pluginName,
582
+ layerName,
583
+ target: pieDatum.data,
584
+ event
585
+ })
586
+ })
587
+ .on('mouseout', (event, pieDatum) => {
588
+ event.stopPropagation()
589
+
590
+ context.eventTrigger$.next({
591
+ // type: 'series',
592
+ // eventName: 'mouseout',
593
+ // pluginName,
594
+ // highlightTarget: data.highlightTarget,
595
+ // datum: pieDatum.data,
596
+ // series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
597
+ // seriesIndex: pieDatum.data.seriesIndex,
598
+ // seriesLabel: pieDatum.data.seriesLabel,
599
+ // event,
600
+ // data: data.computedData,
601
+ eventName: 'mouseout',
602
+ pluginName,
603
+ layerName,
604
+ target: pieDatum.data,
605
+ event
606
+ })
607
+ })
608
+ .on('click', (event, pieDatum) => {
609
+ event.stopPropagation()
610
+
611
+ context.eventTrigger$.next({
612
+ // type: 'series',
613
+ // eventName: 'click',
614
+ // pluginName,
615
+ // highlightTarget: data.highlightTarget,
616
+ // datum: pieDatum.data,
617
+ // series: data.SeriesDataMap.get(pieDatum.data.seriesLabel)!,
618
+ // seriesIndex: pieDatum.data.seriesIndex,
619
+ // seriesLabel: pieDatum.data.seriesLabel,
620
+ // event,
621
+ // data: data.computedData,
622
+ eventName: 'click',
623
+ pluginName,
624
+ layerName,
625
+ target: pieDatum.data,
626
+ event
627
+ })
628
+ })
629
+ })
630
+
631
+ combineLatest({
632
+ pathSelection: pathSelection$,
633
+ highlight: context.seriesHighlight$.pipe(
634
+ map(data => data.map(d => d.id))
635
+ ),
636
+ styles: context.pluginParams$.pipe(
637
+ map(d => d.styles)
638
+ ),
639
+ arc: arc$,
640
+ arcHighlight: arcHighlight$
641
+ }).pipe(
642
+ takeUntil(destroy$),
643
+ debounceTime(0)
644
+ ).subscribe(data => {
645
+ highlight({
646
+ pathSelection: data.pathSelection,
647
+ ids: data.highlight,
648
+ styles: data.styles,
649
+ arc: data.arc,
650
+ arcHighlight: data.arcHighlight
651
+ })
652
+ })
653
+
654
+ return () => {
655
+ destroy$.next(undefined)
656
+ }
657
+ }
658
+
659
+ export const Pie = defineSVGLayer<CompositionPlotExtendContext, CompositionPlotPluginParams, PieParams>({
660
+ name: layerName,
661
+ defaultParams: DEFAULT_PIE_PARAMS,
662
+ layerIndex: LAYER_INDEX_OF_GRAPHIC,
663
+ initShow: false,
664
+ validator: (params) => {
665
+ const result = validateObject(params, {
666
+ outerRadius: {
667
+ toBeTypes: ['number'],
668
+ },
669
+ innerRadius: {
670
+ toBeTypes: ['number'],
671
+ },
672
+ outerRadiusWhileHighlight: {
673
+ toBeTypes: ['number'],
674
+ },
675
+ startAngle: {
676
+ toBeTypes: ['number'],
677
+ },
678
+ endAngle: {
679
+ toBeTypes: ['number'],
680
+ },
681
+ padAngle: {
682
+ toBeTypes: ['number'],
683
+ },
684
+ strokeColorType: {
685
+ toBeTypes: ['string'],
686
+ },
687
+ strokeWidth: {
688
+ toBeTypes: ['number'],
689
+ },
690
+ cornerRadius: {
691
+ toBeTypes: ['number'],
692
+ }
693
+ })
694
+
695
+ return result
696
+ },
697
+ setup: ({ svgG, pluginParams$, layerParams$, context }) => {
698
+
699
+ // const subscription = layerParams$.subscribe((params) => {
700
+ // // Handle params update
701
+ // })
702
+
703
+ // context.seriesData$.subscribe((data) => {
704
+ // // Handle series data update
705
+ // console.log(data)
706
+ // })
707
+ const destroy$ = new Subject()
708
+
709
+ context.layout$
710
+ .pipe(
711
+ takeUntil(destroy$)
712
+ )
713
+ .subscribe(layout => {
714
+ d3.select(svgG)
715
+ .attr('transform', `translate(${layout.left}, ${layout.top})`)
716
+ })
717
+
718
+ const { seriesCenterSelection$ } = seriesCenterSelectionObservable({
719
+ selection: d3.select(svgG),
720
+ pluginName,
721
+ layerName,
722
+ visibleComputedSortedData$: context.visibleComputedSortedData$,
723
+ seriesContainerPosition$: context.seriesContainerPosition$
724
+ })
725
+
726
+ const unsubscribeFnArr: (() => void)[] = []
727
+
728
+ seriesCenterSelection$
729
+ .pipe(
730
+ takeUntil(destroy$)
731
+ )
732
+ .subscribe(seriesCenterSelection => {
733
+ // 每次重新計算時,清除之前的訂閱
734
+ unsubscribeFnArr.forEach(fn => fn())
735
+
736
+ // observer.fullParams$.subscribe(data => {
737
+ // console.log('observer.fullParams$', data)
738
+ // })
739
+
740
+ seriesCenterSelection.each((d, containerIndex, g) => {
741
+ // console.log('containerIndex', containerIndex)
742
+ const containerSelection = d3.select(g[containerIndex])
743
+
744
+ const containerVisibleComputedSortedData$ = context.visibleComputedSortedData$.pipe(
745
+ takeUntil(destroy$),
746
+ map(data => data[containerIndex] ?? data[0])
747
+ )
748
+
749
+ const containerPosition$ = context.seriesContainerPosition$.pipe(
750
+ takeUntil(destroy$),
751
+ map(data => data[containerIndex] ?? data[0])
752
+ )
753
+
754
+ unsubscribeFnArr[containerIndex] = createEachPie({
755
+ containerSelection: containerSelection,
756
+ // computedData$: context.computedData$,
757
+ containerVisibleComputedSortedData$: containerVisibleComputedSortedData$,
758
+ // SeriesDataMap$: context.SeriesDataMap$,
759
+ fullParams$: layerParams$,
760
+ theme$: context.theme$,
761
+ pluginParams$: pluginParams$,
762
+ seriesHighlight$: context.seriesHighlight$,
763
+ seriesContainerPosition$: containerPosition$,
764
+ eventTrigger$: context.eventTrigger$,
765
+ })
766
+
767
+ })
768
+ })
769
+
770
+ return () => {
771
+ // subscription.unsubscribe()
772
+ destroy$.next(undefined)
773
+ unsubscribeFnArr.forEach(fn => fn())
774
+ }
775
+ }
776
+ })