@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,412 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ switchMap,
6
+ debounceTime,
7
+ takeUntil,
8
+ shareReplay,
9
+ distinctUntilChanged,
10
+ Observable,
11
+ Subject } from 'rxjs'
12
+ import type { BaseLayerFn } from '../types/BaseLayer'
13
+ import type { Layout, GraphicStyles, ContainerPositionScaled, XYAxis } from '../types/PluginParams'
14
+ import type { ComputedData, ComputedDatumMultivariate } from '../types/ComputedData'
15
+ import type { BaseXAxisParams } from './types'
16
+ import { createClassName, getColor, getColorScheme } from '../utils/orbchartsUtils'
17
+ import { measureTextWidth } from '../utils/commonUtils'
18
+ import { ColorType, Theme } from '@orbcharts/core'
19
+ import { ContainerSize, Placement } from '../types'
20
+ import { multivariateContainerSelectionsObservable } from '../utils/multivariateObservables'
21
+ import { parseTickFormatValue } from '../utils/d3Utils'
22
+
23
+ interface BaseXAxisContext {
24
+ selection: d3.Selection<any, unknown, any, unknown>
25
+ pluginName: string
26
+ layerName: string
27
+ position$: Observable<'top' | 'bottom'>
28
+ transitionDuration$: Observable<number>
29
+ computedData$: Observable<ComputedData<'multivariate'>>
30
+ // filteredMinMaxValue$: Observable<[number, number]>
31
+ layerParams$: Observable<BaseXAxisParams>
32
+ xAxis$: Observable<XYAxis>
33
+ theme$: Observable<Theme>
34
+ isSeriesSeprate$: Observable<boolean>
35
+ containerPosition$: Observable<ContainerPositionScaled[]>
36
+ // layout$: Observable<Layout>
37
+ containerSize$: Observable<ContainerSize>
38
+ xScale$: Observable<d3.ScaleLinear<number, number>>
39
+ // filteredXYMinMaxData$: Observable<{
40
+ // datumList: ComputedXYDatumMultivariate[];
41
+ // minXDatum: ComputedXYDatumMultivariate | null;
42
+ // maxXDatum: ComputedXYDatumMultivariate | null;
43
+ // minYDatum: ComputedXYDatumMultivariate | null;
44
+ // maxYDatum: ComputedXYDatumMultivariate | null;
45
+ // }>
46
+ // xyMinMax$: Observable<{
47
+ // minX: number;
48
+ // maxX: number;
49
+ // minY: number;
50
+ // maxY: number;
51
+ // }>
52
+ }
53
+
54
+ const defaultTickSize = 6
55
+
56
+ const xTickTextAnchor = 'middle'
57
+ const xTickDominantBaseline = 'hanging'
58
+ const xAxisLabelAnchor = 'start'
59
+ const xAxisLabelDominantBaseline = 'hanging'
60
+
61
+ function renderXAxisLabel ({ selection, position, xLabelClassName, layerParams, containerSize, xAxis, theme }: {
62
+ selection: d3.Selection<SVGGElement, any, any, any>,
63
+ position: 'top' | 'bottom'
64
+ xLabelClassName: string
65
+ layerParams: BaseXAxisParams
66
+ // axisLabelAlign: TextAlign
67
+ containerSize: ContainerSize
68
+ xAxis: XYAxis
69
+ theme: Theme
70
+ // textReverseTransform: string,
71
+ }) {
72
+ const offsetX = layerParams.tickPadding + layerParams.labelOffset[0]
73
+ // const offsetY = layerParams.tickPadding + layerParams.labelOffset[1]
74
+ let labelX = offsetX
75
+
76
+
77
+ let y: number // = position === 'top' ? 0 : layout.height
78
+ let offsetY
79
+ if (position === 'top') {
80
+ y = 0
81
+ offsetY = -layerParams.tickPadding - layerParams.labelOffset[1]
82
+ } else {
83
+ y = containerSize.height
84
+ offsetY = layerParams.tickPadding + layerParams.labelOffset[1]
85
+ }
86
+
87
+ let labelY = offsetY
88
+
89
+ const axisLabelSelection = selection
90
+ .selectAll<SVGGElement, BaseXAxisParams>(`g.${xLabelClassName}`)
91
+ .data([layerParams])
92
+ .join('g')
93
+ .classed(xLabelClassName, true)
94
+ .each((d, i, g) => {
95
+ const text = d3.select(g[i])
96
+ .selectAll<SVGTextElement, BaseXAxisParams>(`text`)
97
+ .data([d])
98
+ .join(
99
+ enter => {
100
+ return enter
101
+ .append('text')
102
+ .style('font-weight', 'bold')
103
+ },
104
+ update => update,
105
+ exit => exit.remove()
106
+ )
107
+ .attr('text-anchor', xAxisLabelAnchor)
108
+ .attr('dominant-baseline', xAxisLabelDominantBaseline)
109
+ .attr('font-size', theme.fontSize)
110
+ .style('fill', getColor(layerParams.labelColorType, theme))
111
+ // .style('transform', textReverseTransform)
112
+ // 偏移使用 x, y 而非 transform 才不會受到外層 scale 變形影響
113
+ .attr('x', labelX)
114
+ .attr('y', labelY)
115
+ .text(d => xAxis.label)
116
+ })
117
+ .attr('transform', d => `translate(${containerSize.width}, ${y})`)
118
+ }
119
+
120
+ function renderXAxis ({ selection, position, xAxisClassName, layerParams, containerSize, theme, xScale, transitionDuration }: {
121
+ selection: d3.Selection<SVGGElement, any, any, any>,
122
+ position: 'top' | 'bottom'
123
+ xAxisClassName: string
124
+ layerParams: BaseXAxisParams
125
+ // tickTextAlign: TextAlign
126
+ containerSize: ContainerSize
127
+ // fullDataFormatter: DataFormatterMultivariate,
128
+ theme: Theme,
129
+ xScale: d3.ScaleLinear<number, number>
130
+ // textReverseTransform: string,
131
+ // xyMinMax: {
132
+ // minX: number;
133
+ // maxX: number;
134
+ // minY: number;
135
+ // maxY: number;
136
+ // }
137
+ transitionDuration: number
138
+ }) {
139
+
140
+ let y: number
141
+ let d3Axis: d3.Axis<d3.NumberValue>
142
+ if (position === 'top') {
143
+ y = 0
144
+ d3Axis = d3.axisTop(xScale)
145
+ } else {
146
+ y = containerSize.height
147
+ d3Axis = d3.axisBottom(xScale)
148
+ }
149
+
150
+ const xAxisSelection = selection
151
+ .selectAll<SVGGElement, BaseXAxisParams>(`g.${xAxisClassName}`)
152
+ .data([layerParams])
153
+ .join('g')
154
+ .classed(xAxisClassName, true)
155
+ .attr('transform', `translate(0, ${y})`)
156
+
157
+ // const _xScale = d3.scaleLinear()
158
+ // .domain([0, 150])
159
+ // .range([416.5, 791.349])
160
+
161
+ // 刻度文字偏移
162
+ let tickPadding = layerParams.tickPadding
163
+
164
+ // 設定Y軸刻度
165
+ const xAxis = d3Axis
166
+ .scale(xScale)
167
+ .ticks(layerParams.ticks) // 刻度分段數量
168
+ .tickFormat(d => parseTickFormatValue(d, layerParams.tickFormat))
169
+ .tickSize(layerParams.tickFullLine == true
170
+ ? -containerSize.height
171
+ : defaultTickSize)
172
+ .tickSizeOuter(-containerSize.height)
173
+ .tickPadding(tickPadding)
174
+
175
+ const xAxisEl = xAxisSelection
176
+ .transition()
177
+ .duration(transitionDuration)
178
+ .ease(d3.easeLinear) // 線性的 - 當托曳或快速變動的時候比較滑順
179
+ .call(xAxis)
180
+
181
+ xAxisEl.selectAll('line')
182
+ .style('fill', 'none')
183
+ .style('stroke', layerParams.tickLineVisible == true ? getColor(layerParams.tickColorType, theme) : 'none')
184
+ .style('stroke-dasharray', layerParams.tickFullLineDasharray)
185
+ .attr('pointer-events', 'none')
186
+
187
+ xAxisEl.selectAll('path')
188
+ .style('fill', 'none')
189
+ // .style('stroke', this.layerParams.axisLineColor!)
190
+ .style('stroke', layerParams.axisLineVisible == true ? getColor(layerParams.axisLineColorType, theme) : 'none')
191
+ .style('shape-rendering', 'crispEdges')
192
+
193
+ // const xText = xAxisEl.selectAll('text')
194
+ const xText = xAxisSelection.selectAll('text')
195
+ // .style('font-family', 'sans-serif')
196
+ .attr('font-size', theme.fontSize)
197
+ .style('color', getColor(layerParams.tickTextColorType, theme))
198
+ .attr('text-anchor', xTickTextAnchor)
199
+ .attr('dominant-baseline', xTickDominantBaseline)
200
+ // .attr('dy', tickPadding)
201
+ // .attr('y', tickPadding)
202
+ // xText.style('transform', textReverseTransform)
203
+
204
+ // // 抵消掉預設的偏移
205
+ // if (fullDataFormatter.grid.valueAxis.position === 'bottom' || fullDataFormatter.grid.valueAxis.position === 'top') {
206
+ xText.attr('dy', 0)
207
+ // }
208
+
209
+ return xAxisSelection
210
+ }
211
+
212
+
213
+ export const createBaseXAxis: BaseLayerFn<BaseXAxisContext> = ({
214
+ selection,
215
+ pluginName,
216
+ layerName,
217
+ position$,
218
+ computedData$,
219
+ layerParams$,
220
+ xAxis$,
221
+ theme$,
222
+ isSeriesSeprate$,
223
+ containerPosition$,
224
+ // layout$,
225
+ containerSize$,
226
+ xScale$,
227
+ // filteredXYMinMaxData$,
228
+ // xyMinMax$
229
+ transitionDuration$
230
+ }) => {
231
+
232
+ const destroy$ = new Subject()
233
+
234
+ // const containerClassName = createClassName(pluginName, 'container')
235
+ const xAxisGClassName = createClassName(pluginName, layerName, 'xAxisG')
236
+ const xAxisClassName = createClassName(pluginName, layerName, 'xAxis')
237
+ const xLabelClassName = createClassName(pluginName, layerName, 'xLabel')
238
+
239
+ const containerSelection$ = multivariateContainerSelectionsObservable({
240
+ selection,
241
+ pluginName,
242
+ layerName,
243
+ clipPathID: null,
244
+ computedData$,
245
+ containerPosition$,
246
+ isSeriesSeprate$,
247
+ }).pipe(
248
+ takeUntil(destroy$),
249
+ )
250
+
251
+ // const containerSelection$ = combineLatest({
252
+ // computedData: computedData$.pipe(
253
+ // distinctUntilChanged((a, b) => {
254
+ // // 只有當series的數量改變時,才重新計算
255
+ // return a.length === b.length
256
+ // }),
257
+ // ),
258
+ // isSeriesSeprate: isSeriesSeprate$
259
+ // }).pipe(
260
+ // takeUntil(destroy$),
261
+ // switchMap(async (d) => d),
262
+ // map(data => {
263
+ // return data.isSeriesSeprate
264
+ // // category分開的時候顯示各別axis
265
+ // ? data.computedData
266
+ // // category合併的時候只顯示第一個axis
267
+ // : [data.computedData[0]]
268
+ // }),
269
+ // map((computedData, i) => {
270
+ // return selection
271
+ // .selectAll<SVGGElement, ComputedDatumMultivariate[]>(`g.${containerClassName}`)
272
+ // .data(computedData, d => d[0] ? d[0].categoryIndex : i)
273
+ // .join('g')
274
+ // .classed(containerClassName, true)
275
+ // })
276
+ // )
277
+
278
+ const axisSelection$ = containerSelection$.pipe(
279
+ takeUntil(destroy$),
280
+ map((containerSelection, i) => {
281
+ return containerSelection
282
+ .selectAll<SVGGElement, ComputedDatumMultivariate[]>(`g.${xAxisGClassName}`)
283
+ .data([xAxisGClassName])
284
+ .join('g')
285
+ .classed(xAxisGClassName, true)
286
+ })
287
+ )
288
+
289
+ // combineLatest({
290
+ // containerSelection: containerSelection$,
291
+ // gridContainerPosition: containerPosition$
292
+ // }).pipe(
293
+ // takeUntil(destroy$),
294
+ // switchMap(async d => d)
295
+ // ).subscribe(data => {
296
+ // data.containerSelection
297
+ // .attr('transform', (d, i) => {
298
+ // const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
299
+ // const translate = gridContainerPosition.translate
300
+ // const scale = gridContainerPosition.scale
301
+ // // return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
302
+ // return `translate(${translate[0]}, ${translate[1]})`
303
+ // })
304
+ // // .attr('opacity', 0)
305
+ // // .transition()
306
+ // // .attr('opacity', 1)
307
+ // })
308
+
309
+ // const textReverseTransform$ = containerPosition$.pipe(
310
+ // takeUntil(destroy$),
311
+ // switchMap(async (d) => d),
312
+ // map(containerPosition => {
313
+ // // const axesRotateXYReverseValue = `rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
314
+ // // const axesRotateReverseValue = `rotate(${data.gridAxesReverseTransform.rotate}deg)`
315
+ // const containerScaleReverseValue = `scale(${1 / containerPosition[0].scale[0]}, ${1 / containerPosition[0].scale[1]})`
316
+ // // 抵消最外層scale
317
+ // return `${containerScaleReverseValue}`
318
+ // }),
319
+ // distinctUntilChanged()
320
+ // )
321
+
322
+ // const xScale$: Observable<d3.ScaleLinear<number, number>> = new Observable(subscriber => {
323
+ // combineLatest({
324
+ // fullDataFormatter: fullDataFormatter$,
325
+ // layout: layout$,
326
+ // // xyMinMax: xyMinMax$
327
+ // filteredXYMinMaxData: filteredXYMinMaxData$
328
+ // }).pipe(
329
+ // takeUntil(destroy$),
330
+ // switchMap(async (d) => d),
331
+ // ).subscribe(data => {
332
+ // const valueIndex = data.fullDataFormatter.xAxis.valueIndex
333
+ // if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
334
+ // || data.filteredXYMinMaxData.minXDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxXDatum.value[valueIndex] == null
335
+ // ) {
336
+ // return
337
+ // }
338
+ // let maxValue = data.filteredXYMinMaxData.maxXDatum.value[valueIndex]
339
+ // let minValue = data.filteredXYMinMaxData.minXDatum.value[valueIndex]
340
+ // if (maxValue === minValue && maxValue === 0) {
341
+ // // 避免最大及最小值同等於 0 造成無法計算scale
342
+ // maxValue = 1
343
+ // }
344
+
345
+ // const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
346
+ // maxValue,
347
+ // minValue,
348
+ // axisWidth: data.layout.width,
349
+ // scaleDomain: data.fullDataFormatter.xAxis.scaleDomain,
350
+ // scaleRange: data.fullDataFormatter.xAxis.scaleRange,
351
+ // })
352
+
353
+ // subscriber.next(xScale)
354
+ // })
355
+ // })
356
+
357
+ combineLatest({
358
+ axisSelection: axisSelection$,
359
+ position: position$,
360
+ layerParams: layerParams$,
361
+ // tickTextAlign: tickTextAlign$,
362
+ // axisLabelAlign: axisLabelAlign$,
363
+ computedData: computedData$,
364
+ // layout: layout$,
365
+ containerSize: containerSize$,
366
+ xAxis: xAxis$,
367
+ theme: theme$,
368
+ xScale: xScale$,
369
+ // textReverseTransform: textReverseTransform$,
370
+ // xyMinMax: xyMinMax$
371
+ transitionDuration: transitionDuration$
372
+ }).pipe(
373
+ takeUntil(destroy$),
374
+ switchMap(async (d) => d),
375
+ ).subscribe(data => {
376
+ // console.log('data.layout', data.layout)
377
+ // console.log('data.containerSize', data.containerSize)
378
+
379
+ renderXAxis({
380
+ selection: data.axisSelection,
381
+ position: data.position,
382
+ xAxisClassName,
383
+ layerParams: data.layerParams,
384
+ // tickTextAlign: data.tickTextAlign,
385
+ theme: data.theme,
386
+ containerSize: data.containerSize,
387
+ // fullDataFormatter: data.fullDataFormatter,
388
+
389
+ xScale: data.xScale,
390
+ // textReverseTransform: data.textReverseTransform,
391
+ // xyMinMax: data.xyMinMax
392
+ transitionDuration: data.transitionDuration
393
+ })
394
+
395
+ renderXAxisLabel({
396
+ selection: data.axisSelection,
397
+ position: data.position,
398
+ xLabelClassName,
399
+ layerParams: data.layerParams,
400
+ // axisLabelAlign: data.axisLabelAlign,
401
+ containerSize: data.containerSize,
402
+ xAxis: data.xAxis,
403
+ theme: data.theme,
404
+ // textReverseTransform: data.textReverseTransform,
405
+ })
406
+
407
+ })
408
+
409
+ return () => {
410
+ destroy$.next(undefined)
411
+ }
412
+ }
@@ -0,0 +1,250 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ switchMap,
6
+ debounceTime,
7
+ takeUntil,
8
+ shareReplay,
9
+ distinctUntilChanged,
10
+ Observable,
11
+ Subject } from 'rxjs'
12
+ import type { BaseLayerFn } from '../types/BaseLayer'
13
+ import type { Layout, GraphicStyles, ContainerPositionScaled, XYAxis } from '../types/PluginParams'
14
+ import { ColorType, EventData, Theme } from '@orbcharts/core'
15
+ import { createValueToAxisScale } from '../utils/d3Scale'
16
+
17
+ interface BaseXZoomContext {
18
+ rootSelection: d3.Selection<any, unknown, any, unknown>
19
+ pluginName: string
20
+ layerName: string
21
+ initXAxis$: Observable<XYAxis>
22
+ initYAxis$: Observable<XYAxis>
23
+ xyMinMax$: Observable<{
24
+ minX: number;
25
+ maxX: number;
26
+ minY: number;
27
+ maxY: number;
28
+ }>
29
+ layout$: Observable<Layout>
30
+ eventTrigger$: Subject<EventData>
31
+ }
32
+
33
+ export const createBaseXZoom: BaseLayerFn<BaseXZoomContext> = ({
34
+ rootSelection,
35
+ pluginName,
36
+ layerName,
37
+ initXAxis$,
38
+ initYAxis$,
39
+ xyMinMax$,
40
+ layout$,
41
+ eventTrigger$
42
+ }) => {
43
+
44
+ const destroy$ = new Subject()
45
+
46
+ // 紀錄zoom最後一次的transform
47
+ let lastTransform = {
48
+ k: 1,
49
+ x: 0,
50
+ y: 0
51
+ }
52
+
53
+ // const initXAxis$ = fullDataFormatter$.pipe(
54
+ // map(d => d.xAxis),
55
+ // // 只用第一次資料來計算scale才不會造成每次變動都受到影響
56
+ // first()
57
+ // )
58
+
59
+ // const initYAxis$ = fullDataFormatter$.pipe(
60
+ // map(d => d.yAxis),
61
+ // // 只用第一次資料來計算scale才不會造成每次變動都受到影響
62
+ // first()
63
+ // )
64
+
65
+ const initXScale$: Observable<d3.ScaleLinear<number, number>> = new Observable(subscriber => {
66
+ combineLatest({
67
+ initXAxis: initXAxis$,
68
+ layout: layout$,
69
+ xyMinMax: xyMinMax$
70
+ }).pipe(
71
+ takeUntil(destroy$),
72
+ debounceTime(0),
73
+ ).subscribe(data => {
74
+
75
+ const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
76
+ maxValue: data.xyMinMax.maxX,
77
+ minValue: data.xyMinMax.minX,
78
+ axisWidth: data.layout.width,
79
+ scaleDomain: data.initXAxis.scaleDomain,
80
+ scaleRange: data.initXAxis.scaleRange,
81
+ })
82
+
83
+ subscriber.next(xScale)
84
+ })
85
+ })
86
+
87
+ // const initYScale$: Observable<d3.ScaleLinear<number, number>> = new Observable(subscriber => {
88
+ // combineLatest({
89
+ // initYAxis: initYAxis$,
90
+ // layout: observer.layout$,
91
+ // xyMinMax: observer.xyMinMax$
92
+ // }).pipe(
93
+ // takeUntil(destroy$),
94
+ // debounceTime(0),
95
+ // ).subscribe(data => {
96
+
97
+ // const yScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
98
+ // maxValue: data.xyMinMax.maxY,
99
+ // minValue: data.xyMinMax.minY,
100
+ // axisWidth: data.layout.height,
101
+ // scaleDomain: data.initYAxis.scaleDomain,
102
+ // scaleRange: data.initYAxis.scaleRange,
103
+ // reverse: true
104
+ // })
105
+
106
+ // subscriber.next(yScale)
107
+ // })
108
+ // })
109
+
110
+ const minMaxScaleDomain$ = combineLatest({
111
+ initXAxis: initXAxis$,
112
+ initYAxis: initYAxis$,
113
+ xyMinMax: xyMinMax$
114
+ }).pipe(
115
+ takeUntil(destroy$),
116
+ debounceTime(0),
117
+ map(data => {
118
+ let minX = data.xyMinMax.minX
119
+ let maxX = data.xyMinMax.maxX
120
+ let minY = data.xyMinMax.minY
121
+ let maxY = data.xyMinMax.maxY
122
+
123
+ // 原始設定為auto時要額外判斷
124
+ if (data.initXAxis.scaleDomain[0] === 'auto' && minX > 0) {
125
+ minX = 0
126
+ }
127
+ if (data.initXAxis.scaleDomain[1] === 'auto' && maxX < 0) {
128
+ maxX = 0
129
+ }
130
+ if (data.initYAxis.scaleDomain[0] === 'auto' && minY > 0) {
131
+ minY = 0
132
+ }
133
+ if (data.initYAxis.scaleDomain[1] === 'auto' && maxY < 0) {
134
+ maxY = 0
135
+ }
136
+
137
+ return {
138
+ minX,
139
+ maxX,
140
+ minY,
141
+ maxY
142
+ }
143
+ }),
144
+ )
145
+
146
+ combineLatest({
147
+ initXScale: initXScale$,
148
+ // fullDataFormatter: fullDataFormatter$,
149
+ minMaxScaleDomain: minMaxScaleDomain$,
150
+ }).pipe(
151
+ takeUntil(destroy$),
152
+ debounceTime(0),
153
+ ).subscribe(data => {
154
+ // const groupMin = 0
155
+
156
+ const shadowScale = data.initXScale.copy()
157
+
158
+ const zoom = d3.zoom()
159
+ // .scaleExtent([1, data.groupMaxIndex])
160
+ // .translateExtent([[0, 0], [data.layout.rootWidth, data.layout.rootWidth]])
161
+ .on("zoom", function zoomed(event) {
162
+ // debugger
163
+ // console.log('event', event)
164
+ const t = event.transform;
165
+
166
+ // if (event.sourceEvent.type === 'mousemove') {
167
+ // // 當進行平移時,反向計算 x 軸
168
+ // const dx = event.transform.x - currentTransform.x; // 本次平移增量
169
+ // const reversedX = currentTransform.x - dx; // 反向累積平移
170
+ // // 更新變換狀態
171
+ // currentTransform = d3.zoomIdentity
172
+ // .translate(reversedX, event.transform.y)
173
+ // .scale(event.transform.k);
174
+ // } else {
175
+ // // 縮放操作:只更新縮放比例
176
+ // currentTransform = d3.zoomIdentity
177
+ // .translate(currentTransform.x, currentTransform.y)
178
+ // .scale(event.transform.k);
179
+ // }
180
+ // console.log('currentTransform', currentTransform)
181
+
182
+ // console.log('t.x', t.x)
183
+ const mapGroupindex = (d: number) => {
184
+ const n = Math.round(d)
185
+ return Math.min(data.minMaxScaleDomain.maxX, Math.max(data.minMaxScaleDomain.minX, n));
186
+ }
187
+
188
+ const zoomedDomain = t.rescaleX(shadowScale)
189
+ .domain()
190
+ .map(mapGroupindex)
191
+
192
+
193
+ // domain超過極限值
194
+ if (zoomedDomain[0] <= data.minMaxScaleDomain.minX && zoomedDomain[1] >= data.minMaxScaleDomain.maxX) {
195
+ // 繼續縮小
196
+ if (t.k < lastTransform.k) {
197
+ // 維持前一次的transform
198
+ t.k = lastTransform.k
199
+ t.x = lastTransform.x
200
+ t.y = lastTransform.y
201
+ }
202
+ // domain間距小於1
203
+ } else if ((zoomedDomain[1] - zoomedDomain[0]) <= 1) {
204
+ // 繼續放大
205
+ if (t.k > lastTransform.k) {
206
+ // 維持前一次的transform
207
+ t.k = lastTransform.k
208
+ t.x = lastTransform.x
209
+ t.y = lastTransform.y
210
+ }
211
+ }
212
+
213
+ // 紀錄transform
214
+ lastTransform.k = t.k
215
+ lastTransform.x = t.x
216
+ lastTransform.y = t.y
217
+
218
+ // console.log(zoomedDomain)
219
+ // const newDataFormatter: DataFormatterMultiValue = {
220
+ // ...data.fullDataFormatter,
221
+ // xAxis: {
222
+ // ...data.fullDataFormatter.xAxis,
223
+ // scaleDomain: zoomedDomain
224
+ // }
225
+ // }
226
+ // dataFormatter$.next(newDataFormatter)
227
+ eventTrigger$.next({
228
+ eventName: 'zoom',
229
+ pluginName,
230
+ layerName,
231
+ target: null,
232
+ data: {
233
+ scaleDomain: zoomedDomain
234
+ }
235
+ })
236
+ })
237
+
238
+ // 傳入外層selection
239
+ // subject.selection.call(zoom as any)
240
+ rootSelection.call(zoom)
241
+
242
+ })
243
+
244
+ return () => {
245
+ destroy$.next(undefined)
246
+ // rootRectSelection.remove()
247
+
248
+ rootSelection.call(d3.zoom().on('zoom', null))
249
+ }
250
+ }