@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,783 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ debounceTime,
6
+ switchMap,
7
+ takeUntil,
8
+ distinctUntilChanged,
9
+ shareReplay,
10
+ Observable,
11
+ Subject } from 'rxjs'
12
+ import type { BaseLayerFn } from '../types/BaseLayer'
13
+ import type { EventData } from '@orbcharts/core'
14
+ import type {
15
+ ComputedDatumGrid,
16
+ ComputedData,
17
+ ContainerPositionScaled,
18
+ Layout,
19
+ TransformData,
20
+ GraphicStyles} from '../types'
21
+ import type { ComputedAxesDataGrid } from '../plugins/SeriesPlot/types'
22
+ import { getD3TransitionEase } from '../utils/d3Utils'
23
+ import { createClassName, createUniID } from '../utils/orbchartsUtils'
24
+ import { gridSelectionsObservable } from '../utils/gridObservables'
25
+
26
+ export interface BaseBarsParams {
27
+ barWidth: number;
28
+ barPadding: number;
29
+ barGroupPadding: number;
30
+ barRadius: number | boolean;
31
+ }
32
+
33
+ interface BaseBarsContext {
34
+ selection: d3.Selection<any, unknown, any, unknown>
35
+ pluginName: string
36
+ layerName: string
37
+ computedData$: Observable<ComputedData<'grid'>>
38
+ visibleComputedData$: Observable<ComputedDatumGrid[][]>
39
+ visibleComputedAxesData$: Observable<ComputedAxesDataGrid>
40
+ seriesLabels$: Observable<string[]>
41
+ SeriesDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
42
+ CategoryDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
43
+ baseBarsParams$: Observable<BaseBarsParams>
44
+ gridAxesTransform$: Observable<TransformData>
45
+ gridGraphicTransform$: Observable<TransformData>
46
+ gridGraphicReverseScale$: Observable<[number, number][]>
47
+ gridAxesSize$: Observable<{
48
+ width: number;
49
+ height: number;
50
+ }>
51
+ gridHighlight$: Observable<ComputedDatumGrid[]>
52
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
53
+ isSeriesSeprate$: Observable<boolean>
54
+ styles$: Observable<GraphicStyles>
55
+ eventTrigger$: Subject<EventData<'grid'>>
56
+ }
57
+
58
+ interface RenderBarParams {
59
+ graphicGSelection: d3.Selection<SVGGElement, string, any, any>
60
+ rectClassName: string
61
+ visibleComputedAxesData: ComputedAxesDataGrid
62
+ zeroYArr: number[]
63
+ barScale: d3.ScalePoint<string>
64
+ styles: GraphicStyles
65
+ barWidth: number
66
+ transformedBarRadius: [number, number][]
67
+ delayGroup: number
68
+ transitionItem: number
69
+ isSeriesSeprate: boolean
70
+ }
71
+
72
+ type ClipPathDatum = {
73
+ id: string;
74
+ // x: number;
75
+ // y: number;
76
+ width: number;
77
+ height: number;
78
+ }
79
+
80
+ // const pluginName = 'Bars'
81
+ // const rectClassName = createClassName(pluginName, 'rect')
82
+ // group的delay在動畫中的佔比(剩餘部份的時間為圖形本身的動畫時間,因為delay時間和最後一個group的動畫時間加總為1)
83
+ const groupDelayProportionOfDuration = 0.3
84
+
85
+ function calcBarWidth ({ axisWidth, groupAmount, barAmountOfGroup, barPadding = 0, barGroupPadding = 0 }: {
86
+ axisWidth: number
87
+ groupAmount: number
88
+ barAmountOfGroup: number
89
+ barPadding: number
90
+ barGroupPadding: number
91
+ }) {
92
+ const eachGroupWidth = groupAmount > 1 // 等於 1 時會算出 Infinity
93
+ ? axisWidth / (groupAmount - 1) // -1是因為要扣掉兩側的padding
94
+ : axisWidth
95
+ const width = (eachGroupWidth - barGroupPadding) / barAmountOfGroup - barPadding
96
+ return width > 1 ? width : 1
97
+ }
98
+
99
+ function makeBarScale (barWidth: number, seriesLabels: string[], params: BaseBarsParams) {
100
+ const barHalfWidth = barWidth! / 2
101
+ const barGroupWidth = barWidth * seriesLabels.length + params.barPadding! * seriesLabels.length
102
+ return d3.scalePoint()
103
+ .domain(seriesLabels)
104
+ .range([-barGroupWidth / 2 + barHalfWidth, barGroupWidth / 2 - barHalfWidth])
105
+ }
106
+
107
+ function calcDelayGroup (barGroupAmount: number, totalDuration: number) {
108
+ if (barGroupAmount <= 1) {
109
+ // 一筆內計算會出錯所以不算
110
+ return 0
111
+ }
112
+ return totalDuration / (barGroupAmount - 1) * groupDelayProportionOfDuration // 依group數量計算
113
+ }
114
+
115
+ function calctransitionItem (barGroupAmount: number, totalDuration: number) {
116
+ if (barGroupAmount <= 1) {
117
+ // 一筆內不會有delay
118
+ return totalDuration
119
+ }
120
+ return totalDuration * (1 - groupDelayProportionOfDuration) // delay後剩餘的時間
121
+ }
122
+ // let _data: ComputedDatumGrid[][] = []
123
+
124
+ function renderRectBars ({ graphicGSelection, rectClassName, visibleComputedAxesData, zeroYArr, barScale, styles, barWidth, transformedBarRadius, delayGroup, transitionItem, isSeriesSeprate }: RenderBarParams) {
125
+
126
+ const barHalfWidth = barWidth! / 2
127
+
128
+ graphicGSelection
129
+ .each((seriesData, seriesIndex, g) => {
130
+ d3.select(g[seriesIndex])
131
+ .selectAll<SVGGElement, ComputedDatumGrid>(`rect.${rectClassName}`)
132
+ .data(visibleComputedAxesData[seriesIndex] ?? [], d => d.id)
133
+ .join(
134
+ enter => {
135
+ // console.log('enter')
136
+ return enter
137
+ .append('rect')
138
+ .classed(rectClassName, true)
139
+ .attr('cursor', 'pointer')
140
+ .attr('height', d => 1)
141
+ },
142
+ update => update,
143
+ exit => exit.remove()
144
+ )
145
+ .attr('transform', (d, i) => `translate(${(d ? d.axisX : 0) - barHalfWidth}, ${0})`)
146
+ .attr('fill', d => d.color)
147
+ .attr('y', d => d.axisY < zeroYArr[seriesIndex] ? d.axisY : zeroYArr[seriesIndex])
148
+ .attr('x', d => isSeriesSeprate ? 0 : barScale(d.series)!)
149
+ .attr('width', barWidth!)
150
+ .attr('rx', transformedBarRadius[seriesIndex][0] ?? 1)
151
+ .attr('ry', transformedBarRadius[seriesIndex][1] ?? 1)
152
+ .transition()
153
+ .duration(transitionItem)
154
+ .ease(getD3TransitionEase(styles.transitionEase))
155
+ .delay((d, i) => d.categoryIndex * delayGroup)
156
+ .attr('height', d => Math.abs(d.axisYFromZero) || 1) // 無值還是給一個 1 的高度
157
+ })
158
+
159
+
160
+ // graphicGSelection
161
+ // .each((d, seriesIndex, g) => {
162
+ // d3.select(g[seriesIndex])
163
+ // .selectAll<SVGGElement, ComputedDatumGrid>(`g.${barClassName}`)
164
+ // .data(computedData[seriesIndex], d => d.seriesIndex)
165
+ // .join('g')
166
+ // .classed(barClassName, true)
167
+ // .attr('transform', (d, i) => `translate(${d ? d.axisX : 0}, ${0})`)
168
+ // .each((datum, i, g) => {
169
+ // d3.select(g[i])
170
+ // .selectAll<SVGRectElement, ComputedDatumGrid>(`rect.${rectClassName}`)
171
+ // .data([computedData[seriesIndex][i]], d => d.id)
172
+ // .join(
173
+ // enter => {
174
+ // return enter
175
+ // .append('rect')
176
+ // .classed(rectClassName, true)
177
+ // .attr('height', d => 0)
178
+ // },
179
+ // update => update,
180
+ // exit => exit.remove()
181
+ // )
182
+ // .attr('cursor', 'pointer')
183
+ // .attr('fill', d => d.color)
184
+ // .attr('y', d => d.axisY < zeroYArr[seriesIndex] ? d.axisY : zeroYArr[seriesIndex])
185
+ // .attr('x', d => isSeriesSeprate ? 0 : barScale(d.seriesLabel)!)
186
+ // .attr('width', barWidth!)
187
+ // .attr('transform', `translate(${-barHalfWidth}, 0)`)
188
+ // // .attr('rx', params.barRadius == true ? barHalfWidth
189
+ // // : params.barRadius == false ? 0
190
+ // // : typeof params.barRadius == 'number' ? params.barRadius
191
+ // // : 0)
192
+ // .attr('rx', transformedBarRadius[0])
193
+ // .attr('ry', transformedBarRadius[1])
194
+ // .transition()
195
+ // .duration(transitionItem)
196
+ // .ease(getD3TransitionEase(chartParams.transitionEase))
197
+ // .delay((d, i) => d.groupIndex * delayGroup)
198
+ // .attr('height', d => Math.abs(d.axisYFromZero))
199
+ // })
200
+ // })
201
+
202
+ const graphicBarSelection: d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown> = graphicGSelection.selectAll(`rect.${rectClassName}`)
203
+
204
+ return graphicBarSelection
205
+ }
206
+
207
+ function renderClipPath ({ defsSelection, clipPathData }: {
208
+ defsSelection: d3.Selection<SVGDefsElement, any, any, any>
209
+ clipPathData: ClipPathDatum[]
210
+ }) {
211
+ const clipPath = defsSelection
212
+ .selectAll<SVGClipPathElement, Layout>('clipPath')
213
+ .data(clipPathData)
214
+ .join(
215
+ enter => {
216
+ return enter
217
+ .append('clipPath')
218
+ },
219
+ update => update,
220
+ exit => exit.remove()
221
+ )
222
+ .attr('id', d => d.id)
223
+ .each((d, i, g) => {
224
+ const rect = d3.select(g[i])
225
+ .selectAll<SVGRectElement, typeof d>('rect')
226
+ .data([d])
227
+ .join(
228
+ enter => {
229
+ return enter
230
+ .append('rect')
231
+ },
232
+ update => update,
233
+ exit => exit.remove()
234
+ )
235
+ .attr('x', 0)
236
+ .attr('y', 0)
237
+ .attr('width', _d => _d.width)
238
+ .attr('height', _d => _d.height)
239
+ })
240
+ }
241
+
242
+ function highlight ({ selection, ids, styles }: {
243
+ selection: d3.Selection<any, ComputedDatumGrid, any, any>
244
+ ids: string[]
245
+ styles: GraphicStyles
246
+ }) {
247
+ selection.interrupt('highlight')
248
+
249
+ if (!ids.length) {
250
+ // remove highlight
251
+ selection
252
+ .transition('highlight')
253
+ .duration(200)
254
+ .style('opacity', 1)
255
+ return
256
+ }
257
+
258
+ selection
259
+ .each((d, i, n) => {
260
+ if (ids.includes(d.id)) {
261
+ d3.select(n[i])
262
+ .style('opacity', 1)
263
+ } else {
264
+ d3.select(n[i])
265
+ .style('opacity', styles.unhighlightedOpacity)
266
+ }
267
+ })
268
+ }
269
+
270
+
271
+ export const createBaseBars: BaseLayerFn<BaseBarsContext> = ({
272
+ selection,
273
+ pluginName,
274
+ layerName,
275
+ computedData$,
276
+ visibleComputedData$,
277
+ visibleComputedAxesData$,
278
+ seriesLabels$,
279
+ SeriesDataMap$,
280
+ CategoryDataMap$,
281
+ baseBarsParams$,
282
+ gridAxesTransform$,
283
+ gridGraphicTransform$,
284
+ gridGraphicReverseScale$,
285
+ gridAxesSize$,
286
+ gridHighlight$,
287
+ gridContainerPosition$,
288
+ isSeriesSeprate$,
289
+ styles$,
290
+ eventTrigger$
291
+ }) => {
292
+
293
+ const destroy$ = new Subject()
294
+
295
+ const clipPathID = createUniID(pluginName, layerName, 'clipPath-box')
296
+ const rectClassName = createClassName(pluginName, layerName, 'rect')
297
+
298
+ // const seriesSelection$ = computedData$.pipe(
299
+ // takeUntil(destroy$),
300
+ // distinctUntilChanged((a, b) => {
301
+ // // 只有當series的數量改變時,才重新計算
302
+ // return a.length === b.length
303
+ // }),
304
+ // map((computedData, i) => {
305
+ // return selection
306
+ // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${seriesClassName}`)
307
+ // .data(computedData, d => d[0] ? d[0].seriesIndex : i)
308
+ // .join(
309
+ // enter => {
310
+ // return enter
311
+ // .append('g')
312
+ // .classed(seriesClassName, true)
313
+ // .each((d, i, g) => {
314
+ // const axesSelection = d3.select(g[i])
315
+ // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${axesClassName}`)
316
+ // .data([i])
317
+ // .join(
318
+ // enter => {
319
+ // return enter
320
+ // .append('g')
321
+ // .classed(axesClassName, true)
322
+ // .attr('clip-path', `url(#${clipPathID})`)
323
+ // .each((d, i, g) => {
324
+ // const defsSelection = d3.select(g[i])
325
+ // .selectAll<SVGDefsElement, any>('defs')
326
+ // .data([i])
327
+ // .join('defs')
328
+
329
+ // const graphicGSelection = d3.select(g[i])
330
+ // .selectAll<SVGGElement, any>('g')
331
+ // .data([i])
332
+ // .join('g')
333
+ // .classed(graphicClassName, true)
334
+ // })
335
+ // },
336
+ // update => update,
337
+ // exit => exit.remove()
338
+ // )
339
+ // })
340
+ // },
341
+ // update => update,
342
+ // exit => exit.remove()
343
+ // )
344
+ // })
345
+ // )
346
+
347
+ // combineLatest({
348
+ // seriesSelection: seriesSelection$,
349
+ // gridContainerPosition: gridContainerPosition$
350
+ // }).pipe(
351
+ // takeUntil(destroy$),
352
+ // debounceTime(0)
353
+ // ).subscribe(data => {
354
+ // data.seriesSelection
355
+ // .transition()
356
+ // .attr('transform', (d, i) => {
357
+ // const translate = data.gridContainerPosition[i].translate
358
+ // const scale = data.gridContainerPosition[i].scale
359
+ // return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
360
+ // })
361
+ // })
362
+
363
+
364
+ // const axesSelection$ = combineLatest({
365
+ // seriesSelection: seriesSelection$,
366
+ // gridAxesTransform: gridAxesTransform$
367
+ // }).pipe(
368
+ // takeUntil(destroy$),
369
+ // debounceTime(0),
370
+ // map(data => {
371
+ // return data.seriesSelection
372
+ // .select<SVGGElement>(`g.${axesClassName}`)
373
+ // .style('transform', data.gridAxesTransform.value)
374
+ // })
375
+ // )
376
+ // const defsSelection$ = axesSelection$.pipe(
377
+ // takeUntil(destroy$),
378
+ // map(axesSelection => {
379
+ // return axesSelection.select<SVGDefsElement>('defs')
380
+ // })
381
+ // )
382
+ // const graphicGSelection$ = combineLatest({
383
+ // axesSelection: axesSelection$,
384
+ // gridGraphicTransform: gridGraphicTransform$
385
+ // }).pipe(
386
+ // takeUntil(destroy$),
387
+ // debounceTime(0),
388
+ // map(data => {
389
+ // const graphicGSelection = data.axesSelection
390
+ // .select<SVGGElement>(`g.${graphicClassName}`)
391
+ // graphicGSelection
392
+ // .transition()
393
+ // .duration(50)
394
+ // .style('transform', data.gridGraphicTransform.value)
395
+ // return graphicGSelection
396
+ // })
397
+ // )
398
+
399
+ const {
400
+ seriesSelection$,
401
+ axesSelection$,
402
+ defsSelection$,
403
+ graphicGSelection$
404
+ } = gridSelectionsObservable({
405
+ selection,
406
+ pluginName,
407
+ layerName,
408
+ clipPathID,
409
+ seriesLabels$,
410
+ gridContainerPosition$,
411
+ gridAxesTransform$,
412
+ gridGraphicTransform$
413
+ })
414
+
415
+ const zeroYArr$ = visibleComputedAxesData$.pipe(
416
+ takeUntil(destroy$),
417
+ map(data => {
418
+ return data.map(d => {
419
+ return d[0] ? d[0].axisY - d[0].axisYFromZero : 0
420
+ })
421
+ }),
422
+ distinctUntilChanged()
423
+ )
424
+
425
+ const barWidth$ = combineLatest({
426
+ computedData: computedData$,
427
+ visibleComputedData: visibleComputedData$,
428
+ params: baseBarsParams$,
429
+ gridAxesSize: gridAxesSize$,
430
+ isSeriesSeprate: isSeriesSeprate$
431
+ }).pipe(
432
+ takeUntil(destroy$),
433
+ debounceTime(0),
434
+ map(data => {
435
+ if (data.params.barWidth) {
436
+ return data.params.barWidth
437
+ } else if (data.isSeriesSeprate) {
438
+ return calcBarWidth({
439
+ axisWidth: data.gridAxesSize.width,
440
+ groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
441
+ barAmountOfGroup: 1,
442
+ barPadding: data.params.barPadding,
443
+ barGroupPadding: data.params.barGroupPadding
444
+ })
445
+ } else {
446
+ return calcBarWidth({
447
+ axisWidth: data.gridAxesSize.width,
448
+ groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
449
+ barAmountOfGroup: data.visibleComputedData.length,
450
+ barPadding: data.params.barPadding,
451
+ barGroupPadding: data.params.barGroupPadding
452
+ })
453
+ }
454
+ }),
455
+ distinctUntilChanged()
456
+ )
457
+
458
+ // 圓角的值 [rx, ry]
459
+ const transformedBarRadius$: Observable<[number, number][]> = combineLatest({
460
+ computedData: computedData$,
461
+ // gridGraphicTransform: gridGraphicTransform$,
462
+ barWidth: barWidth$,
463
+ params: baseBarsParams$,
464
+ // gridContainerPosition: gridContainerPosition$,
465
+ // gridAxesTransform: gridAxesTransform$
466
+ gridGraphicReverseScale: gridGraphicReverseScale$
467
+ }).pipe(
468
+ takeUntil(destroy$),
469
+ debounceTime(0),
470
+ map(data => {
471
+ const barHalfWidth = data.barWidth! / 2
472
+ const radius = data.params.barRadius === true ? barHalfWidth
473
+ : data.params.barRadius === false ? 0
474
+ : typeof data.params.barRadius == 'number' ? data.params.barRadius
475
+ : 0
476
+
477
+ return data.computedData.map((series, seriesIndex) => {
478
+ const gridGraphicReverseScale = data.gridGraphicReverseScale[seriesIndex] ?? data.gridGraphicReverseScale[0]
479
+
480
+ let transformedRx = radius * gridGraphicReverseScale[0]
481
+ let transformedRy = radius * gridGraphicReverseScale[1]
482
+ // if (radius == 0) {
483
+ // transformedRx = 0
484
+ // transformedRy = 0
485
+ // } else if (data.gridAxesTransform.rotate == 0) {
486
+ // transformedRx = radius
487
+ // // 抵消外層scale的變型
488
+ // / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[0].scale[0]
489
+ // transformedRy = radius
490
+ // // 抵消外層scale的變型
491
+ // / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[0].scale[1]
492
+ // } else if (data.gridAxesTransform.rotate != 0) {
493
+ // transformedRx = radius
494
+ // // 抵消外層scale的變型,由於有90度的旋轉,所以外層 (container) x和y的scale要互換
495
+ // / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[0].scale[1]
496
+ // transformedRy = radius
497
+ // // 抵消外層scale的變型,由於有90度的旋轉,所以外層 (container) x和y的scale要互換
498
+ // / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[0].scale[0]
499
+ // }
500
+
501
+ // 如果計算出來的x圓角值大於寬度一半則進行修正
502
+ if (transformedRx > barHalfWidth) {
503
+ const rScale = barHalfWidth / transformedRx
504
+ transformedRx = transformedRx * rScale
505
+ transformedRy = transformedRy * rScale
506
+ }
507
+
508
+ return [transformedRx, transformedRy]
509
+ })
510
+ })
511
+ )
512
+
513
+
514
+ // const seriesLabels$ = visibleComputedData$.pipe(
515
+ // takeUntil(destroy$),
516
+ // map(data => {
517
+ // const SeriesLabelSet: Set<string> = new Set()
518
+ // data.forEach(d => {
519
+ // d.forEach(_d => {
520
+ // SeriesLabelSet.add(_d.seriesLabel)
521
+ // })
522
+ // })
523
+ // return Array.from(SeriesLabelSet)
524
+ // })
525
+ // )
526
+
527
+ const categoryLabels$ = visibleComputedData$.pipe(
528
+ takeUntil(destroy$),
529
+ map(data => {
530
+ const GroupLabelSet: Set<string> = new Set()
531
+ data.forEach(d => {
532
+ d.forEach(_d => {
533
+ GroupLabelSet.add(_d.category)
534
+ })
535
+ })
536
+ return Array.from(GroupLabelSet)
537
+ })
538
+ )
539
+
540
+ const barScale$ = combineLatest({
541
+ seriesLabels: seriesLabels$,
542
+ barWidth: barWidth$,
543
+ params: baseBarsParams$,
544
+ }).pipe(
545
+ takeUntil(destroy$),
546
+ debounceTime(0),
547
+ map(data => {
548
+ return makeBarScale(data.barWidth, data.seriesLabels, data.params)
549
+ })
550
+ )
551
+
552
+ const transitionDuration$ = styles$.pipe(
553
+ takeUntil(destroy$),
554
+ map(d => d.transitionDuration),
555
+ distinctUntilChanged()
556
+ )
557
+
558
+ const delayGroup$ = new Observable<number>(subscriber => {
559
+ combineLatest({
560
+ categoryLabels: categoryLabels$,
561
+ transitionDuration: transitionDuration$,
562
+ }).pipe(
563
+ debounceTime(0)
564
+ ).subscribe(data => {
565
+ const delay = calcDelayGroup(data.categoryLabels.length, data.transitionDuration)
566
+ subscriber.next(delay)
567
+ })
568
+ }).pipe(
569
+ takeUntil(destroy$),
570
+ distinctUntilChanged()
571
+ )
572
+
573
+ const transitionItem$ = new Observable<number>(subscriber => {
574
+ combineLatest({
575
+ categoryLabels: categoryLabels$,
576
+ transitionDuration: transitionDuration$
577
+ }).pipe(
578
+ debounceTime(0)
579
+ ).subscribe(data => {
580
+ const transition = calctransitionItem(data.categoryLabels.length, data.transitionDuration)
581
+ subscriber.next(transition)
582
+ })
583
+ }).pipe(
584
+ takeUntil(destroy$),
585
+ distinctUntilChanged()
586
+ )
587
+
588
+ combineLatest({
589
+ defsSelection: defsSelection$,
590
+ gridAxesSize: gridAxesSize$,
591
+ }).pipe(
592
+ takeUntil(destroy$),
593
+ debounceTime(0)
594
+ ).subscribe(data => {
595
+ const clipPathData = [{
596
+ id: clipPathID,
597
+ width: data.gridAxesSize.width,
598
+ height: data.gridAxesSize.height
599
+ }]
600
+ renderClipPath({
601
+ defsSelection: data.defsSelection,
602
+ clipPathData
603
+ })
604
+ })
605
+
606
+
607
+ const highlightTarget$ = styles$.pipe(
608
+ takeUntil(destroy$),
609
+ map(d => d.highlightTarget),
610
+ distinctUntilChanged()
611
+ )
612
+
613
+ const barSelection$ = combineLatest({
614
+ graphicGSelection: graphicGSelection$,
615
+ visibleComputedAxesData: visibleComputedAxesData$,
616
+ // barData$: barData$,
617
+ zeroYArr: zeroYArr$,
618
+ categoryLabels: categoryLabels$,
619
+ barScale: barScale$,
620
+ params: baseBarsParams$,
621
+ styles: styles$,
622
+ highlightTarget: highlightTarget$,
623
+ barWidth: barWidth$,
624
+ transformedBarRadius: transformedBarRadius$,
625
+ delayGroup: delayGroup$,
626
+ transitionItem: transitionItem$,
627
+ isSeriesSeprate: isSeriesSeprate$
628
+ }).pipe(
629
+ takeUntil(destroy$),
630
+ switchMap(async (d) => d),
631
+ map(data => {
632
+ return renderRectBars({
633
+ graphicGSelection: data.graphicGSelection,
634
+ rectClassName,
635
+ visibleComputedAxesData: data.visibleComputedAxesData,
636
+ zeroYArr: data.zeroYArr,
637
+ barScale: data.barScale,
638
+ styles: data.styles,
639
+ barWidth: data.barWidth,
640
+ transformedBarRadius: data.transformedBarRadius,
641
+ delayGroup: data.delayGroup,
642
+ transitionItem: data.transitionItem,
643
+ isSeriesSeprate: data.isSeriesSeprate
644
+ })
645
+ })
646
+ )
647
+
648
+ combineLatest({
649
+ barSelection: barSelection$,
650
+ computedData: computedData$,
651
+ highlightTarget: highlightTarget$,
652
+ SeriesDataMap: SeriesDataMap$,
653
+ CategoryDataMap: CategoryDataMap$,
654
+ }).pipe(
655
+ takeUntil(destroy$),
656
+ switchMap(async (d) => d),
657
+ ).subscribe(data => {
658
+ data.barSelection
659
+ .on('mouseover', (event, datum) => {
660
+ event.stopPropagation()
661
+
662
+ eventTrigger$.next({
663
+ // type: 'grid',
664
+ // eventName: 'mouseover',
665
+ // pluginName,
666
+ // highlightTarget: data.highlightTarget,
667
+ // datum,
668
+ // gridIndex: datum.gridIndex,
669
+ // series: data.SeriesDataMap.get(datum.seriesLabel)!,
670
+ // seriesIndex: datum.seriesIndex,
671
+ // seriesLabel: datum.seriesLabel,
672
+ // group: data.CategoryDataMap.get(datum.groupLabel)!,
673
+ // groupIndex: datum.groupIndex,
674
+ // groupLabel: datum.groupLabel,
675
+ // event,
676
+ // data: data.computedData
677
+ eventName: 'mouseover',
678
+ pluginName,
679
+ layerName,
680
+ target: datum,
681
+ event,
682
+ })
683
+ })
684
+ .on('mousemove', (event, datum) => {
685
+ event.stopPropagation()
686
+
687
+ eventTrigger$.next({
688
+ // type: 'grid',
689
+ // eventName: 'mousemove',
690
+ // pluginName,
691
+ // highlightTarget: data.highlightTarget,
692
+ // datum,
693
+ // gridIndex: datum.gridIndex,
694
+ // series: data.SeriesDataMap.get(datum.seriesLabel)!,
695
+ // seriesIndex: datum.seriesIndex,
696
+ // seriesLabel: datum.seriesLabel,
697
+ // group: data.CategoryDataMap.get(datum.groupLabel)!,
698
+ // groupIndex: datum.groupIndex,
699
+ // groupLabel: datum.groupLabel,
700
+ // event,
701
+ // data: data.computedData
702
+ eventName: 'mousemove',
703
+ pluginName,
704
+ layerName,
705
+ target: datum,
706
+ event,
707
+ })
708
+ })
709
+ .on('mouseout', (event, datum) => {
710
+ event.stopPropagation()
711
+
712
+ eventTrigger$.next({
713
+ // type: 'grid',
714
+ // eventName: 'mouseout',
715
+ // pluginName,
716
+ // highlightTarget: data.highlightTarget,
717
+ // datum,
718
+ // gridIndex: datum.gridIndex,
719
+ // series: data.SeriesDataMap.get(datum.seriesLabel)!,
720
+ // seriesIndex: datum.seriesIndex,
721
+ // seriesLabel: datum.seriesLabel,
722
+ // group: data.CategoryDataMap.get(datum.groupLabel)!,
723
+ // groupIndex: datum.groupIndex,
724
+ // groupLabel: datum.groupLabel,
725
+ // event,
726
+ // data: data.computedData
727
+ eventName: 'mouseout',
728
+ pluginName,
729
+ layerName,
730
+ target: datum,
731
+ event,
732
+ })
733
+ })
734
+ .on('click', (event, datum) => {
735
+ event.stopPropagation()
736
+
737
+ eventTrigger$.next({
738
+ // type: 'grid',
739
+ // eventName: 'click',
740
+ // pluginName,
741
+ // highlightTarget: data.highlightTarget,
742
+ // datum,
743
+ // gridIndex: datum.gridIndex,
744
+ // series: data.SeriesDataMap.get(datum.seriesLabel)!,
745
+ // seriesIndex: datum.seriesIndex,
746
+ // seriesLabel: datum.seriesLabel,
747
+ // group: data.CategoryDataMap.get(datum.groupLabel)!,
748
+ // groupIndex: datum.groupIndex,
749
+ // groupLabel: datum.groupLabel,
750
+ // event,
751
+ // data: data.computedData
752
+ eventName: 'click',
753
+ pluginName,
754
+ layerName,
755
+ target: datum,
756
+ event,
757
+ })
758
+ })
759
+ })
760
+
761
+
762
+ combineLatest({
763
+ barSelection: barSelection$,
764
+ highlight: gridHighlight$.pipe(
765
+ map(data => data.map(d => d.id))
766
+ ),
767
+ styles: styles$
768
+ }).pipe(
769
+ takeUntil(destroy$),
770
+ debounceTime(0)
771
+ ).subscribe(data => {
772
+ highlight({
773
+ selection: data.barSelection,
774
+ ids: data.highlight,
775
+ styles: data.styles
776
+ })
777
+ })
778
+
779
+
780
+ return () => {
781
+ destroy$.next(undefined)
782
+ }
783
+ }