@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,612 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ debounceTime,
5
+ switchMap,
6
+ distinctUntilChanged,
7
+ first,
8
+ map,
9
+ takeUntil,
10
+ Observable,
11
+ Subject } from 'rxjs'
12
+ import type { ColorType, Theme } from '@orbcharts/core'
13
+ import type { BaseLayerFn } from '../types/BaseLayer'
14
+ import type {
15
+ CategoryAxis,
16
+ ValueAxis,
17
+ ComputedDatumGrid,
18
+ ContainerPositionScaled,
19
+ ContainerSize,
20
+ TransformData,
21
+ ComputedData,
22
+ GraphicStyles
23
+ } from '../types'
24
+ import { createValueToAxisScale } from '../utils/d3Scale'
25
+ import { parseTickFormatValue } from '../utils/d3Utils'
26
+ import { getColor, getMinMaxValue, createClassName } from '../utils/orbchartsUtils'
27
+ import { gridContainerSelectionsObservable } from '../utils/gridObservables'
28
+
29
+ export interface BaseValueAxisParams {
30
+ labelOffset: [number, number];
31
+ labelColorType: ColorType;
32
+ axisLineVisible: boolean;
33
+ axisLineColorType: ColorType;
34
+ ticks: number;
35
+ tickFormat: string | ((text: d3.NumberValue) => string | d3.NumberValue);
36
+ tickLineVisible: boolean;
37
+ tickPadding: number;
38
+ tickFullLine: boolean;
39
+ tickFullLineDasharray: string;
40
+ tickColorType: ColorType;
41
+ tickTextRotate: number;
42
+ tickTextColorType: ColorType;
43
+ }
44
+
45
+ interface BaseValueAxisContext {
46
+ selection: d3.Selection<any, unknown, any, unknown>
47
+ pluginName: string
48
+ layerName: string
49
+ computedData$: Observable<ComputedData<'grid'>>
50
+ filteredMinMaxValue$: Observable<[number, number]>
51
+ baseValueAxisParams$: Observable<BaseValueAxisParams>
52
+ categoryAxis$: Observable<CategoryAxis>
53
+ valueAxis$: Observable<ValueAxis>
54
+ theme$: Observable<Theme>
55
+ gridAxesTransform$: Observable<TransformData>
56
+ gridAxesReverseTransform$: Observable<TransformData>
57
+ // gridAxesSize$: Observable<{
58
+ // width: number;
59
+ // height: number;
60
+ // }>
61
+ gridContainerPosition$: Observable<ContainerPositionScaled[]>
62
+ gridAxesSize$: Observable<ContainerSize>
63
+ // gridAxesContainerSize$: Observable<ContainerSize>
64
+ isSeriesSeprate$: Observable<boolean>
65
+ }
66
+
67
+ interface TextAlign {
68
+ textAnchor: "start" | "middle" | "end"
69
+ dominantBaseline: "middle" | "auto" | "hanging"
70
+ }
71
+
72
+ // const pluginName = 'ValueAxis'
73
+ // const containerClassName = createClassName(pluginName, 'container')
74
+ // const yAxisGClassName = createClassName(pluginName, 'yAxisG')
75
+ // const yAxisClassName = createClassName(pluginName, 'yAxis')
76
+ // const textClassName = createClassName(pluginName, 'text')
77
+ const defaultTickSize = 6
78
+
79
+ function renderAxisLabel ({ selection, textClassName, baseValueAxisParams, axisLabelAlign, gridAxesSize, categoryAxis, valueAxis, theme, textReverseTransform }: {
80
+ selection: d3.Selection<SVGGElement, any, any, any>,
81
+ textClassName: string
82
+ baseValueAxisParams: BaseValueAxisParams
83
+ axisLabelAlign: TextAlign
84
+ gridAxesSize: ContainerSize
85
+ categoryAxis: CategoryAxis
86
+ valueAxis: ValueAxis
87
+ theme: Theme
88
+ textReverseTransform: string,
89
+ }) {
90
+ const offsetX = baseValueAxisParams.tickPadding - baseValueAxisParams.labelOffset[0]
91
+ const offsetY = baseValueAxisParams.tickPadding + baseValueAxisParams.labelOffset[1]
92
+ let labelX = 0
93
+ let labelY = 0
94
+ if (categoryAxis.position === 'bottom') {
95
+ // labelY = - gridAxesSize.height - offsetY
96
+ labelY = - offsetY
97
+ if (valueAxis.position === 'left') {
98
+ labelX = - offsetX
99
+ } else if (valueAxis.position === 'right') {
100
+ labelX = offsetX
101
+ }
102
+ } else if (categoryAxis.position === 'top') {
103
+ // labelY = gridAxesSize.height + offsetY
104
+ labelY = offsetY
105
+ if (valueAxis.position === 'left') {
106
+ labelX = - offsetX
107
+ } else if (valueAxis.position === 'right') {
108
+ labelX = offsetX
109
+ }
110
+ } else if (categoryAxis.position === 'left') {
111
+ // labelX = gridAxesSize.width + offsetX
112
+ labelX = offsetX
113
+ if (valueAxis.position === 'bottom') {
114
+ labelY = offsetY
115
+ } else if (valueAxis.position === 'top') {
116
+ labelY = - offsetY
117
+ }
118
+ } else if (categoryAxis.position === 'right') {
119
+ labelX = - offsetX
120
+ if (valueAxis.position === 'bottom') {
121
+ labelY = offsetY
122
+ } else if (valueAxis.position === 'top') {
123
+ labelY = - offsetY
124
+ }
125
+ }
126
+
127
+ const axisLabelSelection = selection
128
+ .selectAll<SVGGElement, BaseValueAxisParams>(`g.${textClassName}`)
129
+ .data([baseValueAxisParams])
130
+ .join('g')
131
+ .classed(textClassName, true)
132
+ .each((d, i, g) => {
133
+ const text = d3.select(g[i])
134
+ .selectAll<SVGTextElement, BaseValueAxisParams>(`text`)
135
+ .data([d])
136
+ .join(
137
+ enter => {
138
+ return enter
139
+ .append('text')
140
+ .style('font-weight', 'bold')
141
+ },
142
+ update => update,
143
+ exit => exit.remove()
144
+ )
145
+ .attr('text-anchor', axisLabelAlign.textAnchor)
146
+ .attr('dominant-baseline', axisLabelAlign.dominantBaseline)
147
+ .attr('font-size', theme.fontSize)
148
+ .style('fill', getColor(baseValueAxisParams.labelColorType, theme))
149
+ .style('transform', textReverseTransform)
150
+ // 偏移使用 x, y 而非 transform 才不會受到外層 scale 變形影響
151
+ .attr('x', labelX)
152
+ .attr('y', labelY)
153
+ .text(d => valueAxis.label)
154
+ })
155
+ .attr('transform', d => `translate(0, ${gridAxesSize.height})`)
156
+ // .attr('transform', d => `translate(${- baseValueAxisParams.tickPadding + baseValueAxisParams.labelOffset[0]}, ${gridAxesSize.height + baseValueAxisParams.tickPadding + baseValueAxisParams.labelOffset[1]})`)
157
+
158
+
159
+ }
160
+
161
+ function renderAxis ({ selection, yAxisClassName, baseValueAxisParams, tickTextAlign, gridAxesSize, valueAxis, valueScale, textReverseTransformWithRotate, theme }: {
162
+ selection: d3.Selection<SVGGElement, any, any, any>,
163
+ yAxisClassName: string
164
+ baseValueAxisParams: BaseValueAxisParams
165
+ tickTextAlign: TextAlign
166
+ gridAxesSize: ContainerSize
167
+ valueAxis: ValueAxis
168
+ valueScale: d3.ScaleLinear<number, number>
169
+ textReverseTransformWithRotate: string,
170
+ theme: Theme
171
+ }) {
172
+
173
+ const yAxisSelection = selection
174
+ .selectAll<SVGGElement, BaseValueAxisParams>(`g.${yAxisClassName}`)
175
+ .data([baseValueAxisParams])
176
+ .join('g')
177
+ .classed(yAxisClassName, true)
178
+
179
+ // const _valueScale = d3.scaleLinear()
180
+ // .domain([0, 150])
181
+ // .range([416.5, 791.349])
182
+
183
+ // 刻度文字偏移
184
+ let tickPadding = 0
185
+ let textY = 0
186
+ if (valueAxis.position === 'left') {
187
+ tickPadding = baseValueAxisParams.tickPadding
188
+ textY = 0
189
+ } else if (valueAxis.position === 'right') {
190
+ tickPadding = - baseValueAxisParams.tickPadding
191
+ textY = 0
192
+ } else if (valueAxis.position === 'bottom') {
193
+ tickPadding = 0
194
+ textY = baseValueAxisParams.tickPadding
195
+ } else if (valueAxis.position === 'top') {
196
+ tickPadding = 0
197
+ textY = - baseValueAxisParams.tickPadding
198
+ }
199
+
200
+ // 設定Y軸刻度
201
+ const yAxis = d3.axisLeft(valueScale)
202
+ .scale(valueScale)
203
+ .ticks(baseValueAxisParams.ticks) // 刻度分段數量
204
+ .tickFormat(d => parseTickFormatValue(d, baseValueAxisParams.tickFormat))
205
+ .tickSize(baseValueAxisParams.tickFullLine == true
206
+ ? -gridAxesSize.width
207
+ : defaultTickSize)
208
+ .tickPadding(tickPadding)
209
+
210
+ const yAxisEl = yAxisSelection
211
+ .transition()
212
+ .duration(100)
213
+ .ease(d3.easeLinear) // 線性的 - 當托曳或快速變動的時候比較滑順
214
+ .call(yAxis)
215
+
216
+ yAxisEl.selectAll('line')
217
+ .style('fill', 'none')
218
+ .style('stroke', baseValueAxisParams.tickLineVisible == true ? getColor(baseValueAxisParams.tickColorType, theme) : 'none')
219
+ .style('stroke-dasharray', baseValueAxisParams.tickFullLineDasharray)
220
+ .style('vector-effect', 'non-scaling-stroke') // 避免 scale 導致線條變形
221
+ .attr('pointer-events', 'none')
222
+
223
+ yAxisEl.selectAll('path')
224
+ .style('fill', 'none')
225
+ // .style('stroke', this.baseValueAxisParams.axisLineColor!)
226
+ .style('stroke', baseValueAxisParams.axisLineVisible == true ? getColor(baseValueAxisParams.axisLineColorType, theme) : 'none')
227
+ .style('shape-rendering', 'crispEdges')
228
+
229
+ // const yText = yAxisEl.selectAll('text')
230
+ const yText = yAxisSelection.selectAll('text')
231
+ // .style('font-family', 'sans-serif')
232
+ .attr('font-size', theme.fontSize)
233
+ .style('color', getColor(baseValueAxisParams.tickTextColorType, theme))
234
+ .attr('text-anchor', tickTextAlign.textAnchor)
235
+ .attr('dominant-baseline', tickTextAlign.dominantBaseline)
236
+ // .attr('dy', 0)
237
+ .attr('y', textY)
238
+ .attr('dy', 0)
239
+ yText.style('transform', textReverseTransformWithRotate)
240
+
241
+ // 抵消掉預設的偏移
242
+ if (valueAxis.position === 'bottom' || valueAxis.position === 'top') {
243
+ yText.attr('dy', 0)
244
+ }
245
+
246
+ return yAxisSelection
247
+ }
248
+
249
+
250
+
251
+ export const createBaseValueAxis: BaseLayerFn<BaseValueAxisContext> = ({
252
+ selection,
253
+ pluginName,
254
+ layerName,
255
+ computedData$,
256
+ filteredMinMaxValue$,
257
+ baseValueAxisParams$,
258
+ categoryAxis$,
259
+ valueAxis$,
260
+ theme$,
261
+ gridAxesSize$,
262
+ gridAxesTransform$,
263
+ gridAxesReverseTransform$,
264
+ // gridAxesSize$,
265
+ gridContainerPosition$,
266
+ // gridAxesContainerSize$,
267
+ isSeriesSeprate$,
268
+ }) => {
269
+
270
+ const destroy$ = new Subject()
271
+
272
+ const containerClassName = createClassName(pluginName, layerName, 'container')
273
+ const yAxisGClassName = createClassName(pluginName, layerName, 'yAxisG')
274
+ const yAxisClassName = createClassName(pluginName, layerName, 'yAxis')
275
+ const textClassName = createClassName(pluginName, layerName, 'text')
276
+
277
+ const containerSelection$ = gridContainerSelectionsObservable({
278
+ selection,
279
+ pluginName,
280
+ layerName,
281
+ computedData$,
282
+ gridContainerPosition$,
283
+ isSeriesSeprate$
284
+ })
285
+
286
+ // const containerSelection$ = combineLatest({
287
+ // computedData: computedData$.pipe(
288
+ // distinctUntilChanged((a, b) => {
289
+ // // 只有當series的數量改變時,才重新計算
290
+ // return a.length === b.length
291
+ // }),
292
+ // ),
293
+ // isSeriesSeprate: isSeriesSeprate$
294
+ // }).pipe(
295
+ // takeUntil(destroy$),
296
+ // debounceTime(0),
297
+ // map(data => {
298
+ // return data.isSeriesSeprate
299
+ // // series分開的時候顯示各別axis
300
+ // ? data.computedData
301
+ // // series合併的時候只顯示第一個axis
302
+ // : [data.computedData[0]]
303
+ // }),
304
+ // map((computedData, i) => {
305
+ // return selection
306
+ // .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${containerClassName}`)
307
+ // .data(computedData, d => d[0] ? d[0].seriesIndex : i)
308
+ // .join('g')
309
+ // .classed(containerClassName, true)
310
+ // })
311
+ // )
312
+
313
+ const axisSelection$ = containerSelection$.pipe(
314
+ takeUntil(destroy$),
315
+ map((containerSelection, i) => {
316
+ return containerSelection
317
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${yAxisGClassName}`)
318
+ .data([yAxisGClassName])
319
+ .join('g')
320
+ .classed(yAxisGClassName, true)
321
+ })
322
+ )
323
+
324
+ // combineLatest({
325
+ // containerSelection: containerSelection$,
326
+ // gridContainerPosition: gridContainerPosition$
327
+ // }).pipe(
328
+ // takeUntil(destroy$),
329
+ // debounceTime(0)
330
+ // ).subscribe(data => {
331
+ // data.containerSelection
332
+ // .attr('transform', (d, i) => {
333
+ // const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
334
+ // const translate = gridContainerPosition.translate
335
+ // const scale = gridContainerPosition.scale
336
+ // // return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
337
+ // return `translate(${translate[0]}, ${translate[1]})`
338
+ // })
339
+ // // .attr('opacity', 0)
340
+ // // .transition()
341
+ // // .attr('opacity', 1)
342
+ // })
343
+
344
+ combineLatest({
345
+ axisSelection: axisSelection$,
346
+ gridAxesTransform: gridAxesTransform$,
347
+ }).pipe(
348
+ takeUntil(destroy$),
349
+ debounceTime(0)
350
+ ).subscribe(data => {
351
+ data.axisSelection
352
+ .style('transform', data.gridAxesTransform.value)
353
+ // .attr('opacity', 0)
354
+ // .transition()
355
+ // .attr('opacity', 1)
356
+
357
+ })
358
+
359
+ // const gridAxesSize$ = gridAxisSizeObservable({
360
+ // fullDataFormatter$,
361
+ // layout$
362
+ // })
363
+
364
+ // const textReverseTransform$: Observable<string> = new Observable(subscriber => {
365
+ // combineLatest({
366
+ // baseValueAxisParams: baseValueAxisParams$,
367
+ // layout: layout$
368
+ // }).pipe(
369
+ // takeUntil(destroy$),
370
+ // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
371
+ // debounceTime(0),
372
+ // ).subscribe(data => {
373
+
374
+ // const transformData = Object.assign({}, data.layout.content.axesTransformData)
375
+
376
+ // const value = getAxesTransformValue({
377
+ // translate: [0, 0],
378
+ // scale: [transformData.scale[0] * -1, transformData.scale[1] * -1],
379
+ // rotate: transformData.rotate * -1 + data.baseValueAxisParams.tickTextRotate,
380
+ // rotateX: transformData.rotateX * -1,
381
+ // rotateY: transformData.rotateY * -1
382
+ // })
383
+
384
+ // subscriber.next(value)
385
+ // })
386
+ // })
387
+ // const reverseTransform$: Observable<TransformData> = gridAxesTransform$.pipe(
388
+ // takeUntil(destroy$),
389
+ // map(d => {
390
+ // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
391
+ // const scale: [number, number] = [d.scale[0] * -1, d.scale[1] * -1]
392
+ // const rotate = d.rotate * -1
393
+ // const rotateX = d.rotateX * -1
394
+ // const rotateY = d.rotateY * -1
395
+ // return {
396
+ // translate,
397
+ // scale,
398
+ // rotate,
399
+ // rotateX,
400
+ // rotateY,
401
+ // value: ''
402
+ // }
403
+ // }),
404
+ // )
405
+ const textReverseTransform$ = combineLatest({
406
+ gridAxesReverseTransform: gridAxesReverseTransform$,
407
+ gridContainerPosition: gridContainerPosition$
408
+ }).pipe(
409
+ takeUntil(destroy$),
410
+ debounceTime(0),
411
+ map(data => {
412
+ // const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
413
+ const axesRotateXYReverseValue = `rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
414
+ const axesRotateReverseValue = `rotate(${data.gridAxesReverseTransform.rotate}deg)`
415
+ const containerScaleReverseValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
416
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale)
417
+ return `${axesRotateXYReverseValue} ${axesRotateReverseValue} ${containerScaleReverseValue}`
418
+ }),
419
+ distinctUntilChanged()
420
+ )
421
+
422
+ const textReverseTransformWithRotate$ = combineLatest({
423
+ textReverseTransform: textReverseTransform$,
424
+ baseValueAxisParams: baseValueAxisParams$,
425
+ }).pipe(
426
+ takeUntil(destroy$),
427
+ debounceTime(0),
428
+ map(data => {
429
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
430
+ return `${data.textReverseTransform} rotate(${data.baseValueAxisParams.tickTextRotate}deg)`
431
+ })
432
+ )
433
+
434
+ // const minMax$: Observable<[number, number]> = new Observable(subscriber => {
435
+ // combineLatest({
436
+ // fullDataFormatter: fullDataFormatter$,
437
+ // computedData: computedData$
438
+ // }).pipe(
439
+ // takeUntil(destroy$),
440
+ // debounceTime(0),
441
+ // ).subscribe(data => {
442
+ // const groupMin = 0
443
+ // const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
444
+ // // const groupScaleDomainMin = data.fullDataFormatter.categoryAxis.scaleDomain[0] === 'auto'
445
+ // // ? groupMin - data.fullDataFormatter.categoryAxis.scalePadding
446
+ // // : data.fullDataFormatter.categoryAxis.scaleDomain[0] as number - data.fullDataFormatter.categoryAxis.scalePadding
447
+ // const groupScaleDomainMin = data.fullDataFormatter.categoryAxis.scaleDomain[0] - data.fullDataFormatter.categoryAxis.scalePadding
448
+ // const groupScaleDomainMax = data.fullDataFormatter.categoryAxis.scaleDomain[1] === 'max'
449
+ // ? groupMax + data.fullDataFormatter.categoryAxis.scalePadding
450
+ // : data.fullDataFormatter.categoryAxis.scaleDomain[1] as number + data.fullDataFormatter.categoryAxis.scalePadding
451
+
452
+ // const filteredData = data.computedData.map((d, i) => {
453
+ // return d.filter((_d, _i) => {
454
+ // return _i >= groupScaleDomainMin && _i <= groupScaleDomainMax
455
+ // })
456
+ // })
457
+
458
+ // const filteredMinMax = getMinMaxValue(filteredData.flat())
459
+ // if (filteredMinMax[0] === filteredMinMax[1]) {
460
+ // filteredMinMax[0] = filteredMinMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
461
+ // }
462
+ // subscriber.next(filteredMinMax)
463
+ // })
464
+ // })
465
+
466
+ const valueScale$: Observable<d3.ScaleLinear<number, number>> = new Observable(subscriber => {
467
+ combineLatest({
468
+ valueAxis: valueAxis$,
469
+ gridAxesSize: gridAxesSize$,
470
+ // minMax: minMax$
471
+ filteredMinMaxValue: filteredMinMaxValue$
472
+ }).pipe(
473
+ takeUntil(destroy$),
474
+ debounceTime(0),
475
+ ).subscribe(data => {
476
+ let maxValue = data.filteredMinMaxValue[1]
477
+ let minValue = data.filteredMinMaxValue[0]
478
+ if (maxValue === minValue && maxValue === 0) {
479
+ // 避免最大及最小值同等於 0 造成無法計算scale
480
+ maxValue = 1
481
+ }
482
+
483
+ const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
484
+ maxValue,
485
+ minValue,
486
+ axisWidth: data.gridAxesSize.height,
487
+ scaleDomain: data.valueAxis.scaleDomain,
488
+ scaleRange: data.valueAxis.scaleRange
489
+ })
490
+
491
+ subscriber.next(valueScale)
492
+ })
493
+ })
494
+
495
+ const tickTextAlign$: Observable<TextAlign> = combineLatest({
496
+ categoryAxis: categoryAxis$,
497
+ valueAxis: valueAxis$,
498
+ baseValueAxisParams: baseValueAxisParams$
499
+ }).pipe(
500
+ takeUntil(destroy$),
501
+ debounceTime(0),
502
+ map(data => {
503
+ let textAnchor: 'start' | 'middle' | 'end' = 'start'
504
+ let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
505
+
506
+ if (data.valueAxis.position === 'left') {
507
+ textAnchor = 'end'
508
+ dominantBaseline = 'middle'
509
+ } else if (data.valueAxis.position === 'right') {
510
+ textAnchor = 'start'
511
+ dominantBaseline = 'middle'
512
+ } else if (data.valueAxis.position === 'bottom') {
513
+ textAnchor = data.baseValueAxisParams.tickTextRotate
514
+ ? 'end'
515
+ : 'middle'
516
+ dominantBaseline = 'hanging'
517
+ } else if (data.valueAxis.position === 'top') {
518
+ textAnchor = data.baseValueAxisParams.tickTextRotate
519
+ ? 'start'
520
+ : 'middle'
521
+ dominantBaseline = 'auto'
522
+ }
523
+ return {
524
+ textAnchor,
525
+ dominantBaseline
526
+ }
527
+ })
528
+ )
529
+
530
+ const axisLabelAlign$: Observable<TextAlign> = combineLatest({
531
+ categoryAxis: categoryAxis$,
532
+ valueAxis: valueAxis$
533
+ }).pipe(
534
+ takeUntil(destroy$),
535
+ debounceTime(0),
536
+ map(d => {
537
+ let textAnchor: 'start' | 'middle' | 'end' = 'start'
538
+ let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
539
+
540
+ if (d.categoryAxis.position === 'bottom') {
541
+ dominantBaseline = 'auto'
542
+ } else if (d.categoryAxis.position === 'top') {
543
+ dominantBaseline = 'hanging'
544
+ } else if (d.categoryAxis.position === 'left') {
545
+ textAnchor = 'start'
546
+ } else if (d.categoryAxis.position === 'right') {
547
+ textAnchor = 'end'
548
+ }
549
+ if (d.valueAxis.position === 'left') {
550
+ textAnchor = 'end'
551
+ } else if (d.valueAxis.position === 'right') {
552
+ textAnchor = 'start'
553
+ } else if (d.valueAxis.position === 'bottom') {
554
+ dominantBaseline = 'hanging'
555
+ } else if (d.valueAxis.position === 'top') {
556
+ dominantBaseline = 'auto'
557
+ }
558
+ return {
559
+ textAnchor,
560
+ dominantBaseline
561
+ }
562
+ })
563
+ )
564
+
565
+
566
+ combineLatest({
567
+ axisSelection: axisSelection$,
568
+ baseValueAxisParams: baseValueAxisParams$,
569
+ tickTextAlign: tickTextAlign$,
570
+ axisLabelAlign: axisLabelAlign$,
571
+ computedData: computedData$,
572
+ gridAxesSize: gridAxesSize$,
573
+ categoryAxis: categoryAxis$,
574
+ valueAxis: valueAxis$,
575
+ valueScale: valueScale$,
576
+ textReverseTransform: textReverseTransform$,
577
+ textReverseTransformWithRotate: textReverseTransformWithRotate$,
578
+ theme: theme$
579
+ }).pipe(
580
+ takeUntil(destroy$),
581
+ debounceTime(0),
582
+ ).subscribe(data => {
583
+
584
+ renderAxis({
585
+ selection: data.axisSelection,
586
+ yAxisClassName,
587
+ baseValueAxisParams: data.baseValueAxisParams,
588
+ tickTextAlign: data.tickTextAlign,
589
+ gridAxesSize: data.gridAxesSize,
590
+ valueAxis: data.valueAxis,
591
+ valueScale: data.valueScale,
592
+ textReverseTransformWithRotate: data.textReverseTransformWithRotate,
593
+ theme: data.theme
594
+ })
595
+
596
+ renderAxisLabel({
597
+ selection: data.axisSelection,
598
+ textClassName,
599
+ baseValueAxisParams: data.baseValueAxisParams,
600
+ axisLabelAlign: data.axisLabelAlign,
601
+ gridAxesSize: data.gridAxesSize,
602
+ categoryAxis: data.categoryAxis,
603
+ valueAxis: data.valueAxis,
604
+ theme: data.theme,
605
+ textReverseTransform: data.textReverseTransform,
606
+ })
607
+ })
608
+
609
+ return () => {
610
+ destroy$.next(undefined)
611
+ }
612
+ }