@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,901 @@
1
+ import {
2
+ combineLatest,
3
+ distinctUntilChanged,
4
+ iif,
5
+ filter,
6
+ map,
7
+ merge,
8
+ takeUntil,
9
+ shareReplay,
10
+ switchMap,
11
+ Subject,
12
+ Observable,
13
+ debounceTime} from 'rxjs'
14
+ import type {
15
+ ContainerSize,
16
+ ComputedDatumMultivariate,
17
+ ComputedData,
18
+ XYAxis,
19
+ TransformData,
20
+ Layout
21
+ } from '../../types'
22
+ import type { ContainerPositionScaled } from '../../types/PluginParams'
23
+ import type { ComputedXYDatumMultivariate, ComputedXYDataMultivariate, ScatterPlotPluginParams } from './types'
24
+ import { getMinMax } from '../../utils/commonUtils'
25
+ import { createValueToAxisScale, createLabelToAxisScale, createAxisToLabelIndexScale } from '../../utils/d3Scale'
26
+ import { calcContainerPositionScaled } from '../../utils/orbchartsUtils'
27
+ import { Encoding, ModelDataMultivariate } from '@orbcharts/core'
28
+
29
+ interface ComputedDatumWithSumMultivariate extends ComputedDatumMultivariate {
30
+ sum: number
31
+ }
32
+
33
+ const xValueIndex = 0
34
+ const yValueIndex = 1
35
+
36
+ export const multivariateComputedDataObservable = ({ selectedMultivariateData$, pluginParams$ }: {
37
+ selectedMultivariateData$: Observable<ModelDataMultivariate>
38
+ pluginParams$: Observable<ScatterPlotPluginParams>
39
+ }): Observable<ComputedDatumMultivariate[][]> => {
40
+ return combineLatest({
41
+ selectedMultivariateData: selectedMultivariateData$,
42
+ pluginParams: pluginParams$
43
+ }).pipe(
44
+ debounceTime(0),
45
+ map(({ selectedMultivariateData, pluginParams }) => {
46
+ return selectedMultivariateData
47
+ .map((data) => {
48
+ return data.map((datum, index) => {
49
+ const visibleFilter = pluginParams.visibleFilter
50
+ return {
51
+ ...datum,
52
+ visible: visibleFilter ? visibleFilter(datum) : true,
53
+ }
54
+ })
55
+ })
56
+ })
57
+ )
58
+ }
59
+
60
+ function createDefaultValueLabel (chartTypeOrPrefix: string, valueIndex: number) {
61
+ // return `${chartTypeOrPrefix}_value${valueIndex}`
62
+ return `value${valueIndex}`
63
+ }
64
+
65
+ export const valueLabelsObservable = ({ encoding$ }: {
66
+ // computedData$: Observable<ComputedData<'multivariate'>>
67
+ encoding$: Observable<Encoding>
68
+ }) => {
69
+ // return combineLatest({
70
+ // computedData: computedData$,
71
+ // encoding: encoding$,
72
+ // }).pipe(
73
+ // map(data => {
74
+ // return data.computedData[0] && data.computedData[0][0] && data.computedData[0][0].multivariate.length
75
+ // ? data.computedData[0][0].multivariate.map((d, i) => data.encoding.multivariate[i].name ?? createDefaultValueLabel('multivariate', i))
76
+ // : []
77
+ // }),
78
+ // )
79
+ return encoding$.pipe(
80
+ map(encoding => {
81
+ return encoding.multivariate.map((d, i) => d.name ?? createDefaultValueLabel('multivariate', i))
82
+ }),
83
+ distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
84
+ )
85
+ }
86
+
87
+ export const xyMinMaxObservable = ({ computedData$, xyValueIndex$ }: {
88
+ computedData$: Observable<ComputedData<'multivariate'>>
89
+ xyValueIndex$: Observable<[number, number]>
90
+ }) => {
91
+ return combineLatest({
92
+ computedData: computedData$,
93
+ xyValueIndex: xyValueIndex$,
94
+ }).pipe(
95
+ map(data => {
96
+ const flatData = data.computedData.flat()
97
+ const [minX, maxX] = getMinMax(flatData.map(d => d.multivariate[data.xyValueIndex[0]].value))
98
+ const [minY, maxY] = getMinMax(flatData.map(d => d.multivariate[data.xyValueIndex[1]].value))
99
+ return { minX, maxX, minY, maxY }
100
+ })
101
+ )
102
+ }
103
+
104
+ export const computedXYDataObservable = ({ computedData$, xyMinMax$, xyValueIndex$, layout$ }: {
105
+ computedData$: Observable<ComputedData<'multivariate'>>
106
+ xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
107
+ xyValueIndex$: Observable<[number, number]>
108
+ layout$: Observable<Layout>
109
+ }): Observable<ComputedXYDataMultivariate> => {
110
+
111
+ // 未篩選範圍前的 scale
112
+ function createOriginXScale (xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }, layout: Layout) {
113
+ let maxValue = xyMinMax.maxX
114
+ let minValue = xyMinMax.minX
115
+ if (minValue === maxValue && maxValue === 0) {
116
+ // 避免最大及最小值相同造成無法計算scale
117
+ maxValue = 1
118
+ }
119
+ const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
120
+ maxValue,
121
+ minValue,
122
+ axisWidth: layout.width,
123
+ scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
124
+ scaleRange: [0, 1] // 不使用dataFormatter設定
125
+ })
126
+
127
+ return valueScale
128
+ }
129
+
130
+ // 未篩選範圍及visible前的 scale
131
+ function createOriginYScale (xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }, layout: Layout) {
132
+ let maxValue = xyMinMax.maxY
133
+ let minValue = xyMinMax.minY
134
+ if (minValue === maxValue && maxValue === 0) {
135
+ // 避免最大及最小值相同造成無法計算scale
136
+ maxValue = 1
137
+ }
138
+ const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
139
+ maxValue,
140
+ minValue,
141
+ axisWidth: layout.height,
142
+ scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
143
+ scaleRange: [0, 1], // 不使用dataFormatter設定
144
+ reverse: true
145
+ })
146
+
147
+ return valueScale
148
+ }
149
+
150
+ return combineLatest({
151
+ computedData: computedData$,
152
+ xyMinMax: xyMinMax$,
153
+ xyValueIndex: xyValueIndex$,
154
+ layout: layout$
155
+ }).pipe(
156
+ switchMap(async d => d),
157
+ map(data => {
158
+
159
+ const xScale = createOriginXScale(data.xyMinMax, data.layout)
160
+ const yScale = createOriginYScale(data.xyMinMax, data.layout)
161
+
162
+ return data.computedData
163
+ .map((categoryData, categoryIndex) => {
164
+ return categoryData.map((datum, datumIndex) => {
165
+ return {
166
+ ...datum,
167
+ axisX: xScale(datum.multivariate[data.xyValueIndex[0]].value ?? 0),
168
+ // axisY: data.layout.height - yScale(datum.value[1] ?? 0), // y軸的繪圖座標是從上到下,所以反轉
169
+ axisY: yScale(datum.multivariate[data.xyValueIndex[1]].value ?? 0), // y軸的繪圖座標是從上到下,所以反轉
170
+ }
171
+ })
172
+ })
173
+ })
174
+ )
175
+ }
176
+
177
+ export const seriesLabelsObservable = ({ computedData$ }: {
178
+ computedData$: Observable<ComputedData<'multivariate'>>
179
+ }) => {
180
+ return computedData$.pipe(
181
+ map(data => {
182
+ return data
183
+ .map(d => d[0] ? d[0].series : '')
184
+ // .filter(d => d != null && d != '')
185
+ }),
186
+ distinctUntilChanged((a, b) => {
187
+ return JSON.stringify(a) === JSON.stringify(b)
188
+ }),
189
+ )
190
+ }
191
+
192
+ export const visibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedData<'multivariate'>> }) => {
193
+ return computedData$.pipe(
194
+ map(data => {
195
+ return data
196
+ .map(categoryData => {
197
+ return categoryData.filter(d => d.visible == true)
198
+ })
199
+ .filter(categoryData => {
200
+ return categoryData.length > 0
201
+ })
202
+ })
203
+ )
204
+ }
205
+
206
+ export const ordinalScaleDomainObservable = ({ visibleComputedData$, xAxis$ }: {
207
+ visibleComputedData$: Observable<ComputedData<'multivariate'>>
208
+ xAxis$: Observable<XYAxis>
209
+ }) => {
210
+ return combineLatest({
211
+ visibleComputedData: visibleComputedData$,
212
+ xAxis: xAxis$,
213
+ }).pipe(
214
+ map(data => {
215
+ let maxValue: number = data.visibleComputedData[0] && data.visibleComputedData[0][0] && data.visibleComputedData[0][0].multivariate.length
216
+ ? data.visibleComputedData[0][0].multivariate.length - 1
217
+ : 0
218
+ const scaleDomain: [number, number] = [
219
+ data.xAxis.scaleDomain[0] === 'auto' || data.xAxis.scaleDomain[0] === 'min'
220
+ ? 0
221
+ : data.xAxis.scaleDomain[0] as number,
222
+ data.xAxis.scaleDomain[1] === 'auto' || data.xAxis.scaleDomain[1] === 'max'
223
+ ? maxValue
224
+ : data.xAxis.scaleDomain[1] as number
225
+ ]
226
+ return scaleDomain
227
+ }),
228
+ distinctUntilChanged((a, b) => a[0] === b[0] && a[1] === b[1])
229
+ )
230
+ }
231
+
232
+ export const visibleComputedSumDataObservable = ({ visibleComputedData$, ordinalScaleDomain$ }: {
233
+ visibleComputedData$: Observable<ComputedData<'multivariate'>>
234
+ // fullDataFormatter$: Observable<DataFormatterTypeMap<'multivariate'>>
235
+ ordinalScaleDomain$: Observable<[number, number]>
236
+ }) => {
237
+
238
+ return combineLatest({
239
+ visibleComputedData: visibleComputedData$,
240
+ ordinalScaleDomain: ordinalScaleDomain$,
241
+ }).pipe(
242
+ map(data => {
243
+ return data.visibleComputedData.map(categoryData => {
244
+ return categoryData
245
+ .map((d, i) => {
246
+ let newDatum = d as ComputedDatumWithSumMultivariate
247
+ // 新增總計資料欄位
248
+ newDatum.sum = newDatum.multivariate
249
+ // 只加總範圍內的
250
+ .filter((d, i) => i >= data.ordinalScaleDomain[0] && i <= data.ordinalScaleDomain[1])
251
+ .reduce((acc, curr) => acc + curr.value, 0)
252
+ return newDatum
253
+ })
254
+ })
255
+ })
256
+ )
257
+ }
258
+
259
+ // Ranking資料 - 用 value[index] 排序
260
+ export const visibleComputedRankingByIndexDataObservable = ({ xyValueIndex$, isSeriesSeprate$, visibleComputedData$ }: {
261
+ xyValueIndex$: Observable<[number, number]>
262
+ isSeriesSeprate$: Observable<boolean>
263
+ visibleComputedData$: Observable<ComputedDatumMultivariate[][]>
264
+ }) => {
265
+
266
+ return combineLatest({
267
+ isSeriesSeprate: isSeriesSeprate$,
268
+ xyValueIndex: xyValueIndex$,
269
+ visibleComputedData: visibleComputedData$
270
+ }).pipe(
271
+ switchMap(async d => d),
272
+ map(data => {
273
+ const xValueIndex = data.xyValueIndex[0]
274
+ // -- category 分開 --
275
+ if (data.isSeriesSeprate) {
276
+ return data.visibleComputedData
277
+ .map(categoryData => {
278
+ return categoryData
279
+ .sort((a, b) => {
280
+ const bValue = b.multivariate[xValueIndex].value ?? - Infinity // - Infinity 為最小值
281
+ const aValue = a.multivariate[xValueIndex].value ?? - Infinity
282
+
283
+ return bValue - aValue
284
+ })
285
+ })
286
+ // -- 用 value[index] 排序 --
287
+ } else {
288
+ return [
289
+ data.visibleComputedData
290
+ .flat()
291
+ .sort((a, b) => {
292
+ const bValue = b.multivariate[xValueIndex].value ?? - Infinity // - Infinity 為最小值
293
+ const aValue = a.multivariate[xValueIndex].value ?? - Infinity
294
+
295
+ return bValue - aValue
296
+ })
297
+ ]
298
+ }
299
+ })
300
+ )
301
+ }
302
+
303
+ // Ranking資料 - 用所有 valueIndex 加總資料排序
304
+ export const visibleComputedRankingBySumDataObservable = ({ isSeriesSeprate$, visibleComputedSumData$ }: {
305
+ isSeriesSeprate$: Observable<boolean>
306
+ // visibleComputedData$: Observable<ComputedDatumMultivariate[][]>
307
+ visibleComputedSumData$: Observable<ComputedDatumWithSumMultivariate[][]>
308
+ }) => {
309
+
310
+ return combineLatest({
311
+ isSeriesSeprate: isSeriesSeprate$,
312
+ visibleComputedSumData: visibleComputedSumData$
313
+ }).pipe(
314
+ switchMap(async d => d),
315
+ map(data => {
316
+ // -- category 分開 --
317
+ if (data.isSeriesSeprate) {
318
+ return data.visibleComputedSumData
319
+ .map(categoryData => {
320
+ return categoryData
321
+ .sort((a, b) => b.sum - a.sum)
322
+ })
323
+ // -- 用 value[index] 排序 --
324
+ } else {
325
+ return [
326
+ data.visibleComputedSumData
327
+ .flat()
328
+ .sort((a, b) => b.sum - a.sum)
329
+ ]
330
+ }
331
+ })
332
+ )
333
+ }
334
+
335
+ export const visibleComputedXYDataObservable = ({ computedXYData$ }: { computedXYData$: Observable<ComputedXYDataMultivariate> }) => {
336
+ return computedXYData$.pipe(
337
+ map(data => {
338
+ return data
339
+ .map(categoryData => {
340
+ return categoryData.filter(d => d.visible == true)
341
+ })
342
+ .filter(categoryData => {
343
+ return categoryData.length > 0
344
+ })
345
+ })
346
+ )
347
+ }
348
+
349
+ // 所有container位置(對應category)
350
+ export const containerPositionObservable = ({ computedData$, pluginParams$, layout$ }: {
351
+ computedData$: Observable<ComputedData<'multivariate'>>
352
+ pluginParams$: Observable<ScatterPlotPluginParams>
353
+ layout$: Observable<Layout>
354
+ }): Observable<ContainerPositionScaled[]> => {
355
+
356
+ const containerPosition$ = combineLatest({
357
+ computedData: computedData$,
358
+ pluginParams: pluginParams$,
359
+ layout: layout$,
360
+ }).pipe(
361
+ debounceTime(0),
362
+ map(data => {
363
+ // 無資料時回傳預設container位置
364
+ if (data.computedData.length === 0) {
365
+ const defaultPositionArr: ContainerPositionScaled[] = [
366
+ {
367
+ "slotIndex": 0,
368
+ "rowIndex": 0,
369
+ "columnIndex": 0,
370
+ "translate": [0, 0],
371
+ "scale": [1, 1]
372
+ }
373
+ ]
374
+ return defaultPositionArr
375
+ }
376
+ if (data.pluginParams.separateSeries) {
377
+ // -- 依slotIndexes計算 --
378
+ return calcContainerPositionScaled(data.layout, data.pluginParams.container, data.computedData.length)
379
+ // return data.computedData.map((seriesData, seriesIndex) => {
380
+ // const columnIndex = seriesIndex % data.pluginParams.container.columnAmount
381
+ // const rowIndex = Math.floor(seriesIndex / data.pluginParams.container.columnAmount)
382
+ // const { translate, scale } = calcMultivariateContainerPosition(data.layout, data.pluginParams.container, rowIndex, columnIndex)
383
+ // return {
384
+ // slotIndex: seriesIndex,
385
+ // rowIndex,
386
+ // columnIndex,
387
+ // translate,
388
+ // scale,
389
+ // }
390
+ // })
391
+ } else {
392
+ // -- 無拆分 --
393
+ const containerPositionArr = calcContainerPositionScaled(data.layout, data.pluginParams.container, 1)
394
+ return data.computedData.map((d, i) => containerPositionArr[0]) // 每個series相同位置
395
+ // const columnIndex = 0
396
+ // const rowIndex = 0
397
+ // return data.computedData.map((seriesData, seriesIndex) => {
398
+ // const { translate, scale } = calcMultivariateContainerPosition(data.layout, data.pluginParams.container, rowIndex, columnIndex)
399
+ // return {
400
+ // slotIndex: 0,
401
+ // rowIndex,
402
+ // columnIndex,
403
+ // translate,
404
+ // scale,
405
+ // }
406
+ // })
407
+ }
408
+ })
409
+ )
410
+
411
+ return containerPosition$
412
+ }
413
+
414
+ export const filteredXYMinMaxDataObservable = ({ visibleComputedXYData$, xyMinMax$, xyValueIndex$, xAxis$, yAxis$ }: {
415
+ visibleComputedXYData$: Observable<ComputedXYDataMultivariate>
416
+ xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
417
+ xyValueIndex$: Observable<[number, number]>
418
+ xAxis$: Observable<XYAxis>
419
+ yAxis$: Observable<XYAxis>
420
+ }) => {
421
+ return combineLatest({
422
+ visibleComputedXYData: visibleComputedXYData$,
423
+ xyMinMax: xyMinMax$,
424
+ xyValueIndex: xyValueIndex$,
425
+ xAxis: xAxis$,
426
+ yAxis: yAxis$,
427
+ }).pipe(
428
+ map(data => {
429
+ // 所有可見資料依 dataFormatter 的 scale 設定篩選出最大小值
430
+ const { minX, maxX, minY, maxY } = (() => {
431
+
432
+ let { minX, maxX, minY, maxY } = data.xyMinMax
433
+
434
+ if (data.xAxis.scaleDomain[0] === 'auto' && minX > 0) {
435
+ minX = 0
436
+ } else if (typeof data.xAxis.scaleDomain[0] === 'number') {
437
+ minX = data.xAxis.scaleDomain[0] as number
438
+ }
439
+ if (data.xAxis.scaleDomain[1] === 'auto' && maxX < 0) {
440
+ maxX = 0
441
+ } else if (typeof data.xAxis.scaleDomain[1] === 'number') {
442
+ maxX = data.xAxis.scaleDomain[1] as number
443
+ }
444
+ if (data.yAxis.scaleDomain[0] === 'auto' && minY > 0) {
445
+ minY = 0
446
+ } else if (typeof data.yAxis.scaleDomain[0] === 'number') {
447
+ minY = data.yAxis.scaleDomain[0] as number
448
+ }
449
+ if (data.yAxis.scaleDomain[1] === 'auto' && maxY < 0) {
450
+ maxY = 0
451
+ } else if (typeof data.yAxis.scaleDomain[1] === 'number') {
452
+ maxY = data.yAxis.scaleDomain[1] as number
453
+ }
454
+
455
+ return { minX, maxX, minY, maxY }
456
+ })()
457
+ // console.log({ minX, maxX, minY, maxY })
458
+ let datumList: ComputedXYDatumMultivariate[] = []
459
+ let minXDatum: ComputedXYDatumMultivariate | null = null
460
+ let maxXDatum: ComputedXYDatumMultivariate | null = null
461
+ let minYDatum: ComputedXYDatumMultivariate | null = null
462
+ let maxYDatum: ComputedXYDatumMultivariate | null = null
463
+ // console.log('data.visibleComputedXYData', data.visibleComputedXYData)
464
+ // minX, maxX, minY, maxY 範圍內的最大最小值資料
465
+ // console.log({ minX, maxX, minY, maxY })
466
+ for (let categoryData of data.visibleComputedXYData) {
467
+ for (let datum of categoryData) {
468
+ const xValue = datum.multivariate[data.xyValueIndex[0]].value
469
+ const yValue = datum.multivariate[data.xyValueIndex[1]].value
470
+ // 比較矩形範圍(所以 minX, maxX, minY, maxY 要同時比較)
471
+ if (xValue >= minX && xValue <= maxX && yValue >= minY && yValue <= maxY) {
472
+ datumList.push(datum)
473
+ if (minXDatum == null || xValue < minXDatum.multivariate[data.xyValueIndex[0]].value) {
474
+ minXDatum = datum
475
+ }
476
+ if (maxXDatum == null || xValue > maxXDatum.multivariate[data.xyValueIndex[0]].value) {
477
+ maxXDatum = datum
478
+ }
479
+ if (minYDatum == null || yValue < minYDatum.multivariate[data.xyValueIndex[1]].value) {
480
+ minYDatum = datum
481
+ }
482
+ if (maxYDatum == null || yValue > maxYDatum.multivariate[data.xyValueIndex[1]].value) {
483
+ maxYDatum = datum
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ return {
490
+ datumList,
491
+ minXDatum,
492
+ maxXDatum,
493
+ minYDatum,
494
+ maxYDatum
495
+ }
496
+ })
497
+ )
498
+ }
499
+
500
+ export const graphicTransformObservable = ({ xyMinMax$, xyValueIndex$, filteredXYMinMaxData$, xAxis$, yAxis$, layout$ }: {
501
+ xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
502
+ xyValueIndex$: Observable<[number, number]>
503
+ filteredXYMinMaxData$: Observable<{
504
+ minXDatum: ComputedXYDatumMultivariate
505
+ maxXDatum: ComputedXYDatumMultivariate
506
+ minYDatum: ComputedXYDatumMultivariate
507
+ maxYDatum: ComputedXYDatumMultivariate
508
+ }>
509
+ xAxis$: Observable<XYAxis>
510
+ yAxis$: Observable<XYAxis>
511
+ layout$: Observable<Layout>
512
+ }): Observable<TransformData> => {
513
+ const destroy$ = new Subject()
514
+
515
+ function calcDataAreaTransform ({ xyMinMax, xyValueIndex, filteredXYMinMaxData, xAxis, yAxis, width, height }: {
516
+ xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }
517
+ xyValueIndex: [number, number]
518
+ filteredXYMinMaxData: {
519
+ minXDatum: ComputedXYDatumMultivariate
520
+ maxXDatum: ComputedXYDatumMultivariate
521
+ minYDatum: ComputedXYDatumMultivariate
522
+ maxYDatum: ComputedXYDatumMultivariate
523
+ }
524
+ xAxis: XYAxis
525
+ yAxis: XYAxis
526
+ width: number
527
+ height: number
528
+ }): TransformData {
529
+ // const flatData = data.flat()
530
+
531
+ let translateX = 0
532
+ let translateY = 0
533
+ let scaleX = 0
534
+ let scaleY = 0
535
+
536
+ // // minX, maxX, filteredMinX, filteredMaxX
537
+ // let filteredMinX = 0
538
+ // let filteredMaxX = 0
539
+ // let [minX, maxX] = getMinMax(flatData.map(d => d.multivariate[0].value))
540
+ // if (minX === maxX) {
541
+ // minX = maxX - 1 // 避免最大及最小值相同造成無法計算scale
542
+ // }
543
+ // if (xAxis.scaleDomain[0] === 'auto' && filteredMinX > 0) {
544
+ // filteredMinX = 0
545
+ // } else if (typeof xAxis.scaleDomain[0] === 'number') {
546
+ // filteredMinX = xAxis.scaleDomain[0] as number
547
+ // } else {
548
+ // filteredMinX = minX
549
+ // }
550
+ // if (xAxis.scaleDomain[1] === 'auto' && filteredMaxX < 0) {
551
+ // filteredMaxX = 0
552
+ // } else if (typeof xAxis.scaleDomain[1] === 'number') {
553
+ // filteredMaxX = xAxis.scaleDomain[1] as number
554
+ // } else {
555
+ // filteredMaxX = maxX
556
+ // }
557
+ // if (filteredMinX === filteredMaxX) {
558
+ // filteredMinX = filteredMaxX - 1 // 避免最大及最小值相同造成無法計算scale
559
+ // }
560
+
561
+ // // minY, maxY, filteredMinY, filteredMaxY
562
+ // let filteredMinY = 0
563
+ // let filteredMaxY = 0
564
+ // let [minY, maxY] = getMinMax(flatData.map(d => d.multivariate[1].value))
565
+ // console.log('filteredXYMinMaxData', filteredXYMinMaxData)
566
+ let { minX, maxX, minY, maxY } = xyMinMax
567
+ // console.log({ minX, maxX, minY, maxY })
568
+ let filteredMinX = filteredXYMinMaxData.minXDatum.multivariate[xyValueIndex[0]].value ?? 0
569
+ let filteredMaxX = filteredXYMinMaxData.maxXDatum.multivariate[xyValueIndex[0]].value ?? 0
570
+ let filteredMinY = filteredXYMinMaxData.minYDatum.multivariate[xyValueIndex[1]].value ?? 0
571
+ let filteredMaxY = filteredXYMinMaxData.maxYDatum.multivariate[xyValueIndex[1]].value ?? 0
572
+
573
+ // if (yAxis.scaleDomain[0] === 'auto' && filteredMinY > 0) {
574
+ // filteredMinY = 0
575
+ // } else if (typeof yAxis.scaleDomain[0] === 'number') {
576
+ // filteredMinY = yAxis.scaleDomain[0] as number
577
+ // } else {
578
+ // filteredMinY = minY
579
+ // }
580
+ // if (yAxis.scaleDomain[1] === 'auto' && filteredMaxY < 0) {
581
+ // filteredMaxY = 0
582
+ // } else if (typeof yAxis.scaleDomain[1] === 'number') {
583
+ // filteredMaxY = yAxis.scaleDomain[1] as number
584
+ // } else {
585
+ // filteredMaxY = maxY
586
+ // }
587
+
588
+ // console.log({ minX, maxX, minY, maxY, filteredMinX, filteredMaxX, filteredMinY, filteredMaxY })
589
+ if (filteredMinX === filteredMaxX && filteredMaxX === 0) {
590
+ // 避免最大及最小值相同造成無法計算scale
591
+ filteredMaxX = 1
592
+ }
593
+ if (filteredMinY === filteredMaxY && filteredMaxY === 0) {
594
+ // 避免最大及最小值相同造成無法計算scale
595
+ filteredMaxY = 1
596
+ }
597
+ if (minX === maxX && maxX === 0) {
598
+ // 避免最大及最小值相同造成無法計算scale
599
+ maxX = 1
600
+ }
601
+ if (minY === maxY && maxY === 0) {
602
+ // 避免最大及最小值相同造成無法計算scale
603
+ maxY = 1
604
+ }
605
+ // -- xScale --
606
+ const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
607
+ maxValue: filteredMaxX,
608
+ minValue: filteredMinX,
609
+ axisWidth: width,
610
+ scaleDomain: xAxis.scaleDomain,
611
+ scaleRange: xAxis.scaleRange
612
+ })
613
+
614
+ // -- translateX, scaleX --
615
+ const rangeMinX = xScale(minX > 0 ? 0 : minX) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
616
+ const rangeMaxX = xScale(maxX < 0 ? 0 : maxX) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
617
+ translateX = rangeMinX
618
+ const gWidth = rangeMaxX - rangeMinX
619
+ scaleX = gWidth / width
620
+ // console.log({ gWidth, width, rangeMaxX, rangeMinX, scaleX, translateX })
621
+ // -- yScale --
622
+ const yScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
623
+ maxValue: filteredMaxY,
624
+ minValue: filteredMinY,
625
+ axisWidth: height,
626
+ scaleDomain: yAxis.scaleDomain,
627
+ scaleRange: yAxis.scaleRange,
628
+ reverse: true
629
+ })
630
+
631
+ // -- translateY, scaleY --
632
+ const rangeMinY = yScale(minY > 0 ? 0 : minY) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
633
+ const rangeMaxY = yScale(maxY < 0 ? 0 : maxY) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
634
+ translateY = rangeMaxY // 最大值的 y 最小(最上方)
635
+ const gHeight = rangeMinY - rangeMaxY // 最大的 y 減最小的 y
636
+ scaleY = gHeight / height
637
+
638
+ return {
639
+ translate: [translateX, translateY],
640
+ scale: [scaleX, scaleY],
641
+ rotate: 0,
642
+ rotateX: 0,
643
+ rotateY: 0,
644
+ value: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`
645
+ }
646
+ }
647
+
648
+ return new Observable(subscriber => {
649
+ combineLatest({
650
+ xyMinMax: xyMinMax$,
651
+ xyValueIndex: xyValueIndex$,
652
+ filteredXYMinMaxData: filteredXYMinMaxData$,
653
+ xAxis: xAxis$,
654
+ yAxis: yAxis$,
655
+ layout: layout$
656
+ }).pipe(
657
+ takeUntil(destroy$),
658
+ debounceTime(0),
659
+ ).subscribe(data => {
660
+ if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
661
+ || data.filteredXYMinMaxData.minXDatum.multivariate[data.xyValueIndex[0]].value == null || data.filteredXYMinMaxData.maxXDatum.multivariate[data.xyValueIndex[0]].value == null
662
+ || !data.filteredXYMinMaxData.minYDatum || !data.filteredXYMinMaxData.maxYDatum
663
+ || data.filteredXYMinMaxData.minYDatum.multivariate[data.xyValueIndex[1]].value == null || data.filteredXYMinMaxData.maxYDatum.multivariate[data.xyValueIndex[1]].value == null
664
+ ) {
665
+ return
666
+ }
667
+ const dataAreaTransformData = calcDataAreaTransform({
668
+ xyMinMax: data.xyMinMax,
669
+ xyValueIndex: data.xyValueIndex,
670
+ filteredXYMinMaxData: data.filteredXYMinMaxData,
671
+ xAxis: data.xAxis,
672
+ yAxis: data.yAxis,
673
+ width: data.layout.width,
674
+ height: data.layout.height
675
+ })
676
+
677
+ // console.log('dataAreaTransformData', dataAreaTransformData)
678
+
679
+ subscriber.next(dataAreaTransformData)
680
+ })
681
+
682
+ return function unscbscribe () {
683
+ destroy$.next(undefined)
684
+ }
685
+ })
686
+ }
687
+
688
+ export const graphicReverseScaleObservable = ({ containerPosition$, graphicTransform$ }: {
689
+ containerPosition$: Observable<ContainerPositionScaled[]>
690
+ // multivariateAxesTransform$: Observable<TransformData>
691
+ graphicTransform$: Observable<TransformData>
692
+ }): Observable<[number, number][]> => {
693
+ return combineLatest({
694
+ containerPosition: containerPosition$,
695
+ // multivariateAxesTransform: multivariateAxesTransform$,
696
+ graphicTransform: graphicTransform$,
697
+ }).pipe(
698
+ debounceTime(0),
699
+ map(data => {
700
+ // if (data.multivariateAxesTransform.rotate == 0 || data.multivariateAxesTransform.rotate == 180) {
701
+ return data.containerPosition.map((series, seriesIndex) => {
702
+ return [
703
+ 1 / data.graphicTransform.scale[0] / data.containerPosition[seriesIndex].scale[0],
704
+ 1 / data.graphicTransform.scale[1] / data.containerPosition[seriesIndex].scale[1],
705
+ ]
706
+ })
707
+ // } else {
708
+ // return data.containerPosition.map((series, seriesIndex) => {
709
+ // // 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
710
+ // return [
711
+ // 1 / data.graphicTransform.scale[0] / data.containerPosition[seriesIndex].scale[1],
712
+ // 1 / data.graphicTransform.scale[1] / data.containerPosition[seriesIndex].scale[0],
713
+ // ]
714
+ // })
715
+ // }
716
+ }),
717
+ )
718
+ }
719
+
720
+ // X 軸圖軸 - 用 value[index]
721
+ export const xScaleObservable = ({ visibleComputedSumData$, filteredXYMinMaxData$, xAxis$, containerSize$ }: {
722
+ visibleComputedSumData$: Observable<ComputedDatumMultivariate[][]>
723
+ filteredXYMinMaxData$: Observable<{
724
+ minXDatum: ComputedXYDatumMultivariate
725
+ maxXDatum: ComputedXYDatumMultivariate
726
+ minYDatum: ComputedXYDatumMultivariate
727
+ maxYDatum: ComputedXYDatumMultivariate
728
+ }>
729
+ xAxis$: Observable<XYAxis>
730
+ // layout$: Observable<Layout>
731
+ containerSize$: Observable<ContainerSize>
732
+ }) => {
733
+ return combineLatest({
734
+ visibleComputedSumData: visibleComputedSumData$,
735
+ xAxis: xAxis$,
736
+ containerSize: containerSize$,
737
+ // xyMinMax: xyMinMax$
738
+ filteredXYMinMaxData: filteredXYMinMaxData$
739
+ }).pipe(
740
+ debounceTime(0),
741
+ map(data => {
742
+ // const valueIndex = data.xAxis.valueIndex
743
+ if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
744
+ // || data.filteredXYMinMaxData.minXDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxXDatum.value[valueIndex] == null
745
+ ) {
746
+ return
747
+ }
748
+ let maxValue: number | null = data.filteredXYMinMaxData.maxXDatum.multivariate[xValueIndex].value
749
+ let minValue: number | null = data.filteredXYMinMaxData.minXDatum.multivariate[xValueIndex].value
750
+ if (maxValue === minValue && maxValue === 0) {
751
+ // 避免最大及最小值同等於 0 造成無法計算scale
752
+ maxValue = 1
753
+ }
754
+
755
+ const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
756
+ maxValue,
757
+ minValue,
758
+ axisWidth: data.containerSize.width,
759
+ scaleDomain: data.xAxis.scaleDomain,
760
+ scaleRange: data.xAxis.scaleRange,
761
+ })
762
+ return xScale
763
+ })
764
+ )
765
+ }
766
+
767
+ export const yScaleObservable = ({ yAxis$, filteredXYMinMaxData$, containerSize$ }: {
768
+ yAxis$: Observable<XYAxis>
769
+ filteredXYMinMaxData$: Observable<{
770
+ minXDatum: ComputedXYDatumMultivariate
771
+ maxXDatum: ComputedXYDatumMultivariate
772
+ minYDatum: ComputedXYDatumMultivariate
773
+ maxYDatum: ComputedXYDatumMultivariate
774
+ }>
775
+ containerSize$: Observable<ContainerSize>
776
+ }) => {
777
+ return combineLatest({
778
+ yAxis: yAxis$,
779
+ containerSize: containerSize$,
780
+ // xyMinMax: observer.xyMinMax$
781
+ filteredXYMinMaxData: filteredXYMinMaxData$
782
+ }).pipe(
783
+ debounceTime(0),
784
+ map(data => {
785
+ // const valueIndex = data.yAxis.valueIndex
786
+ if (!data.filteredXYMinMaxData.minYDatum || !data.filteredXYMinMaxData.maxYDatum
787
+ || data.filteredXYMinMaxData.minYDatum.multivariate[yValueIndex].value == null || data.filteredXYMinMaxData.maxYDatum.multivariate[yValueIndex].value == null
788
+ ) {
789
+ return
790
+ }
791
+ let maxValue = data.filteredXYMinMaxData.maxYDatum.multivariate[yValueIndex].value
792
+ let minValue = data.filteredXYMinMaxData.minYDatum.multivariate[yValueIndex].value
793
+ if (maxValue === minValue && maxValue === 0) {
794
+ // 避免最大及最小值同等於 0 造成無法計算scale
795
+ maxValue = 1
796
+ }
797
+
798
+ const yScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
799
+ maxValue,
800
+ minValue,
801
+ axisWidth: data.containerSize.height,
802
+ scaleDomain: data.yAxis.scaleDomain,
803
+ scaleRange: data.yAxis.scaleRange,
804
+ reverse: true
805
+ })
806
+ return yScale
807
+ })
808
+ )
809
+ }
810
+
811
+ export const ordinalPaddingObservable = ({ ordinalScaleDomain$, computedData$, containerSize$ }: {
812
+ // fullDataFormatter$: Observable<DataFormatterMultivariate>
813
+ ordinalScaleDomain$: Observable<[number, number]>
814
+ computedData$: Observable<ComputedData<'multivariate'>>
815
+ containerSize$: Observable<ContainerSize>
816
+ }) => {
817
+ return combineLatest({
818
+ ordinalScaleDomain: ordinalScaleDomain$,
819
+ containerSize: containerSize$,
820
+ computedData: computedData$
821
+ }).pipe(
822
+ debounceTime(0),
823
+ map(data => {
824
+ let maxValue: number = data.computedData[0] && data.computedData[0][0] && data.computedData[0][0].multivariate.length
825
+ ? data.computedData[0][0].multivariate.length - 1
826
+ : 0
827
+ let minValue: number = 0
828
+
829
+ let axisWidth = data.containerSize.width
830
+ // const scaleDomain: [number, number] = [
831
+ // data.fullDataFormatter.xAxis.scaleDomain[0] === 'auto' || data.fullDataFormatter.xAxis.scaleDomain[0] === 'min'
832
+ // ? 0
833
+ // : data.fullDataFormatter.xAxis.scaleDomain[0] as number,
834
+ // data.fullDataFormatter.xAxis.scaleDomain[1] === 'auto' || data.fullDataFormatter.xAxis.scaleDomain[1] === 'max'
835
+ // ? maxValue
836
+ // : data.fullDataFormatter.xAxis.scaleDomain[1] as number
837
+ // ]
838
+ const distance = data.ordinalScaleDomain[1] - data.ordinalScaleDomain[0]
839
+ // console.log('distance', distance)
840
+ if (distance >= 1) {
841
+ return axisWidth / (distance + 1) / 2
842
+ } else {
843
+ return 0
844
+ }
845
+ })
846
+ )
847
+ }
848
+
849
+ // 定性的 X 軸圖軸 - 用 value 的 index 計算
850
+ export const ordinalScaleObservable = ({ ordinalScaleDomain$, computedData$, containerSize$, ordinalPadding$ }: {
851
+ // fullDataFormatter$: Observable<DataFormatterMultivariate>
852
+ ordinalScaleDomain$: Observable<[number, number]>
853
+ computedData$: Observable<ComputedData<'multivariate'>>
854
+ containerSize$: Observable<ContainerSize>
855
+ ordinalPadding$: Observable<number>
856
+ }) => {
857
+ return combineLatest({
858
+ // fullDataFormatter: fullDataFormatter$,
859
+ ordinalScaleDomain: ordinalScaleDomain$,
860
+ computedData: computedData$,
861
+ containerSize: containerSize$,
862
+ ordinalPadding: ordinalPadding$,
863
+ }).pipe(
864
+ debounceTime(0),
865
+ map(data => {
866
+ let maxValue: number = data.computedData[0] && data.computedData[0][0] && data.computedData[0][0].multivariate.length
867
+ ? data.computedData[0][0].multivariate.length - 1
868
+ : 0
869
+ let minValue: number = 0
870
+ let axisWidth = data.containerSize.width - (data.ordinalPadding * 2)
871
+ // const scaleDomain: [number, number] = [
872
+ // data.fullDataFormatter.xAxis.scaleDomain[0] === 'auto' || data.fullDataFormatter.xAxis.scaleDomain[0] === 'min'
873
+ // ? 0
874
+ // : data.fullDataFormatter.xAxis.scaleDomain[0] as number,
875
+ // data.fullDataFormatter.xAxis.scaleDomain[1] === 'auto' || data.fullDataFormatter.xAxis.scaleDomain[1] === 'max'
876
+ // ? maxValue
877
+ // : data.fullDataFormatter.xAxis.scaleDomain[1] as number
878
+ // ]
879
+ // const distance = scaleDomain[1] - scaleDomain[0]
880
+ // // console.log('distance', distance)
881
+ // if (distance >= 1) {
882
+ // axisWidth = axisWidth - (axisWidth / (distance + 1))
883
+ // }
884
+
885
+ const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
886
+ maxValue,
887
+ minValue,
888
+ axisWidth,
889
+ scaleDomain: data.ordinalScaleDomain,
890
+ scaleRange: [0, 1],
891
+ })
892
+
893
+ // const xScale = createLabelToAxisScale({
894
+ // axisLabels: new Array(maxValue + 1).fill('').map((d, i) => String(i)),
895
+ // axisWidth: data.containerSize.width,
896
+ // padding: 0.5
897
+ // })
898
+ return xScale
899
+ })
900
+ )
901
+ }