@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,637 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ Observable,
4
+ Subject,
5
+ of,
6
+ takeUntil,
7
+ filter,
8
+ map,
9
+ switchMap,
10
+ combineLatest,
11
+ merge,
12
+ shareReplay,
13
+ distinctUntilChanged
14
+ } from 'rxjs'
15
+ import type {
16
+ ComputedData,
17
+ ComputedDatumGrid,
18
+ ContainerSize,
19
+ TransformData,
20
+ ContainerPositionScaled,
21
+ Layout } from '../types'
22
+ import { createAxisToLabelIndexScale } from './d3Scale'
23
+ import { createClassName } from './orbchartsUtils'
24
+ import { d3EventObservable } from './observables'
25
+ import { SeriesPlotPluginParams } from '../plugins/SeriesPlot/types'
26
+
27
+ // 建立 grid 主要的 selection
28
+ export const gridSelectionsObservable = ({ selection, pluginName, layerName, clipPathID, seriesLabels$, gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
29
+ selection: d3.Selection<any, unknown, any, unknown>
30
+ pluginName: string
31
+ layerName: string
32
+ clipPathID: string
33
+ // computedData$: Observable<ComputedDataGrid>
34
+ seriesLabels$: Observable<string[]>
35
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
36
+ gridAxesTransform$: Observable<TransformData>
37
+ gridGraphicTransform$: Observable<TransformData>
38
+ }) => {
39
+ const seriesClassName = createClassName(pluginName, layerName, 'series')
40
+ const axesClassName = createClassName(pluginName, layerName, 'axes')
41
+ const graphicClassName = createClassName(pluginName, layerName, 'graphic')
42
+
43
+ // <g> series selection(container排放位置)
44
+ // <g> axes selection(旋轉圖軸方向)
45
+ // <defs> clipPath selection
46
+ // <g> graphic selection(圖形 scale 範圍的變形)
47
+ const seriesSelection$ = seriesLabels$.pipe(
48
+ map((seriesLabels, i) => {
49
+ return selection
50
+ .selectAll<SVGGElement, string>(`g.${seriesClassName}`)
51
+ .data(seriesLabels, d => d)
52
+ .join(
53
+ enter => {
54
+ return enter
55
+ .append('g')
56
+ .classed(seriesClassName, true)
57
+ .each((d, i, g) => {
58
+ const axesSelection = d3.select(g[i])
59
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${axesClassName}`)
60
+ .data([i])
61
+ .join(
62
+ enter => {
63
+ return enter
64
+ .append('g')
65
+ .classed(axesClassName, true)
66
+ .attr('clip-path', `url(#${clipPathID})`)
67
+ .each((d, i, g) => {
68
+ const defsSelection = d3.select(g[i])
69
+ .selectAll<SVGDefsElement, any>('defs')
70
+ .data([i])
71
+ .join('defs')
72
+
73
+ const graphicGSelection = d3.select(g[i])
74
+ .selectAll<SVGGElement, any>('g')
75
+ .data([i])
76
+ .join('g')
77
+ .classed(graphicClassName, true)
78
+ })
79
+ },
80
+ update => update,
81
+ exit => exit.remove()
82
+ )
83
+ })
84
+ },
85
+ update => update,
86
+ exit => exit.remove()
87
+ )
88
+ }),
89
+ shareReplay(1)
90
+ )
91
+
92
+ // <g> series selection
93
+ combineLatest({
94
+ seriesSelection: seriesSelection$,
95
+ gridContainerPosition: gridContainerPosition$
96
+ }).pipe(
97
+ switchMap(async d => d)
98
+ ).subscribe(data => {
99
+ data.seriesSelection
100
+ .transition()
101
+ .attr('transform', (d, i) => {
102
+ const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
103
+ const translate = gridContainerPosition.translate
104
+ const scale = gridContainerPosition.scale
105
+ return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
106
+ })
107
+ })
108
+
109
+ // <g> axes selection
110
+ const axesSelection$ = combineLatest({
111
+ seriesSelection: seriesSelection$,
112
+ gridAxesTransform: gridAxesTransform$
113
+ }).pipe(
114
+ switchMap(async d => d),
115
+ map(data => {
116
+ return data.seriesSelection
117
+ .select<SVGGElement>(`g.${axesClassName}`)
118
+ .style('transform', data.gridAxesTransform.value)
119
+ }),
120
+ shareReplay(1)
121
+ )
122
+
123
+ // <defs> clipPath selection
124
+ const defsSelection$ = axesSelection$.pipe(
125
+ map(axesSelection => {
126
+ return axesSelection.select<SVGDefsElement>('defs')
127
+ }),
128
+ shareReplay(1)
129
+ )
130
+
131
+ // <g> graphic selection
132
+ const graphicGSelection$ = combineLatest({
133
+ axesSelection: axesSelection$,
134
+ gridGraphicTransform: gridGraphicTransform$
135
+ }).pipe(
136
+ switchMap(async d => d),
137
+ map(data => {
138
+ const graphicGSelection = data.axesSelection
139
+ .select<SVGGElement>(`g.${graphicClassName}`)
140
+ graphicGSelection
141
+ .transition()
142
+ .duration(50)
143
+ .style('transform', data.gridGraphicTransform.value)
144
+ return graphicGSelection
145
+ }),
146
+ shareReplay(1)
147
+ )
148
+
149
+ return {
150
+ seriesSelection$,
151
+ axesSelection$,
152
+ defsSelection$,
153
+ graphicGSelection$
154
+ }
155
+ }
156
+
157
+ // 建立 grid 主要的 selection - 只取的container
158
+ export const gridContainerSelectionsObservable = ({ selection, pluginName, layerName, computedData$, gridContainerPosition$, isSeriesSeprate$ }: {
159
+ selection: d3.Selection<any, unknown, any, unknown>
160
+ pluginName: string
161
+ layerName: string
162
+ computedData$: Observable<ComputedData<'grid'>>
163
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
164
+ isSeriesSeprate$: Observable<boolean>
165
+ }) => {
166
+ const containerClassName = createClassName(pluginName, layerName, 'container')
167
+
168
+ const containerSelection$ = combineLatest({
169
+ computedData: computedData$.pipe(
170
+ distinctUntilChanged((a, b) => {
171
+ // 只有當series的數量改變時,才重新計算
172
+ return a.length === b.length
173
+ }),
174
+ ),
175
+ isSeriesSeprate: isSeriesSeprate$
176
+ }).pipe(
177
+ switchMap(async (d) => d),
178
+ map(data => {
179
+ return data.isSeriesSeprate
180
+ // series分開的時候顯示各別axis
181
+ ? data.computedData
182
+ // series合併的時候只顯示第一個axis
183
+ : [data.computedData[0]]
184
+ }),
185
+ map((computedData, i) => {
186
+ return selection
187
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${containerClassName}`)
188
+ .data(computedData, d => (d && d[0]) ? d[0].seriesIndex : i)
189
+ .join('g')
190
+ .classed(containerClassName, true)
191
+ }),
192
+ shareReplay(1)
193
+ )
194
+
195
+ combineLatest({
196
+ containerSelection: containerSelection$,
197
+ gridContainerPosition: gridContainerPosition$
198
+ }).pipe(
199
+ switchMap(async d => d)
200
+ ).subscribe(data => {
201
+ data.containerSelection
202
+ .attr('transform', (d, i) => {
203
+ const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
204
+ const translate = gridContainerPosition.translate
205
+ const scale = gridContainerPosition.scale
206
+ return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
207
+ })
208
+ // .attr('opacity', 0)
209
+ // .transition()
210
+ // .attr('opacity', 1)
211
+ })
212
+
213
+ return containerSelection$
214
+ }
215
+
216
+ // 由事件取得category data的function
217
+ export const gridCategoryPositionFnObservable = ({ pluginParams$, gridAxesSize$, computedData$, gridContainerPosition$, layout$ }: {
218
+ pluginParams$: Observable<SeriesPlotPluginParams>
219
+ gridAxesSize$: Observable<{
220
+ width: number;
221
+ height: number;
222
+ }>
223
+ computedData$: Observable<ComputedData<'grid'>>
224
+ // CategoryDataMap$: Observable<Map<string, ComputedDatumGrid[]>>
225
+ // fullChartParams$: Observable<ChartParams>
226
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
227
+ layout$: Observable<Layout>
228
+ }): Observable<(event: any) => { categoryIndex: number; categoryLabel: string }> => {
229
+ const destroy$ = new Subject()
230
+
231
+ // 顯示範圍內的category labels
232
+ // const scaleRangeCategoryLabels$: Observable<string[]> = new Observable(subscriber => {
233
+ // combineLatest({
234
+ // pluginParams: pluginParams$,
235
+ // computedData: computedData$
236
+ // }).pipe(
237
+ // takeUntil(destroy$),
238
+ // switchMap(async (d) => d),
239
+ // ).subscribe(data => {
240
+ // const categoryMin = 0
241
+ // const categoryMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
242
+ // const categoryScaleDomainMin = data.dataFormatter.categoryAxis.scaleDomain[0] === 'auto'
243
+ // ? categoryMin - data.dataFormatter.categoryAxis.scalePadding
244
+ // : data.dataFormatter.categoryAxis.scaleDomain[0] as number - data.dataFormatter.categoryAxis.scalePadding
245
+ // const categoryScaleDomainMax = data.dataFormatter.categoryAxis.scaleDomain[1] === 'auto'
246
+ // ? categoryMax + data.dataFormatter.categoryAxis.scalePadding
247
+ // : data.dataFormatter.categoryAxis.scaleDomain[1] as number + data.dataFormatter.categoryAxis.scalePadding
248
+
249
+ // // const categoryAmount = data.computedData[0]
250
+ // // ? data.computedData[0].length
251
+ // // : 0
252
+
253
+ // let _labels = data.dataFormatter.seriesDirection === 'row'
254
+ // ? (data.computedData[0] ?? []).map(d => d.categoryLabel)
255
+ // : data.computedData.map(d => d[0].categoryLabel)
256
+
257
+ // const _axisLabels =
258
+ // // new Array(categoryAmount).fill(0)
259
+ // // .map((d, i) => {
260
+ // // return _labels[i] != null
261
+ // // ? _labels[i]
262
+ // // : String(i) // 沒有label則用序列號填充
263
+ // // })
264
+ // _labels
265
+ // .filter((d, i) => {
266
+ // return i >= categoryScaleDomainMin && i <= categoryScaleDomainMax
267
+ // })
268
+ // subscriber.next(_axisLabels)
269
+ // })
270
+ // })
271
+ const categoryScaleDomain$ = combineLatest({
272
+ pluginParams: pluginParams$,
273
+ gridAxesSize: gridAxesSize$,
274
+ computedData: computedData$
275
+ }).pipe(
276
+ switchMap(async (d) => d),
277
+ map(data => {
278
+ const categoryMin = 0
279
+ const categoryMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
280
+ // const categoryScaleDomainMin = data.pluginParams.categoryAxis.scaleDomain[0] === 'auto'
281
+ // ? categoryMin - data.pluginParams.categoryAxis.scalePadding
282
+ // : data.pluginParams.categoryAxis.scaleDomain[0] as number - data.pluginParams.categoryAxis.scalePadding
283
+ const categoryScaleDomainMin = data.pluginParams.categoryAxis.scaleDomain[0] - data.pluginParams.categoryAxis.scalePadding
284
+ const categoryScaleDomainMax = data.pluginParams.categoryAxis.scaleDomain[1] === 'max'
285
+ ? categoryMax + data.pluginParams.categoryAxis.scalePadding
286
+ : data.pluginParams.categoryAxis.scaleDomain[1] as number + data.pluginParams.categoryAxis.scalePadding
287
+
288
+ return [categoryScaleDomainMin, categoryScaleDomainMax]
289
+ }),
290
+ shareReplay(1)
291
+ )
292
+
293
+ const categoryLabels$ = combineLatest({
294
+ pluginParams: pluginParams$,
295
+ computedData: computedData$
296
+ }).pipe(
297
+ switchMap(async d => d),
298
+ map(data => {
299
+ // return data.pluginParams.seriesDirection === 'row'
300
+ // ? (data.computedData[0] ?? []).map(d => d.category)
301
+ // : data.computedData.map(d => d[0].category)
302
+ return (data.computedData[0] ?? []).map(d => d.category)
303
+ })
304
+ )
305
+
306
+ // 顯示範圍內的category labels
307
+ const scaleRangeCategoryLabels$ = combineLatest({
308
+ categoryScaleDomain: categoryScaleDomain$,
309
+ categoryLabels: categoryLabels$
310
+ }).pipe(
311
+ switchMap(async d => d),
312
+ map(data => {
313
+ return data.categoryLabels
314
+ .filter((d, i) => {
315
+ return i >= data.categoryScaleDomain[0] && i <= data.categoryScaleDomain[1]
316
+ })
317
+ })
318
+ )
319
+
320
+ const columnAmount$ = gridContainerPosition$.pipe(
321
+ map(gridContainerPosition => {
322
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
323
+ return current.columnIndex > acc ? current.columnIndex : acc
324
+ }, 0)
325
+ return maxColumnIndex + 1
326
+ }),
327
+ distinctUntilChanged()
328
+ )
329
+
330
+ const rowAmount$ = gridContainerPosition$.pipe(
331
+ map(gridContainerPosition => {
332
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
333
+ return current.rowIndex > acc ? current.rowIndex : acc
334
+ }, 0)
335
+ return maxRowIndex + 1
336
+ }),
337
+ distinctUntilChanged()
338
+ )
339
+
340
+ return new Observable<(event: any) => { categoryIndex: number; categoryLabel: string }>(subscriber => {
341
+ combineLatest({
342
+ pluginParams: pluginParams$,
343
+ axisSize: gridAxesSize$,
344
+ scaleRangeCategoryLabels: scaleRangeCategoryLabels$,
345
+ categoryLabels: categoryLabels$,
346
+ categoryScaleDomain: categoryScaleDomain$,
347
+ columnAmount: columnAmount$,
348
+ rowAmount: rowAmount$,
349
+ layout: layout$
350
+ }).pipe(
351
+ takeUntil(destroy$),
352
+ switchMap(async (d) => d),
353
+ ).subscribe(data => {
354
+
355
+ const reverse = data.pluginParams.valueAxis.position === 'right'
356
+ || data.pluginParams.valueAxis.position === 'bottom'
357
+ ? true : false
358
+
359
+ // 比例尺座標對應非連續資料索引
360
+ const xIndexScale = createAxisToLabelIndexScale({
361
+ axisLabels: data.scaleRangeCategoryLabels,
362
+ axisWidth: data.axisSize.width,
363
+ padding: data.pluginParams.categoryAxis.scalePadding,
364
+ reverse
365
+ })
366
+
367
+ // 依比例尺位置計算座標
368
+ const axisValuePredicate = (event: any) => {
369
+ return data.pluginParams.categoryAxis.position === 'bottom'
370
+ || data.pluginParams.categoryAxis.position === 'top'
371
+ ? event.offsetX - data.pluginParams.styles.padding.left
372
+ : event.offsetY - data.pluginParams.styles.padding.top
373
+ }
374
+
375
+ // 比例尺座標取得categoryData的function
376
+ const createEventCategoryData: (event: MouseEvent) => { categoryIndex: number; categoryLabel: string } = (event: any) => {
377
+ // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
378
+ const eventData = {
379
+ offsetX: event.offsetX * data.columnAmount % data.layout.rootWidth,
380
+ offsetY: event.offsetY * data.rowAmount % data.layout.rootHeight
381
+ }
382
+ // console.log('data.columnAmount', data.columnAmount, 'data.rowAmount', data.rowAmount, 'data.layout.rootWidth', data.layout.rootWidth, 'data.layout.rootHeight', data.layout.rootHeight)
383
+ const axisValue = axisValuePredicate(eventData)
384
+ const xIndex = xIndexScale(axisValue)
385
+ const currentxIndexStart = Math.ceil(data.categoryScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
386
+ const categoryIndex = xIndex + currentxIndexStart
387
+
388
+ return {
389
+ categoryIndex,
390
+ categoryLabel: data.categoryLabels[categoryIndex] ?? ''
391
+ }
392
+ }
393
+
394
+ subscriber.next(createEventCategoryData)
395
+
396
+ return function unsubscribe () {
397
+ destroy$.next(undefined)
398
+ }
399
+ })
400
+ })
401
+ }
402
+
403
+ export const gridCategoryPositionObservable = ({ rootSelection, pluginParams$, gridAxesContainerSize$, computedData$, gridContainerPosition$, layout$ }: {
404
+ rootSelection: d3.Selection<any, unknown, any, unknown>
405
+ pluginParams$: Observable<SeriesPlotPluginParams>
406
+ // gridAxesSize$: Observable<ContainerSize>
407
+ // containerSize$: Observable<ContainerSize>
408
+ gridAxesContainerSize$: Observable<ContainerSize>
409
+ computedData$: Observable<ComputedData<'grid'>>
410
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
411
+ layout$: Observable<Layout>
412
+ }) => {
413
+ const rootMousemove$ = d3EventObservable(rootSelection, 'mousemove')
414
+
415
+ const categoryScaleDomain$ = combineLatest({
416
+ pluginParams: pluginParams$,
417
+ // gridAxesSize: gridAxesSize$,
418
+ computedData: computedData$
419
+ }).pipe(
420
+ switchMap(async (d) => d),
421
+ map(data => {
422
+ const categoryMin = 0
423
+ const categoryMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
424
+ // const categoryScaleDomainMin = data.fullDataFormatter.categoryAxis.scaleDomain[0] === 'auto'
425
+ // ? categoryMin - data.fullDataFormatter.categoryAxis.scalePadding
426
+ // : data.fullDataFormatter.categoryAxis.scaleDomain[0] as number - data.fullDataFormatter.categoryAxis.scalePadding
427
+ const categoryScaleDomainMin = data.pluginParams.categoryAxis.scaleDomain[0] - data.pluginParams.categoryAxis.scalePadding
428
+ const categoryScaleDomainMax = data.pluginParams.categoryAxis.scaleDomain[1] === 'max'
429
+ ? categoryMax + data.pluginParams.categoryAxis.scalePadding
430
+ : data.pluginParams.categoryAxis.scaleDomain[1] as number + data.pluginParams.categoryAxis.scalePadding
431
+
432
+ return [categoryScaleDomainMin, categoryScaleDomainMax]
433
+ }),
434
+ shareReplay(1)
435
+ )
436
+
437
+ const categoryLabels$ = combineLatest({
438
+ pluginParams: pluginParams$,
439
+ computedData: computedData$
440
+ }).pipe(
441
+ switchMap(async d => d),
442
+ map(data => {
443
+ // return data.pluginParams.seriesDirection === 'row'
444
+ // ? (data.computedData[0] ?? []).map(d => d.category)
445
+ // : data.computedData.map(d => d[0].category)
446
+ return (data.computedData[0] ?? []).map(d => d.category)
447
+ })
448
+ )
449
+
450
+ const scaleRangeCategoryLabels$ = combineLatest({
451
+ categoryScaleDomain: categoryScaleDomain$,
452
+ categoryLabels: categoryLabels$
453
+ }).pipe(
454
+ switchMap(async d => d),
455
+ map(data => {
456
+ return data.categoryLabels
457
+ .filter((d, i) => {
458
+ return i >= data.categoryScaleDomain[0] && i <= data.categoryScaleDomain[1]
459
+ })
460
+ })
461
+ )
462
+
463
+ const reverse$ = pluginParams$.pipe(
464
+ map(d => {
465
+ return d.valueAxis.position === 'right' || d.valueAxis.position === 'bottom'
466
+ ? true
467
+ : false
468
+ })
469
+ )
470
+
471
+ // 比例尺座標對應非連續資料索引
472
+ const xIndexScale$ = combineLatest({
473
+ reverse: reverse$,
474
+ // gridAxesSize: gridAxesSize$,
475
+ gridAxesContainerSize: gridAxesContainerSize$,
476
+ scaleRangeCategoryLabels: scaleRangeCategoryLabels$,
477
+ pluginParams: pluginParams$
478
+ }).pipe(
479
+ switchMap(async d => d),
480
+ map(data => {
481
+ return createAxisToLabelIndexScale({
482
+ axisLabels: data.scaleRangeCategoryLabels,
483
+ axisWidth: data.gridAxesContainerSize.width,
484
+ padding: data.pluginParams.categoryAxis.scalePadding,
485
+ reverse: data.reverse
486
+ })
487
+ })
488
+ )
489
+
490
+ // const columnAmount$ = gridContainerPosition$.pipe(
491
+ // map(gridContainerPosition => {
492
+ // const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
493
+ // return current.columnIndex > acc ? current.columnIndex : acc
494
+ // }, 0)
495
+ // return maxColumnIndex + 1
496
+ // }),
497
+ // distinctUntilChanged()
498
+ // )
499
+
500
+ // const rowAmount$ = gridContainerPosition$.pipe(
501
+ // map(gridContainerPosition => {
502
+ // const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
503
+ // return current.rowIndex > acc ? current.rowIndex : acc
504
+ // }, 0)
505
+ // return maxRowIndex + 1
506
+ // }),
507
+ // distinctUntilChanged()
508
+ // )
509
+
510
+ const axisValue$ = combineLatest({
511
+ pluginParams: pluginParams$,
512
+ rootMousemove: rootMousemove$,
513
+ // containerSize: containerSize$,
514
+ gridContainerPosition: gridContainerPosition$,
515
+ // columnAmount: columnAmount$,
516
+ // rowAmount: rowAmount$,
517
+ layout: layout$
518
+ }).pipe(
519
+ switchMap(async d => d),
520
+ map(data => {
521
+ // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
522
+ // const eventData = {
523
+ // offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
524
+ // offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
525
+ // }
526
+ // return data.pluginParams.categoryAxis.position === 'bottom'
527
+ // || data.pluginParams.categoryAxis.position === 'top'
528
+ // ? eventData.offsetX - data.layout.left
529
+ // : eventData.offsetY - data.layout.top
530
+
531
+ if (data.pluginParams.categoryAxis.position === 'bottom' || data.pluginParams.categoryAxis.position === 'top') {
532
+ let x = data.rootMousemove.offsetX
533
+ const rangeArr = data.gridContainerPosition
534
+ .map((d, i) => [d.translate[0], data.gridContainerPosition[i + 1]?.translate[0] ?? data.layout.rootWidth])
535
+ .filter(d => d[0] < d[1])
536
+ const range = rangeArr.find(d => x >= d[0] && x <= d[1])
537
+ if (range) {
538
+ x = x - range[0]
539
+ }
540
+ return x - data.layout.left
541
+ } else {
542
+ let y = data.rootMousemove.offsetY
543
+ const rangeArr = data.gridContainerPosition
544
+ .map((d, i) => [d.translate[1], data.gridContainerPosition[i + 1]?.translate[1] ?? data.layout.rootHeight])
545
+ .filter(d => d[0] < d[1])
546
+ const range = rangeArr.find(d => y >= d[0] && y <= d[1])
547
+ if (range) {
548
+ y = y - range[0]
549
+ }
550
+ return y - data.layout.top
551
+ }
552
+ })
553
+ )
554
+
555
+ const categoryIndex$ = combineLatest({
556
+ xIndexScale: xIndexScale$,
557
+ axisValue: axisValue$,
558
+ categoryScaleDomain: categoryScaleDomain$
559
+ }).pipe(
560
+ switchMap(async d => d),
561
+ map(data => {
562
+ const xIndex = data.xIndexScale(data.axisValue)
563
+ const currentxIndexStart = Math.ceil(data.categoryScaleDomain[0]) // 因為有padding所以會有小數點,所以要無條件進位
564
+ return xIndex + currentxIndexStart
565
+ })
566
+ )
567
+
568
+ const categoryLabel$ = combineLatest({
569
+ categoryIndex: categoryIndex$,
570
+ categoryLabels: categoryLabels$
571
+ }).pipe(
572
+ switchMap(async d => d),
573
+ map(data => {
574
+ return data.categoryLabels[data.categoryIndex] ?? ''
575
+ })
576
+ )
577
+
578
+ return combineLatest({
579
+ categoryIndex: categoryIndex$,
580
+ categoryLabel: categoryLabel$
581
+ }).pipe(
582
+ switchMap(async d => d),
583
+ map(data => {
584
+ return {
585
+ categoryIndex: data.categoryIndex,
586
+ categoryLabel: data.categoryLabel
587
+ }
588
+ })
589
+ )
590
+ }
591
+
592
+ // const gridContainerEventData$ = ({ eventData$, gridContainerPosition$, layout$ }: {
593
+ // eventData$: Observable<any>
594
+ // gridContainerPosition$: Observable<ContainerPositionScaled[]>
595
+ // layout$: Observable<Layout>
596
+ // }): Observable<{
597
+ // offsetX: number;
598
+ // offsetY: number;
599
+ // }> => {
600
+ // const columnAmount$ = gridContainerPosition$.pipe(
601
+ // map(gridContainerPosition => {
602
+ // const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
603
+ // return current.columnIndex > acc ? current.columnIndex : acc
604
+ // }, 0)
605
+ // return maxColumnIndex + 1
606
+ // }),
607
+ // distinctUntilChanged()
608
+ // )
609
+
610
+ // const rowAmount$ = gridContainerPosition$.pipe(
611
+ // map(gridContainerPosition => {
612
+ // const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
613
+ // return current.rowIndex > acc ? current.rowIndex : acc
614
+ // }, 0)
615
+ // return maxRowIndex + 1
616
+ // }),
617
+ // distinctUntilChanged()
618
+ // )
619
+
620
+ // return combineLatest({
621
+ // eventData: eventData$,
622
+ // gridContainerPosition: gridContainerPosition$,
623
+ // layout: layout$,
624
+ // columnAmount: columnAmount$,
625
+ // rowAmount: rowAmount$
626
+ // }).pipe(
627
+ // switchMap(async d => d),
628
+ // map(data => {
629
+ // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
630
+ // const eventData = {
631
+ // offsetX: data.eventData.offsetX * data.columnAmount % data.layout.rootWidth,
632
+ // offsetY: data.eventData.offsetY * data.rowAmount % data.layout.rootHeight
633
+ // }
634
+ // return eventData
635
+ // })
636
+ // )
637
+ // }