@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,726 @@
1
+ import {
2
+ combineLatest,
3
+ distinctUntilChanged,
4
+ debounceTime,
5
+ filter,
6
+ map,
7
+ merge,
8
+ takeUntil,
9
+ shareReplay,
10
+ switchMap,
11
+ Subject,
12
+ Observable,
13
+ iif
14
+ } from 'rxjs'
15
+ import type {
16
+ ModelDatumGrid,
17
+ ModelDataGrid,
18
+ // DataFormatterTypeMap,
19
+ // ContainerPosition,
20
+ // Layout
21
+ } from '@orbcharts/core'
22
+ import type { ComputedData, ComputedDatumGrid } from '../../types/ComputedData'
23
+ import type { ComputedLayoutDatumGrid, ComputedAxesDataGrid, SeriesPlotPluginParams } from './types'
24
+ import type { ValueAxis, CategoryAxis } from '../../types/PluginParams'
25
+ import type { Layout, ContainerPosition, AxisPosition, ContainerPositionScaled } from '../../types/PluginParams'
26
+ // import { getMinMaxGrid } from '../../utils/orbchartsUtils'
27
+ import { createValueToAxisScale, createLabelToAxisScale, createAxisToLabelIndexScale } from '../../utils/d3Scale'
28
+ import { calcContainerPositionScaled } from '../../utils/orbchartsUtils'
29
+ import { getMinMaxValue } from '../../utils/orbchartsUtils'
30
+ import { calcContainerPosition } from '../../utils/orbchartsUtils'
31
+ import { ContainerSize, TransformData } from '../..'
32
+
33
+ export const gridComputedDataObservable = ({ selectedGridData$, pluginParams$ }: {
34
+ selectedGridData$: Observable<ModelDataGrid>
35
+ pluginParams$: Observable<SeriesPlotPluginParams>
36
+ }): Observable<ComputedDatumGrid[][]> => {
37
+ return combineLatest({
38
+ selectedGridData: selectedGridData$,
39
+ pluginParams: pluginParams$
40
+ }).pipe(
41
+ debounceTime(0),
42
+ map(({ selectedGridData, pluginParams }) => {
43
+ return selectedGridData
44
+ .map((data) => {
45
+ return data.map((datum, index) => {
46
+ const visibleFilter = pluginParams.visibleFilter
47
+ return {
48
+ ...datum,
49
+ visible: visibleFilter ? visibleFilter(datum) : true,
50
+ }
51
+ })
52
+ })
53
+ })
54
+ )
55
+ }
56
+
57
+ export const gridComputedAxesDataObservable = ({ computedData$, categoryAxis$, valueAxis$, layout$ }: {
58
+ computedData$: Observable<ComputedDatumGrid[][]>
59
+ // pluginParams$: Observable<SeriesPlotPluginParams>
60
+ categoryAxis$: Observable<CategoryAxis>
61
+ valueAxis$: Observable<ValueAxis>
62
+ layout$: Observable<Layout>
63
+ }): Observable<ComputedLayoutDatumGrid[][]> => {
64
+
65
+ // 未篩選category範圍前的category scale( * 不受到dataFormatter設定影響)
66
+ function createOriginGroupScale (computedData: ComputedDatumGrid[][], categoryAxis: CategoryAxis, layout: Layout) {
67
+ const categoryAxisWidth = (categoryAxis.position === 'top' || categoryAxis.position === 'bottom')
68
+ ? layout.width
69
+ : layout.height
70
+ const categoryEndIndex = computedData[0] ? computedData[0].length - 1 : 0
71
+ const categoryScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
72
+ maxValue: categoryEndIndex,
73
+ minValue: 0,
74
+ axisWidth: categoryAxisWidth,
75
+ scaleDomain: [0, categoryEndIndex], // 不使用dataFormatter設定
76
+ scaleRange: [0, 1] // 不使用dataFormatter設定
77
+ })
78
+
79
+ return categoryScale
80
+ }
81
+
82
+ // 未篩選category範圍及visible前的value scale( * 不受到dataFormatter設定影響)
83
+ function createOriginValueScale (computedData: ComputedDatumGrid[][], valueAxis: ValueAxis, layout: Layout) {
84
+ const valueAxisWidth = (valueAxis.position === 'left' || valueAxis.position === 'right')
85
+ ? layout.height
86
+ : layout.width
87
+
88
+ const listData = computedData.flat()
89
+ let [minValue, maxValue] = getMinMaxValue(listData)
90
+ if (minValue === maxValue && maxValue === 0) {
91
+ // 避免最大及最小值相同造成無法計算scale
92
+ maxValue = 1
93
+ }
94
+
95
+ const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
96
+ maxValue,
97
+ minValue,
98
+ axisWidth: valueAxisWidth,
99
+ // scaleDomain: [minValue, maxValue], // 不使用dataFormatter設定
100
+ scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
101
+ scaleRange: [0, 1] // 不使用dataFormatter設定
102
+ })
103
+
104
+ return valueScale
105
+ }
106
+
107
+ return combineLatest({
108
+ computedData: computedData$,
109
+ categoryAxis: categoryAxis$,
110
+ valueAxis: valueAxis$,
111
+ layout: layout$
112
+ }).pipe(
113
+ debounceTime(0),
114
+ map(data => {
115
+ const categoryScale = createOriginGroupScale(data.computedData, data.categoryAxis, data.layout)
116
+ const valueScale = createOriginValueScale(data.computedData, data.valueAxis, data.layout)
117
+ const zeroY = valueScale(0)
118
+
119
+ return data.computedData.map((seriesData, seriesIndex) => {
120
+ return seriesData.map((categoryDatum, categoryIndex) => {
121
+ const axisX = categoryScale(categoryIndex)
122
+ const axisY = valueScale(categoryDatum.value ?? 0)
123
+ return {
124
+ ...categoryDatum,
125
+ axisX,
126
+ axisY,
127
+ axisYFromZero: axisY - zeroY
128
+ }
129
+ })
130
+ })
131
+ })
132
+ )
133
+ }
134
+
135
+ export const gridAxesSizeObservable = ({ categoryAxis$, valueAxis$, layout$ }: {
136
+ categoryAxis$: Observable<CategoryAxis>
137
+ valueAxis$: Observable<ValueAxis>
138
+ layout$: Observable<Layout>
139
+ }): Observable<{
140
+ width: number;
141
+ height: number;
142
+ }> => {
143
+ const destroy$ = new Subject()
144
+
145
+ function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
146
+ xAxisPosition: AxisPosition
147
+ yAxisPosition: AxisPosition
148
+ width: number
149
+ height: number
150
+ }) {
151
+ if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
152
+ return { width, height }
153
+ } else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
154
+ return {
155
+ width: height,
156
+ height: width
157
+ }
158
+ } else {
159
+ // default
160
+ return { width, height }
161
+ }
162
+ }
163
+
164
+ const categoryAxisPosition$ = categoryAxis$.pipe(
165
+ map(d => d.position),
166
+ distinctUntilChanged()
167
+ )
168
+
169
+ const valueAxisPosition$ = valueAxis$.pipe(
170
+ map(d => d.position),
171
+ distinctUntilChanged()
172
+ )
173
+
174
+ return new Observable(subscriber => {
175
+ combineLatest({
176
+ categoryAxisPosition: categoryAxisPosition$,
177
+ valueAxisPosition: valueAxisPosition$,
178
+ layout: layout$
179
+ }).pipe(
180
+ takeUntil(destroy$),
181
+ debounceTime(0),
182
+ ).subscribe(data => {
183
+
184
+ const axisSize = calcAxesSize({
185
+ xAxisPosition: data.categoryAxisPosition,
186
+ yAxisPosition: data.valueAxisPosition,
187
+ width: data.layout.width,
188
+ height: data.layout.height,
189
+ })
190
+
191
+ subscriber.next(axisSize)
192
+
193
+ return function unsubscribe () {
194
+ destroy$.next(undefined)
195
+ }
196
+ })
197
+ })
198
+ }
199
+
200
+ export const gridAxesContainerSizeObservable = ({ categoryAxis$, valueAxis$, containerSize$ }: {
201
+ containerSize$: Observable<ContainerSize>
202
+ categoryAxis$: Observable<CategoryAxis>
203
+ valueAxis$: Observable<ValueAxis>
204
+ }): Observable<ContainerSize> => {
205
+ return gridAxesSizeObservable({
206
+ categoryAxis$,
207
+ valueAxis$,
208
+ layout$: containerSize$ as Observable<Layout>
209
+ })
210
+ }
211
+
212
+ // export const gridHighlightObservable = ({ computedData$, fullChartParams$, event$ }: {
213
+ // computedData$: Observable<ComputedData<'grid'>>
214
+ // fullChartParams$: Observable<ChartParams>
215
+ // event$: Subject<any>
216
+ // }): Observable<string[]> => {
217
+ // const datumList$ = computedData$.pipe(
218
+ // map(d => d.flat())
219
+ // )
220
+ // return highlightObservable ({ datumList$, fullChartParams$, event$ })
221
+ // }
222
+
223
+ export const gridSeriesLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedData<'grid'>> }) => {
224
+ return computedData$.pipe(
225
+ map(data => {
226
+ return data
227
+ .filter(series => series.length)
228
+ .map(series => {
229
+ return series[0].series
230
+ })
231
+ }),
232
+ distinctUntilChanged((a, b) => {
233
+ return JSON.stringify(a) === JSON.stringify(b)
234
+ }),
235
+ )
236
+ }
237
+
238
+ export const gridVisibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedData<'grid'>> }) => {
239
+ return computedData$.pipe(
240
+ map(data => {
241
+ const visibleComputedData = data
242
+ .map(d => {
243
+ return d.filter(_d => {
244
+ return _d.visible == true
245
+ })
246
+ })
247
+ .filter(d => d.length)
248
+ return visibleComputedData
249
+ })
250
+ )
251
+ }
252
+
253
+ export const gridVisibleComputedAxesDataObservable = ({ computedAxesData$ }: { computedAxesData$: Observable<ComputedAxesDataGrid> }) => {
254
+ return computedAxesData$.pipe(
255
+ map(data => {
256
+ const visibleComputedData = data
257
+ .map(d => {
258
+ return d.filter(_d => {
259
+ return _d.visible == true
260
+ })
261
+ })
262
+ .filter(d => d.length)
263
+ return visibleComputedData
264
+ })
265
+ )
266
+ }
267
+
268
+ // 所有container位置(對應series)
269
+ export const gridContainerPositionObservable = ({ selectedGridData$, pluginParams$, layout$ }: {
270
+ selectedGridData$: Observable<ModelDataGrid>
271
+ pluginParams$: Observable<SeriesPlotPluginParams>
272
+ layout$: Observable<Layout>
273
+ }): Observable<ContainerPositionScaled[]> => {
274
+
275
+ const gridContainerPosition$ = combineLatest({
276
+ selectedGridData: selectedGridData$,
277
+ pluginParams: pluginParams$,
278
+ layout: layout$,
279
+ }).pipe(
280
+ debounceTime(0),
281
+ map(data => {
282
+
283
+ // 無資料時回傳預設container位置
284
+ if (data.selectedGridData.length === 0) {
285
+ const defaultPositionArr: ContainerPositionScaled[] = [
286
+ {
287
+ "slotIndex": 0,
288
+ "rowIndex": 0,
289
+ "columnIndex": 0,
290
+ "translate": [0, 0],
291
+ "scale": [1, 1]
292
+ }
293
+ ]
294
+ return defaultPositionArr
295
+ }
296
+ if (data.pluginParams.separateSeries) {
297
+ // -- 依slotIndexes計算 --
298
+ return calcContainerPositionScaled(data.layout, data.pluginParams.container, data.selectedGridData.length)
299
+ } else {
300
+ // -- 無拆分 --
301
+ const gridContainerPositionArr = calcContainerPositionScaled(data.layout, data.pluginParams.container, 1)
302
+ return data.selectedGridData.map((d, i) => gridContainerPositionArr[0]) // 每個series相同位置
303
+ }
304
+ })
305
+ )
306
+
307
+ return gridContainerPosition$
308
+ }
309
+
310
+ // 將原本的value全部替換成加總後的value
311
+ export const computedStackedDataObservables = ({ isSeriesSeprate$, computedData$ }: {
312
+ isSeriesSeprate$: Observable<boolean>
313
+ computedData$: Observable<ComputedData<'grid'>>
314
+ }): Observable<ComputedData<'grid'>> => {
315
+ const stackedData$: Observable<ComputedData<'grid'>> = computedData$.pipe(
316
+ map(data => {
317
+ // 將同一category的value加總起來
318
+ const stackedValue = new Array(data[0] ? data[0].length : 0)
319
+ .fill(null)
320
+ .map((_, i) => {
321
+ return data.reduce((prev, current) => {
322
+ if (current && current[i]) {
323
+ const currentValue = current[i].value == null || current[i].visible == false
324
+ ? 0
325
+ : current[i].value!
326
+ return prev + currentValue
327
+ }
328
+ return prev
329
+ }, 0)
330
+ })
331
+ // 將原本的value全部替換成加總後的value
332
+ const computedData = data.map((series, seriesIndex) => {
333
+ return series.map((d, i) => {
334
+ return {
335
+ ...d,
336
+ value: stackedValue[i],
337
+ }
338
+ })
339
+ })
340
+ return computedData
341
+ }),
342
+ )
343
+
344
+ return isSeriesSeprate$.pipe(
345
+ switchMap(isSeriesSeprate => {
346
+ return iif(() => isSeriesSeprate, computedData$, stackedData$)
347
+ })
348
+ )
349
+ }
350
+
351
+ export const categoryScaleDomainValueObservable = ({ selectedGridData$, categoryAxis$ }: {
352
+ selectedGridData$: Observable<ModelDataGrid>
353
+ categoryAxis$: Observable<CategoryAxis>
354
+ }): Observable<[number, number]> => {
355
+ return combineLatest({
356
+ selectedGridData: selectedGridData$,
357
+ categoryAxis: categoryAxis$
358
+ }).pipe(
359
+ debounceTime(0),
360
+ map(data => {
361
+ const categoryAxis = data.categoryAxis
362
+ const categoryMin = 0
363
+ const categoryMax = data.selectedGridData[0] ? data.selectedGridData[0].length - 1 : 0
364
+ // const categoryScaleDomainMin = categoryAxis.scaleDomain[0] === 'min'
365
+ // ? categoryMin - categoryAxis.scalePadding
366
+ // : categoryAxis.scaleDomain[0] as number - categoryAxis.scalePadding
367
+ const categoryScaleDomainMin = categoryAxis.scaleDomain[0] - categoryAxis.scalePadding
368
+ const categoryScaleDomainMax = categoryAxis.scaleDomain[1] === 'max'
369
+ ? categoryMax + categoryAxis.scalePadding
370
+ : categoryAxis.scaleDomain[1] as number + categoryAxis.scalePadding
371
+
372
+ return [categoryScaleDomainMin, categoryScaleDomainMax]
373
+ })
374
+ )
375
+ }
376
+
377
+ export const filteredMinMaxValueObservable = ({ computedData$, categoryScaleDomainValue$ }: {
378
+ computedData$: Observable<ComputedData<'grid'>>
379
+ // fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
380
+ categoryScaleDomainValue$: Observable<[number, number]>
381
+ }) => {
382
+ return combineLatest({
383
+ computedData: computedData$,
384
+ // fullDataFormatter: fullDataFormatter$,
385
+ categoryScaleDomainValue: categoryScaleDomainValue$
386
+ }).pipe(
387
+ map(data => {
388
+ const filteredData = data.computedData.map((d, i) => {
389
+ return d.filter((_d, _i) => {
390
+ return _i >= data.categoryScaleDomainValue[0] && _i <= data.categoryScaleDomainValue[1] && _d.visible == true
391
+ })
392
+ })
393
+
394
+ const filteredMinMax = getMinMaxValue(filteredData.flat())
395
+ // if (filteredMinMax[0] === filteredMinMax[1]) {
396
+ // filteredMinMax[0] = filteredMinMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
397
+ // }
398
+ return filteredMinMax
399
+ }),
400
+ )
401
+ }
402
+
403
+ export const gridAxesTransformObservable = ({ categoryAxis$, valueAxis$, layout$ }: {
404
+ categoryAxis$: Observable<CategoryAxis>
405
+ valueAxis$: Observable<ValueAxis>
406
+ layout$: Observable<Layout>
407
+ }): Observable<TransformData> => {
408
+ const destroy$ = new Subject()
409
+
410
+ function calcAxesTransform ({ xAxis, yAxis, width, height }: {
411
+ xAxis: CategoryAxis | ValueAxis,
412
+ yAxis: ValueAxis,
413
+ width: number,
414
+ height: number
415
+ }): TransformData {
416
+ if (!xAxis || !yAxis) {
417
+ return {
418
+ translate: [0, 0],
419
+ scale: [1, 1],
420
+ rotate: 0,
421
+ rotateX: 0,
422
+ rotateY: 0,
423
+ value: ''
424
+ }
425
+ }
426
+ // const width = size.width - fullChartParams.layout.left - fullChartParams.layout.right
427
+ // const height = size.height - fullChartParams.layout.top - fullChartParams.layout.bottom
428
+ let translateX = 0
429
+ let translateY = 0
430
+ let rotate = 0
431
+ let rotateX = 0
432
+ let rotateY = 0
433
+ if (xAxis.position === 'bottom') {
434
+ if (yAxis.position === 'left') {
435
+ rotateX = 180
436
+ translateY = height
437
+ } else if (yAxis.position === 'right') {
438
+ rotateX = 180
439
+ rotateY = 180
440
+ translateX = width
441
+ translateY = height
442
+ } else {
443
+ // 預設
444
+ rotateX = 180
445
+ translateY = height
446
+ }
447
+ } else if (xAxis.position === 'top') {
448
+ if (yAxis.position === 'left') {
449
+ } else if (yAxis.position === 'right') {
450
+ rotateY = 180
451
+ translateX = width
452
+ } else {
453
+ // 預設
454
+ rotateX = 180
455
+ translateY = height
456
+ }
457
+ } else if (xAxis.position === 'left') {
458
+ if (yAxis.position === 'bottom') {
459
+ rotate = -90
460
+ translateY = height
461
+ } else if (yAxis.position === 'top') {
462
+ rotate = -90
463
+ rotateY = 180
464
+ } else {
465
+ // 預設
466
+ rotateX = 180
467
+ translateY = height
468
+ }
469
+ } else if (xAxis.position === 'right') {
470
+ if (yAxis.position === 'bottom') {
471
+ rotate = -90
472
+ rotateX = 180
473
+ translateY = height
474
+ translateX = width
475
+ } else if (yAxis.position === 'top') {
476
+ rotate = -90
477
+ rotateX = 180
478
+ rotateY = 180
479
+ translateX = width
480
+ } else {
481
+ // 預設
482
+ rotateX = 180
483
+ translateY = height
484
+ }
485
+ } else {
486
+ // 預設
487
+ rotateX = 180
488
+ translateY = height
489
+ }
490
+ // selection.style('transform', `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`)
491
+
492
+ return {
493
+ translate: [translateX, translateY],
494
+ scale: [1, 1],
495
+ rotate,
496
+ rotateX,
497
+ rotateY,
498
+ value: `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
499
+ }
500
+ }
501
+
502
+ return new Observable(subscriber => {
503
+ combineLatest({
504
+ categoryAxis: categoryAxis$,
505
+ valueAxis: valueAxis$,
506
+ layout: layout$
507
+ }).pipe(
508
+ takeUntil(destroy$),
509
+ debounceTime(0),
510
+ ).subscribe(data => {
511
+ const axesTransformData = calcAxesTransform({
512
+ xAxis: data.categoryAxis,
513
+ yAxis: data.valueAxis,
514
+ width: data.layout.width,
515
+ height: data.layout.height
516
+ })
517
+
518
+ subscriber.next(axesTransformData)
519
+ })
520
+
521
+ return function unscbscribe () {
522
+ destroy$.next(undefined)
523
+ }
524
+ })
525
+ }
526
+
527
+ export const gridAxesReverseTransformObservable = ({ gridAxesTransform$ }: {
528
+ gridAxesTransform$: Observable<TransformData>
529
+ }): Observable<TransformData> => {
530
+ return gridAxesTransform$.pipe(
531
+ map(d => {
532
+ // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
533
+ const translate: [number, number] = [0, 0] // 無需逆轉
534
+ const scale: [number, number] = [1 / d.scale[0], 1 / d.scale[1]]
535
+ const rotate = d.rotate * -1
536
+ const rotateX = d.rotateX * -1
537
+ const rotateY = d.rotateY * -1
538
+ return {
539
+ translate,
540
+ scale,
541
+ rotate,
542
+ rotateX,
543
+ rotateY,
544
+ value: `translate(${translate[0]}px, ${translate[1]}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotate(${rotate}deg)`
545
+ }
546
+ }),
547
+ )
548
+ }
549
+
550
+ export const gridGraphicTransformObservable = ({ computedData$, categoryScaleDomainValue$, filteredMinMaxValue$, categoryAxis$, valueAxis$, layout$ }: {
551
+ computedData$: Observable<ComputedData<'grid'>>
552
+ categoryScaleDomainValue$: Observable<[number, number]>
553
+ filteredMinMaxValue$: Observable<[number, number]>
554
+ categoryAxis$: Observable<CategoryAxis>
555
+ valueAxis$: Observable<ValueAxis>
556
+ layout$: Observable<Layout>
557
+ }): Observable<TransformData> => {
558
+ const destroy$ = new Subject()
559
+
560
+ function calcGridDataAreaTransform ({ data, categoryAxis, valueAxis, categoryScaleDomainValue, filteredMinMaxValue, width, height }: {
561
+ data: ComputedData<'grid'>
562
+ categoryAxis: CategoryAxis
563
+ valueAxis: ValueAxis
564
+ categoryScaleDomainValue: [number, number],
565
+ filteredMinMaxValue: [number, number],
566
+ width: number
567
+ height: number
568
+ }): TransformData {
569
+ let translateX = 0
570
+ let translateY = 0
571
+ let scaleX = 0
572
+ let scaleY = 0
573
+
574
+ // -- categoryScale --
575
+ const categoryAxisWidth = (categoryAxis.position === 'top' || categoryAxis.position === 'bottom')
576
+ ? width
577
+ : height
578
+ const categoryMin = 0
579
+ const categoryMax = data[0] ? data[0].length - 1 : 0
580
+ // const categoryScaleDomainMin = categoryAxis.scaleDomain[0] - categoryAxis.scalePadding
581
+ // const categoryScaleDomainMax = categoryAxis.scaleDomain[1] === 'max'
582
+ // ? categoryMax + categoryAxis.scalePadding
583
+ // : categoryAxis.scaleDomain[1] as number + categoryAxis.scalePadding
584
+
585
+ const categoryScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
586
+ maxValue: categoryMax,
587
+ minValue: categoryMin,
588
+ axisWidth: categoryAxisWidth,
589
+ // scaleDomain: categoryAxis.scaleDomain,
590
+ scaleDomain: categoryScaleDomainValue,
591
+ scaleRange: [0, 1]
592
+ })
593
+
594
+ // -- translateX, scaleX --
595
+ const rangeMinX = categoryScale(categoryMin)
596
+ const rangeMaxX = categoryScale(categoryMax)
597
+ if (categoryMin == categoryMax) {
598
+ // 當category只有一個
599
+ translateX = 0
600
+ scaleX = 1
601
+ } else {
602
+ translateX = rangeMinX
603
+ const gWidth = rangeMaxX - rangeMinX
604
+ scaleX = gWidth / categoryAxisWidth
605
+ }
606
+
607
+ // -- valueScale --
608
+ // const filteredData = data.map((d, i) => {
609
+ // return d.filter((_d, _i) => {
610
+ // return _i >= categoryScaleDomainMin && _i <= categoryScaleDomainMax && _d.visible == true
611
+ // })
612
+ // })
613
+
614
+ // const filteredMinMax = getMinMaxGrid(filteredData)
615
+ const filteredMin = filteredMinMaxValue[0]
616
+ let filteredMax = filteredMinMaxValue[1]
617
+ if (filteredMin === filteredMax && filteredMax === 0) {
618
+ // filteredMinMaxValue[0] = filteredMinMaxValue[1] - 1 // 避免最大及最小值相同造成無法計算scale
619
+ filteredMax = 1 // 避免最大及最小值同等於 0 造成無法計算scale
620
+ }
621
+
622
+ const valueAxisWidth = (valueAxis.position === 'left' || valueAxis.position === 'right')
623
+ ? height
624
+ : width
625
+
626
+ const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
627
+ maxValue: filteredMax,
628
+ minValue: filteredMin,
629
+ axisWidth: valueAxisWidth,
630
+ scaleDomain: valueAxis.scaleDomain,
631
+ scaleRange: valueAxis.scaleRange
632
+ })
633
+ // console.log({
634
+ // maxValue: filteredMinMaxValue[1],
635
+ // minValue: filteredMinMaxValue[0],
636
+ // axisWidth: valueAxisWidth,
637
+ // scaleDomain: valueAxis.scaleDomain,
638
+ // scaleRange: valueAxis.scaleRange
639
+ // })
640
+ // -- translateY, scaleY --
641
+ const minMax = getMinMaxValue(data.flat())
642
+ const min = minMax[0]
643
+ let max = minMax[1]
644
+ if (min === max && max === 0) {
645
+ // minMax[0] = minMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
646
+ max = 1 // 避免最大及最小值同等於 0 造成無法計算scale
647
+ }
648
+ // const rangeMinY = valueScale(minMax[0])
649
+ const rangeMinY = valueScale(minMax[0] > 0 ? 0 : minMax[0]) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
650
+ const rangeMaxY = valueScale(minMax[1] < 0 ? 0 : minMax[1]) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
651
+ translateY = rangeMinY
652
+ const gHeight = rangeMaxY - rangeMinY
653
+ scaleY = gHeight / valueAxisWidth
654
+
655
+ return {
656
+ translate: [translateX, translateY],
657
+ scale: [scaleX, scaleY],
658
+ rotate: 0,
659
+ rotateX: 0,
660
+ rotateY: 0,
661
+ value: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`
662
+ }
663
+ }
664
+
665
+ return new Observable(subscriber => {
666
+ combineLatest({
667
+ computedData: computedData$,
668
+ categoryScaleDomainValue: categoryScaleDomainValue$,
669
+ filteredMinMaxValue: filteredMinMaxValue$,
670
+ categoryAxis: categoryAxis$,
671
+ valueAxis: valueAxis$,
672
+ layout: layout$
673
+ }).pipe(
674
+ takeUntil(destroy$),
675
+ debounceTime(0),
676
+ ).subscribe(data => {
677
+ const dataAreaTransformData = calcGridDataAreaTransform ({
678
+ data: data.computedData,
679
+ categoryAxis: data.categoryAxis,
680
+ valueAxis: data.valueAxis,
681
+ categoryScaleDomainValue: data.categoryScaleDomainValue,
682
+ filteredMinMaxValue: data.filteredMinMaxValue,
683
+ width: data.layout.width,
684
+ height: data.layout.height
685
+ })
686
+
687
+ subscriber.next(dataAreaTransformData)
688
+ })
689
+
690
+ return function unsubscribe () {
691
+ destroy$.next(undefined)
692
+ }
693
+ })
694
+ }
695
+
696
+ export const gridGraphicReverseScaleObservable = ({ gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
697
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
698
+ gridAxesTransform$: Observable<TransformData>
699
+ gridGraphicTransform$: Observable<TransformData>
700
+ }): Observable<[number, number][]> => {
701
+ return combineLatest({
702
+ gridContainerPosition: gridContainerPosition$,
703
+ gridAxesTransform: gridAxesTransform$,
704
+ gridGraphicTransform: gridGraphicTransform$,
705
+ }).pipe(
706
+ debounceTime(0),
707
+ map(data => {
708
+ if (data.gridAxesTransform.rotate == 0 || data.gridAxesTransform.rotate == 180) {
709
+ return data.gridContainerPosition.map((series, seriesIndex) => {
710
+ return [
711
+ 1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[0],
712
+ 1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[1],
713
+ ]
714
+ })
715
+ } else {
716
+ return data.gridContainerPosition.map((series, seriesIndex) => {
717
+ // 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
718
+ return [
719
+ 1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[1],
720
+ 1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[0],
721
+ ]
722
+ })
723
+ }
724
+ }),
725
+ )
726
+ }