@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,1131 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ // of,
4
+ iif,
5
+ EMPTY,
6
+ debounceTime,
7
+ combineLatest,
8
+ switchMap,
9
+ map,
10
+ filter,
11
+ first,
12
+ takeUntil,
13
+ distinctUntilChanged,
14
+ shareReplay,
15
+ Subject,
16
+ Observable } from 'rxjs'
17
+ import type { CategoryAuxParams, SeriesPlotPluginParams } from '../types'
18
+ import { DEFAULT_CATEGORY_AUX_PARAMS } from '../defaults'
19
+ import { LAYER_INDEX_OF_AUX } from '../../../const/layerIndex'
20
+ import { defineSVGLayer } from '@orbcharts/core'
21
+ import { SeriesPlotExtendContext } from '../types'
22
+ import { validateObject } from '@orbcharts/core'
23
+ import { createClassName, getColor } from '../../../utils/orbchartsUtils'
24
+ import { gridSelectionsObservable, gridCategoryPositionObservable } from '../../../utils/gridObservables'
25
+ import { parseTickFormatValue } from '../../../utils/d3Utils'
26
+ import { measureTextWidth } from '../../../utils/commonUtils'
27
+ import { renderTspansOnAxis } from '../../../utils/d3Graphics'
28
+ import { Theme } from '@orbcharts/core'
29
+ import { d3EventObservable } from '../../../utils/observables'
30
+
31
+
32
+ interface LineDatum {
33
+ id: string
34
+ x1: number
35
+ x2: number
36
+ y1: number
37
+ y2: number
38
+ }
39
+
40
+ interface LabelDatum {
41
+ id: string
42
+ text: string
43
+ textArr: string[]
44
+ textWidth: number
45
+ textHeight: number
46
+ x: number
47
+ y: number
48
+ }
49
+
50
+ const pluginName = 'SeriesPlot'
51
+ const layerName = 'CategoryAux'
52
+
53
+ const labelClassName = createClassName(pluginName, layerName, 'label-box')
54
+
55
+ const rectPaddingWidth = 6
56
+ const rectPaddingHeight = 3
57
+
58
+
59
+ function createLineData ({ categoryLabel, axisX, axisHeight, layerParams }: {
60
+ categoryLabel: string
61
+ axisX: number
62
+ axisHeight: number
63
+ layerParams: CategoryAuxParams
64
+ }): LineDatum[] {
65
+ return layerParams.showLine && categoryLabel
66
+ ? [{
67
+ id: categoryLabel,
68
+ x1: axisX,
69
+ x2: axisX,
70
+ y1: 0,
71
+ y2: axisHeight
72
+ }]
73
+ : []
74
+ }
75
+
76
+ function createLabelData ({ categoryLabel, axisX, layerParams, textSizePx, rowAmount }: {
77
+ categoryLabel: string
78
+ axisX: number
79
+ layerParams: CategoryAuxParams
80
+ textSizePx: number
81
+ rowAmount: number
82
+ }) {
83
+ const text = parseTickFormatValue(categoryLabel, layerParams.labelTextFormat)
84
+ const textArr = text.split('\n')
85
+ const maxLengthText = textArr.reduce((acc, current) => current.length > acc.length ? current : acc, '')
86
+ const textWidth = measureTextWidth(maxLengthText, textSizePx)
87
+ const textHeight = textSizePx * textArr.length
88
+ return layerParams.showLabel && categoryLabel
89
+ ? [{
90
+ id: categoryLabel,
91
+ x: axisX,
92
+ y: - layerParams.labelPadding * rowAmount, // rowAmount 是為了把外部 container 的變形逆轉回來
93
+ text,
94
+ textArr,
95
+ textWidth,
96
+ textHeight
97
+ }]
98
+ : []
99
+ }
100
+
101
+ function renderLine ({ selection, pluginName, lineData, layerParams, theme }: {
102
+ selection: d3.Selection<any, string, any, unknown>
103
+ pluginName: string
104
+ lineData: LineDatum[]
105
+ layerParams: CategoryAuxParams
106
+ theme: Theme
107
+ }) {
108
+ const gClassName = createClassName(pluginName, layerName, 'auxline')
109
+ const auxLineSelection = selection
110
+ .selectAll<SVGLineElement, LineDatum>(`line.${gClassName}`)
111
+ .data(lineData)
112
+ .join(
113
+ enter => {
114
+ return enter
115
+ .append('line')
116
+ .classed(gClassName, true)
117
+ .style('stroke-width', 1)
118
+ .style('pointer-events', 'none')
119
+ .style('vector-effect', 'non-scaling-stroke')
120
+ .attr('x1', d => d.x1)
121
+ .attr('y1', d => d.y1)
122
+ .attr('x2', d => d.x2)
123
+ .attr('y2', d => d.y2)
124
+ },
125
+ update => {
126
+ const updateSelection = update
127
+ .transition()
128
+ .duration(50)
129
+ .attr('x1', d => d.x1)
130
+ .attr('y1', d => d.y1)
131
+ .attr('x2', d => d.x2)
132
+ .attr('y2', d => d.y2)
133
+ return updateSelection
134
+ },
135
+ exit => exit.remove()
136
+ )
137
+ .style('stroke', d => getColor(layerParams.lineColorType, theme))
138
+ .style('stroke-dasharray', layerParams.lineDashArray ?? 'none')
139
+
140
+ return auxLineSelection
141
+ }
142
+
143
+ function removeLine (selection: d3.Selection<any, string, any, unknown>) {
144
+ const update = selection
145
+ .selectAll<SVGLineElement, LineDatum>('line')
146
+ .data([])
147
+
148
+ update.exit().remove()
149
+ }
150
+
151
+ function renderLabel ({ selection, labelData, pluginParams, layerParams, theme, textReverseTransformWithRotate, fontSizePx }: {
152
+ selection: d3.Selection<any, string, any, unknown>
153
+ labelData: LabelDatum[]
154
+ pluginParams: SeriesPlotPluginParams
155
+ layerParams: CategoryAuxParams
156
+ theme: Theme
157
+ // gridAxesReverseTransformValue: string
158
+ textReverseTransformWithRotate: string
159
+ fontSizePx: number
160
+ }) {
161
+ // const rectHeight = textSizePx + 6
162
+
163
+ const axisLabelSelection = selection
164
+ .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
165
+ .data(labelData)
166
+ .join(
167
+ enter => {
168
+ return enter
169
+ .append('g')
170
+ .classed(labelClassName, true)
171
+ .style('cursor', 'pointer')
172
+ .attr("transform", (d, i) => {
173
+ return `translate(${d.x}, ${d.y})`
174
+ })
175
+ },
176
+ update => {
177
+ const updateSelection = update
178
+ .transition()
179
+ .duration(50)
180
+ .attr("transform", (d, i) => {
181
+ return `translate(${d.x}, ${d.y})`
182
+ })
183
+ return updateSelection
184
+ },
185
+ exit => exit.remove()
186
+ )
187
+ .each((datum, i, n) => {
188
+ const gSelection = d3.select(n[i])
189
+
190
+ // const rectWidth = measureTextWidth(datum.text, textSizePx) + 12
191
+ const rectWidth = datum.textWidth + (rectPaddingWidth * 2)
192
+ const rectHeight = datum.textHeight + (rectPaddingHeight * 2)
193
+ // -- label偏移位置 --
194
+ let rectX = - rectWidth / 2
195
+ let rectY = -2
196
+ let x = rectX
197
+ let y = rectY - 3 // 奇怪的偏移修正
198
+ if (pluginParams.categoryAxis.position === 'bottom') {
199
+ rectX = layerParams.labelRotate
200
+ ? - rectWidth + rectHeight // 有傾斜時以末端對齊(+height是為了修正移動太多)
201
+ : - rectWidth / 2
202
+ rectY = 2
203
+ x = rectX
204
+ y = rectY - 3 // 奇怪的偏移修正
205
+ } else if (pluginParams.categoryAxis.position === 'left') {
206
+ rectX = - rectWidth + 2
207
+ rectY = - rectHeight / 2
208
+ x = rectX
209
+ y = rectY - 3 // 奇怪的偏移修正
210
+ if (layerParams.labelRotate) {
211
+ y += rectHeight
212
+ }
213
+ } else if (pluginParams.categoryAxis.position === 'right') {
214
+ rectX = - 2
215
+ rectY = - rectHeight / 2
216
+ x = rectX
217
+ y = rectY - 3 // 奇怪的偏移修正
218
+ if (layerParams.labelRotate) {
219
+ y += rectHeight
220
+ }
221
+ } else if (pluginParams.categoryAxis.position === 'top') {
222
+ rectX = layerParams.labelRotate
223
+ ? - rectWidth + rectHeight // 有傾斜時以末端對齊(+height是為了修正移動太多)
224
+ : - rectWidth / 2
225
+ rectY = - rectHeight + 6
226
+ x = - rectHeight
227
+ y = rectY - 3 // 奇怪的偏移修正
228
+ }
229
+
230
+ // -- rect --
231
+ const rect = gSelection
232
+ .selectAll<SVGRectElement, LabelDatum>('rect')
233
+ .data([datum])
234
+ .join(
235
+ enter => enter.append('rect')
236
+ .style('cursor', 'pointer')
237
+ .attr('rx', 5)
238
+ .attr('ry', 5),
239
+ update => update,
240
+ exit => exit.remove()
241
+ )
242
+ .attr('width', d => `${rectWidth}px`)
243
+ .attr('height', `${rectHeight}px`)
244
+ .attr('fill', d => getColor(layerParams.labelColorType, theme))
245
+ .attr('x', x)
246
+ .attr('y', y) // 奇怪的偏移修正
247
+ .style('transform', textReverseTransformWithRotate)
248
+
249
+ // -- text --
250
+ const text = gSelection
251
+ .selectAll<SVGTextElement, LabelDatum>('text')
252
+ .data([datum])
253
+ .join(
254
+ enter => enter.append('text')
255
+ .style('dominant-baseline', 'hanging')
256
+ .style('cursor', 'pointer'),
257
+ update => update,
258
+ exit => exit.remove()
259
+ )
260
+ .style('transform', textReverseTransformWithRotate)
261
+ .attr('fill', d => getColor(layerParams.labelTextColorType, theme))
262
+ .attr('font-size', theme.fontSize)
263
+ .attr('x', x + rectPaddingWidth)
264
+ .attr('y', y + rectPaddingHeight)
265
+ .each((d, i, n) => {
266
+ renderTspansOnAxis(d3.select(n[i]), {
267
+ textArr: datum.textArr,
268
+ textSizePx: fontSizePx,
269
+ categoryAxisPosition: pluginParams.categoryAxis.position,
270
+ isContainerRotated: false
271
+ })
272
+ })
273
+
274
+ // -- 第二次文字寬度(因為原本計算的文字寬度有可能因為字體差異會有誤差) --
275
+ // 取得文字寬度
276
+ let textWidthArr: number[] = []
277
+ text.selectAll('tspan')
278
+ .each((d, i, n) => {
279
+ const tspan = d3.select(n[i])
280
+ const textNode: SVGTextElement = tspan.node() as SVGTextElement
281
+ if (textNode && textNode.getBBox()) {
282
+ textWidthArr.push(textNode.getBBox().width)
283
+ }
284
+ })
285
+ const maxTextWidth = Math.max(...textWidthArr)
286
+ // 依文字寬度設定矩形寬度
287
+ rect.attr('width', maxTextWidth + rectPaddingWidth * 2)
288
+ })
289
+
290
+ return axisLabelSelection
291
+ }
292
+
293
+ function removeLabel (selection: d3.Selection<any, string, any, unknown>) {
294
+ const gUpdate = selection
295
+ .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
296
+ .data([])
297
+
298
+ gUpdate.exit().remove()
299
+ }
300
+
301
+
302
+ export const CategoryAux = defineSVGLayer<SeriesPlotExtendContext, SeriesPlotPluginParams, CategoryAuxParams>({
303
+ name: layerName,
304
+ defaultParams: DEFAULT_CATEGORY_AUX_PARAMS,
305
+ layerIndex: LAYER_INDEX_OF_AUX,
306
+ initShow: false,
307
+ validator: (params) => {
308
+ const result = validateObject(params, {
309
+ showLine: {
310
+ toBeTypes: ['boolean']
311
+ },
312
+ showLabel: {
313
+ toBeTypes: ['boolean']
314
+ },
315
+ lineDashArray: {
316
+ toBeTypes: ['string']
317
+ },
318
+ lineColorType: {
319
+ toBeOption: 'ColorType'
320
+ },
321
+ labelColorType: {
322
+ toBeOption: 'ColorType'
323
+ },
324
+ labelTextColorType: {
325
+ toBeOption: 'ColorType'
326
+ },
327
+ labelTextFormat: {
328
+ toBeTypes: ['string', 'Function']
329
+ },
330
+ labelPadding: {
331
+ toBeTypes: ['number']
332
+ },
333
+ labelRotate: {
334
+ toBeTypes: ['number']
335
+ }
336
+ })
337
+ return result
338
+ },
339
+ setup: ({ svgG, pluginParams$, layerParams$, context }) => {
340
+ const destroy$ = new Subject()
341
+
342
+ context.layout$
343
+ .pipe(
344
+ takeUntil(destroy$)
345
+ )
346
+ .subscribe(layout => {
347
+ d3.select(svgG)
348
+ .attr('transform', `translate(${layout.left}, ${layout.top})`)
349
+ })
350
+
351
+ let isLabelMouseover = false
352
+
353
+ // const rootSelection = d3.select(`svg.orbcharts-${pluginName}__svg`)
354
+ const rootSelection = d3.select(svgG.parentElement)
355
+
356
+ const rootRectSelection: d3.Selection<SVGRectElement, any, any, any> = rootSelection
357
+ .insert('rect', 'g')
358
+ .classed(createClassName(pluginName, layerName, 'rect'), true)
359
+ .attr('opacity', 0)
360
+
361
+ // const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
362
+ // .append('g')
363
+
364
+ const {
365
+ seriesSelection$,
366
+ axesSelection$,
367
+ defsSelection$,
368
+ graphicGSelection$
369
+ } = gridSelectionsObservable({
370
+ selection: d3.select(svgG),
371
+ pluginName,
372
+ layerName,
373
+ clipPathID: 'test',
374
+ seriesLabels$: context.isSeriesSeprate$.pipe(
375
+ switchMap(isSeriesSeprate => {
376
+ return iif(
377
+ () => isSeriesSeprate,
378
+ context.seriesLabels$,
379
+ // 如果沒分開的話只取一筆
380
+ context.seriesLabels$.pipe(
381
+ map(d => [d[0]])
382
+ )
383
+ )
384
+ })
385
+ ),
386
+ gridContainerPosition$: context.gridContainerPosition$,
387
+ gridAxesTransform$: context.gridAxesTransform$,
388
+ gridGraphicTransform$: context.gridGraphicTransform$
389
+ })
390
+
391
+ context.layout$.pipe(
392
+ takeUntil(destroy$),
393
+ ).subscribe(d => {
394
+ rootRectSelection
395
+ .attr('width', d.rootWidth)
396
+ .attr('height', d.rootHeight)
397
+ })
398
+
399
+ // context.gridAxesTransform$
400
+ // .pipe(
401
+ // takeUntil(destroy$),
402
+ // map(d => d.value),
403
+ // distinctUntilChanged()
404
+ // ).subscribe(d => {
405
+ // axisSelection
406
+ // .style('transform', d)
407
+ // })
408
+
409
+ // const visibleComputedData$ = context.computedData$.pipe(
410
+ // takeUntil(destroy$),
411
+ // map(data => {
412
+ // const visibleComputedData = data
413
+ // .map(d => {
414
+ // return d.filter(_d => {
415
+ // return _d.visible == true
416
+ // })
417
+ // })
418
+ // .filter(d => d.length)
419
+ // // console.log('visibleComputedData', visibleComputedData)
420
+ // return visibleComputedData
421
+ // })
422
+ // )
423
+
424
+ // const SeriesDataMap$ = visibleComputedData$.pipe(
425
+ // map(d => makeGridSeriesDataMap(d))
426
+ // )
427
+
428
+ // const CategoryDataMap$ = visibleComputedData$.pipe(
429
+ // map(d => makeGridCategoryDataMap(d))
430
+ // )
431
+
432
+ // const contentTransform$: Observable<string> = new Observable(subscriber => {
433
+ // combineLatest({
434
+ // layerParams: context.layerParams$,
435
+ // gridAxesTransform: context.gridAxesTransform$
436
+ // }).pipe(
437
+ // takeUntil(destroy$),
438
+ // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
439
+ // debounceTime(0),
440
+ // ).subscribe(data => {
441
+
442
+ // const transformData = Object.assign({}, data.gridAxesTransform)
443
+
444
+ // // const value = getAxesTransformValue({
445
+ // // translate: [0, 0],
446
+ // // scale: [transformData.scale[0] * -1, transformData.scale[1] * -1],
447
+ // // rotate: transformData.rotate * -1,
448
+ // // rotateX: transformData.rotateX * -1,
449
+ // // rotateY: transformData.rotateY * -1
450
+ // // })
451
+
452
+ // subscriber.next(transformData.value)
453
+ // })
454
+ // })
455
+ // const reverseTransform$: Observable<TransformData> = context.gridAxesTransform$.pipe(
456
+ // takeUntil(destroy$),
457
+ // map(d => {
458
+ // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
459
+ // const scale: [number, number] = [d.scale[0] * -1, d.scale[1] * -1]
460
+ // const rotate = d.rotate * -1
461
+ // const rotateX = d.rotateX * -1
462
+ // const rotateY = d.rotateY * -1
463
+ // return {
464
+ // translate,
465
+ // scale,
466
+ // rotate,
467
+ // rotateX,
468
+ // rotateY,
469
+ // value: ''
470
+ // }
471
+ // }),
472
+ // )
473
+ // const contentTransform$ = combineLatest({
474
+ // layerParams: context.layerParams$,
475
+ // reverseTransform: reverseTransform$
476
+ // }).pipe(
477
+ // takeUntil(destroy$),
478
+ // switchMap(async data => {
479
+ // const translate = [0, 0]
480
+ // return `translate(${translate[0]}px, ${translate[1]}px) rotate(${data.reverseTransform.rotate}deg) rotateX(${data.reverseTransform.rotateX}deg) rotateY(${data.reverseTransform.rotateY}deg)`
481
+ // }),
482
+ // distinctUntilChanged()
483
+ // )
484
+
485
+ // const groupScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
486
+ // combineLatest({
487
+ // fullDataFormatter: context.fullDataFormatter$,
488
+ // gridAxesSize: context.gridAxesSize$,
489
+ // computedData: context.computedData$
490
+ // }).pipe(
491
+ // takeUntil(destroy$),
492
+ // debounceTime(0),
493
+ // ).subscribe(data => {
494
+ // const groupMin = 0
495
+ // const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
496
+ // const groupScaleDomainMin = data.fullDataFormatter.categoryAxis.scaleDomain[0] === 'auto'
497
+ // ? groupMin - data.fullDataFormatter.categoryAxis.scalePadding
498
+ // : data.fullDataFormatter.categoryAxis.scaleDomain[0] as number - data.fullDataFormatter.categoryAxis.scalePadding
499
+ // const groupScaleDomainMax = data.fullDataFormatter.categoryAxis.scaleDomain[1] === 'auto'
500
+ // ? groupMax + data.fullDataFormatter.categoryAxis.scalePadding
501
+ // : data.fullDataFormatter.categoryAxis.scaleDomain[1] as number + data.fullDataFormatter.categoryAxis.scalePadding
502
+
503
+ // const groupingLength = data.computedData[0]
504
+ // ? data.computedData[0].length
505
+ // : 0
506
+
507
+ // let _labels = data.fullDataFormatter.seriesDirection === 'row'
508
+ // // ? data.fullDataFormatter.columnLabels
509
+ // // : data.fullDataFormatter.rowLabels
510
+ // ? (data.computedData[0] ?? []).map(d => d.categoryLabel)
511
+ // : data.computedData.map(d => d[0].categoryLabel)
512
+
513
+ // const axisLabels = new Array(groupingLength).fill(0)
514
+ // .map((d, i) => {
515
+ // return _labels[i] != null
516
+ // ? _labels[i]
517
+ // : String(i) // 沒有label則用序列號填充
518
+ // })
519
+ // .filter((d, i) => {
520
+ // return i >= groupScaleDomainMin && i <= groupScaleDomainMax
521
+ // })
522
+
523
+
524
+ // const padding = data.fullDataFormatter.categoryAxis.scalePadding
525
+
526
+ // const groupScale = createLabelToAxisScale({
527
+ // axisLabels,
528
+ // axisWidth: data.gridAxesSize.width,
529
+ // padding
530
+ // })
531
+
532
+ // subscriber.next(groupScale)
533
+ // })
534
+ // })
535
+
536
+ // const groupScaleDomain$ = combineLatest({
537
+ // fullDataFormatter: context.fullDataFormatter$,
538
+ // gridAxesSize: context.gridAxesSize$,
539
+ // computedData: context.computedData$
540
+ // }).pipe(
541
+ // takeUntil(destroy$),
542
+ // debounceTime(0),
543
+ // map(data => {
544
+ // const groupMin = 0
545
+ // const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
546
+ // // const groupScaleDomainMin = data.fullDataFormatter.categoryAxis.scaleDomain[0] === 'auto'
547
+ // // ? groupMin - data.fullDataFormatter.categoryAxis.scalePadding
548
+ // // : data.fullDataFormatter.categoryAxis.scaleDomain[0] as number - data.fullDataFormatter.categoryAxis.scalePadding
549
+ // const groupScaleDomainMin = data.fullDataFormatter.categoryAxis.scaleDomain[0] - data.fullDataFormatter.categoryAxis.scalePadding
550
+ // const groupScaleDomainMax = data.fullDataFormatter.categoryAxis.scaleDomain[1] === 'max'
551
+ // ? groupMax + data.fullDataFormatter.categoryAxis.scalePadding
552
+ // : data.fullDataFormatter.categoryAxis.scaleDomain[1] as number + data.fullDataFormatter.categoryAxis.scalePadding
553
+
554
+ // return [groupScaleDomainMin, groupScaleDomainMax]
555
+ // }),
556
+ // shareReplay(1)
557
+ // )
558
+
559
+ const groupScale$ = combineLatest({
560
+ categoryScaleDomainValue: context.categoryScaleDomainValue$,
561
+ gridAxesSize: context.gridAxesSize$
562
+ }).pipe(
563
+ takeUntil(destroy$),
564
+ debounceTime(0),
565
+ map(data => {
566
+ const groupScale: d3.ScaleLinear<number, number> = d3.scaleLinear()
567
+ .domain(data.categoryScaleDomainValue)
568
+ .range([0, data.gridAxesSize.width])
569
+ return groupScale
570
+ })
571
+ )
572
+
573
+ // // 取得事件座標的group資料
574
+ // const gridGroupPositionFn$ = gridGroupPositionFnObservable({
575
+ // fullDataFormatter$: context.fullDataFormatter$,
576
+ // gridAxesSize$: context.gridAxesSize$,
577
+ // computedData$: context.computedData$,
578
+ // fullChartParams$: context.fullChartParams$,
579
+ // })
580
+
581
+ const highlightTarget$ = pluginParams$.pipe(
582
+ takeUntil(destroy$),
583
+ map(d => d.styles.highlightTarget),
584
+ distinctUntilChanged()
585
+ )
586
+
587
+ // combineLatest({
588
+ // computedData: context.computedData$,
589
+ // gridAxesSize: context.gridAxesSize$,
590
+ // layerParams: context.layerParams$,
591
+ // fullChartParams: context.fullChartParams$,
592
+ // highlightTarget: highlightTarget$,
593
+ // SeriesDataMap: context.SeriesDataMap$,
594
+ // CategoryDataMap: context.CategoryDataMap$,
595
+ // gridGroupPositionFn: gridGroupPositionFn$,
596
+ // groupScale: groupScale$,
597
+ // }).pipe(
598
+ // takeUntil(destroy$),
599
+ // debounceTime(0),
600
+ // ).subscribe(data => {
601
+
602
+ // // store.selection
603
+ // rootSelection
604
+ // .on('mouseover', (event, datum) => {
605
+ // // event.stopPropagation()
606
+
607
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
608
+
609
+ // subject.event$.next({
610
+ // type: 'grid',
611
+ // pluginName: name,
612
+ // eventName: 'mouseover',
613
+ // highlightTarget: data.highlightTarget,
614
+ // datum: null,
615
+ // gridIndex: 0,
616
+ // series: [],
617
+ // seriesIndex: -1,
618
+ // seriesLabel: '',
619
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
620
+ // // group: [],
621
+ // categoryIndex,
622
+ // categoryLabel,
623
+ // event,
624
+ // data: data.computedData
625
+ // })
626
+ // })
627
+ // .on('mousemove', (event, datum) => {
628
+ // // event.stopPropagation()
629
+
630
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
631
+
632
+ // subject.event$.next({
633
+ // type: 'grid',
634
+ // pluginName: name,
635
+ // eventName: 'mousemove',
636
+ // highlightTarget: data.highlightTarget,
637
+ // datum: null,
638
+ // gridIndex: 0,
639
+ // series: [],
640
+ // seriesIndex: -1,
641
+ // seriesLabel: '',
642
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
643
+ // // group: [],
644
+ // categoryIndex,
645
+ // categoryLabel,
646
+ // event,
647
+ // data: data.computedData
648
+ // })
649
+ // })
650
+ // .on('mouseout', (event, datum) => {
651
+ // // event.stopPropagation()
652
+
653
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
654
+
655
+ // subject.event$.next({
656
+ // type: 'grid',
657
+ // pluginName: name,
658
+ // eventName: 'mouseout',
659
+ // highlightTarget: data.highlightTarget,
660
+ // datum: null,
661
+ // gridIndex: 0,
662
+ // series: [],
663
+ // seriesIndex: -1,
664
+ // seriesLabel: '',
665
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
666
+ // // group: [],
667
+ // categoryIndex,
668
+ // categoryLabel,
669
+ // event,
670
+ // data: data.computedData
671
+ // })
672
+ // })
673
+ // .on('click', (event, datum) => {
674
+ // event.stopPropagation()
675
+
676
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
677
+
678
+ // subject.event$.next({
679
+ // type: 'grid',
680
+ // pluginName: name,
681
+ // eventName: 'click',
682
+ // highlightTarget: data.highlightTarget,
683
+ // datum: null,
684
+ // gridIndex: 0,
685
+ // series: [],
686
+ // seriesIndex: -1,
687
+ // seriesLabel: '',
688
+ // // group: data.CategoryDataMap.get(categoryLabel) ?? [],
689
+ // group: [],
690
+ // categoryIndex,
691
+ // categoryLabel,
692
+ // event,
693
+ // data: data.computedData
694
+ // })
695
+ // })
696
+
697
+ // // barSelection$.next(barSelection!)
698
+ // })
699
+
700
+ const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove').pipe(
701
+ takeUntil(destroy$),
702
+ )
703
+
704
+ // const mousemoveGroupLabel$ = combineLatest({
705
+ // rootMousemove: rootMousemove$,
706
+ // gridGroupPositionFn: gridGroupPositionFn$,
707
+ // }).pipe(
708
+ // takeUntil(destroy$),
709
+ // switchMap(async d => d),
710
+ // map(data => {
711
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(data.rootMousemove)
712
+ // return { categoryIndex, categoryLabel }
713
+ // }),
714
+ // shareReplay(1)
715
+ // )
716
+
717
+
718
+ const textReverseTransform$ = combineLatest({
719
+ gridAxesReverseTransform: context.gridAxesReverseTransform$,
720
+ gridContainerPosition: context.gridContainerPosition$
721
+ }).pipe(
722
+ takeUntil(destroy$),
723
+ debounceTime(0),
724
+ map(data => {
725
+ // const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
726
+ const axesRotateXYReverseValue = `rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
727
+ const axesRotateReverseValue = `rotate(${data.gridAxesReverseTransform.rotate}deg)`
728
+ const containerScaleReverseValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
729
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale)
730
+ return `${axesRotateXYReverseValue} ${axesRotateReverseValue} ${containerScaleReverseValue}`
731
+ }),
732
+ distinctUntilChanged()
733
+ )
734
+
735
+ const textReverseTransformWithRotate$ = combineLatest({
736
+ textReverseTransform: textReverseTransform$,
737
+ layerParams: layerParams$,
738
+ }).pipe(
739
+ takeUntil(destroy$),
740
+ debounceTime(0),
741
+ map(data => {
742
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
743
+ return `${data.textReverseTransform} rotate(${data.layerParams.labelRotate}deg)`
744
+ })
745
+ )
746
+
747
+ const columnAmount$ = context.gridContainerPosition$.pipe(
748
+ takeUntil(destroy$),
749
+ map(gridContainerPosition => {
750
+ const maxColumnIndex = gridContainerPosition.reduce((acc, current) => {
751
+ return current.columnIndex > acc ? current.columnIndex : acc
752
+ }, 0)
753
+ return maxColumnIndex + 1
754
+ }),
755
+ distinctUntilChanged()
756
+ )
757
+
758
+ const rowAmount$ = context.gridContainerPosition$.pipe(
759
+ takeUntil(destroy$),
760
+ map(gridContainerPosition => {
761
+ const maxRowIndex = gridContainerPosition.reduce((acc, current) => {
762
+ return current.rowIndex > acc ? current.rowIndex : acc
763
+ }, 0)
764
+ return maxRowIndex + 1
765
+ }),
766
+ distinctUntilChanged()
767
+ )
768
+
769
+ const gridGroupPosition$ = gridCategoryPositionObservable({
770
+ rootSelection,
771
+ // fullDataFormatter$: context.fullDataFormatter$,
772
+ pluginParams$: pluginParams$,
773
+ // containerSize$: context.containerSize$,
774
+ gridAxesContainerSize$: context.gridAxesContainerSize$,
775
+ computedData$: context.computedData$,
776
+ gridContainerPosition$: context.gridContainerPosition$,
777
+ layout$: context.layout$
778
+ }).pipe(
779
+ takeUntil(destroy$)
780
+ )
781
+
782
+ combineLatest({
783
+ axesSelection: axesSelection$,
784
+ columnAmount: columnAmount$,
785
+ rowAmount: rowAmount$,
786
+ layout: context.layout$,
787
+ rootMousemove: rootMousemove$,
788
+ // gridGroupPositionFn: gridGroupPositionFn$,
789
+ gridGroupPosition: gridGroupPosition$,
790
+ computedData: context.computedData$,
791
+ groupScale: groupScale$,
792
+ gridAxesSize: context.gridAxesSize$,
793
+ pluginParams: pluginParams$,
794
+ layerParams: layerParams$,
795
+ theme: context.theme$,
796
+ highlightTarget: highlightTarget$,
797
+ // gridAxesReverseTransform: context.gridAxesReverseTransform$,
798
+ textReverseTransformWithRotate: textReverseTransformWithRotate$,
799
+ // CategoryDataMap: context.CategoryDataMap$,
800
+ fontSizePx: context.fontSizePx$
801
+ }).pipe(
802
+ takeUntil(destroy$),
803
+ switchMap(async d => d),
804
+ ).subscribe(data => {
805
+ // // 由於event座標是基於底層的,但是container會有多欄,所以要重新計算
806
+ // const eventData = {
807
+ // offsetX: data.rootMousemove.offsetX * data.columnAmount % data.layout.rootWidth,
808
+ // offsetY: data.rootMousemove.offsetY * data.rowAmount % data.layout.rootHeight
809
+ // }
810
+ // 依event的座標取得group資料
811
+ const { categoryIndex, categoryLabel } = data.gridGroupPosition
812
+ // console.log('gridGroupPosition', categoryIndex, categoryLabel)
813
+ const axisX = data.groupScale(categoryIndex) ?? 0
814
+ // console.log('axisX', axisX)
815
+ const lineData = createLineData({
816
+ categoryLabel: categoryLabel,
817
+ axisX,
818
+ axisHeight: data.gridAxesSize.height,
819
+ layerParams: data.layerParams,
820
+ })
821
+ // console.log('lineData', lineData)
822
+ renderLine({
823
+ // selection: axisSelection,
824
+ selection: data.axesSelection,
825
+ pluginName,
826
+ lineData,
827
+ layerParams: data.layerParams,
828
+ theme: data.theme
829
+ })
830
+ const labelData = createLabelData({
831
+ categoryLabel: categoryLabel,
832
+ axisX,
833
+ layerParams: data.layerParams,
834
+ textSizePx: data.fontSizePx,
835
+ rowAmount: data.rowAmount
836
+ })
837
+ const labelSelection = renderLabel({
838
+ // selection: axisSelection,
839
+ selection: data.axesSelection,
840
+ labelData,
841
+ pluginParams: data.pluginParams,
842
+ layerParams: data.layerParams,
843
+ // gridAxesReverseTransformValue: data.gridAxesReverseTransform.value,
844
+ textReverseTransformWithRotate: data.textReverseTransformWithRotate,
845
+ theme: data.theme,
846
+ fontSizePx: data.fontSizePx,
847
+ })
848
+
849
+ // label的事件
850
+ labelSelection
851
+ .on('mouseover', (event, datum) => {
852
+ event.stopPropagation()
853
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
854
+
855
+ isLabelMouseover = true
856
+
857
+ context.eventTrigger$.next({
858
+ // type: 'grid',
859
+ // pluginName: name,
860
+ // eventName: 'mouseover',
861
+ // highlightTarget: data.highlightTarget,
862
+ // datum: null,
863
+ // gridIndex: 0,
864
+ // series: [],
865
+ // seriesIndex: -1,
866
+ // seriesLabel: '',
867
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
868
+ // categoryIndex,
869
+ // categoryLabel,
870
+ // event,
871
+ // data: data.computedData
872
+ eventName: 'mouseover',
873
+ pluginName,
874
+ layerName,
875
+ target: null,
876
+ event,
877
+ })
878
+ })
879
+ .on('mousemove', (event, datum) => {
880
+ event.stopPropagation()
881
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
882
+
883
+ context.eventTrigger$.next({
884
+ // type: 'grid',
885
+ // pluginName: name,
886
+ // eventName: 'mousemove',
887
+ // highlightTarget: data.highlightTarget,
888
+ // datum: null,
889
+ // gridIndex: 0,
890
+ // series: [],
891
+ // seriesIndex: -1,
892
+ // seriesLabel: '',
893
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
894
+ // categoryIndex,
895
+ // categoryLabel,
896
+ // event,
897
+ // data: data.computedData
898
+ eventName: 'mousemove',
899
+ pluginName,
900
+ layerName,
901
+ target: null,
902
+ event,
903
+ })
904
+ })
905
+ .on('mouseout', (event, datum) => {
906
+ event.stopPropagation()
907
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
908
+
909
+ isLabelMouseover = false
910
+
911
+ context.eventTrigger$.next({
912
+ // type: 'grid',
913
+ // pluginName: name,
914
+ // eventName: 'mouseout',
915
+ // highlightTarget: data.highlightTarget,
916
+ // datum: null,
917
+ // gridIndex: 0,
918
+ // series: [],
919
+ // seriesIndex: -1,
920
+ // seriesLabel: '',
921
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
922
+ // categoryIndex,
923
+ // categoryLabel,
924
+ // event,
925
+ // data: data.computedData
926
+ eventName: 'mouseout',
927
+ pluginName,
928
+ layerName,
929
+ target: null,
930
+ event,
931
+ })
932
+ })
933
+ .on('click', (event, datum) => {
934
+ event.stopPropagation()
935
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
936
+
937
+ context.eventTrigger$.next({
938
+ // type: 'grid',
939
+ // pluginName: name,
940
+ // eventName: 'click',
941
+ // highlightTarget: data.highlightTarget,
942
+ // datum: null,
943
+ // gridIndex: 0,
944
+ // series: [],
945
+ // seriesIndex: -1,
946
+ // seriesLabel: '',
947
+ // group: data.CategoryDataMap.get(categoryLabel) ?? [],
948
+ // categoryIndex,
949
+ // categoryLabel,
950
+ // event,
951
+ // data: data.computedData
952
+ eventName: 'click',
953
+ pluginName,
954
+ layerName,
955
+ target: null,
956
+ event,
957
+ })
958
+ })
959
+
960
+ })
961
+
962
+ // // -- highlight(無論highlightTarget設定為何,一律依從categoryLabel來顯示) --
963
+ // combineLatest({
964
+ // event: subject.event$.pipe(
965
+ // filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove')
966
+ // ),
967
+ // computedData: context.computedData$,
968
+ // groupScale: groupScale$,
969
+ // gridAxesSize: context.gridAxesSize$,
970
+ // layerParams: context.layerParams$,
971
+ // fullChartParams: context.fullChartParams$,
972
+ // highlightTarget: highlightTarget$,
973
+ // gridAxesReverseTransform: context.gridAxesReverseTransform$,
974
+ // CategoryDataMap: context.CategoryDataMap$,
975
+ // gridGroupPositionFn: gridGroupPositionFn$,
976
+ // textSizePx: context.textSizePx$
977
+ // }).pipe(
978
+ // takeUntil(destroy$),
979
+ // switchMap(async d => d)
980
+ // ).subscribe(data => {
981
+ // // const group = data.event.eventName === 'mouseover' || data.event.eventName === 'mousemove'
982
+ // // ? data.event.group
983
+ // // : []
984
+
985
+ // // const categoryLabel = data.event.eventName === 'mouseover' || data.event.eventName === 'mousemove'
986
+ // // ? data.event.categoryLabel
987
+ // // : ''
988
+ // const axisX = data.groupScale(data.event.categoryLabel) ?? 0
989
+
990
+ // const lineData = createLineData({
991
+ // categoryLabel: data.event.categoryLabel,
992
+ // axisX,
993
+ // axisHeight: data.gridAxesSize.height,
994
+ // layerParams: data.layerParams,
995
+ // })
996
+ // renderLine({
997
+ // selection: axisSelection,
998
+ // pluginName: name,
999
+ // lineData,
1000
+ // layerParams: data.layerParams,
1001
+ // fullChartParams: data.fullChartParams
1002
+ // })
1003
+ // const labelData = createLabelData({
1004
+ // categoryLabel: data.event.categoryLabel,
1005
+ // axisX,
1006
+ // layerParams: data.layerParams
1007
+ // })
1008
+ // const labelSelection = renderLabel({
1009
+ // selection: axisSelection,
1010
+ // labelData,
1011
+ // layerParams: data.layerParams,
1012
+ // fullChartParams: data.fullChartParams,
1013
+ // gridAxesReverseTransformValue: data.gridAxesReverseTransform.value,
1014
+ // textSizePx: data.textSizePx
1015
+ // })
1016
+
1017
+ // // label的事件
1018
+ // labelSelection
1019
+ // .on('mouseover', (event, datum) => {
1020
+
1021
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
1022
+
1023
+ // subject.event$.next({
1024
+ // type: 'grid',
1025
+ // pluginName: name,
1026
+ // eventName: 'mouseover',
1027
+ // highlightTarget: data.highlightTarget,
1028
+ // datum: null,
1029
+ // gridIndex: 0,
1030
+ // series: [],
1031
+ // seriesIndex: -1,
1032
+ // seriesLabel: '',
1033
+ // group: data.event.group,
1034
+ // categoryIndex,
1035
+ // categoryLabel,
1036
+ // event,
1037
+ // data: data.computedData
1038
+ // })
1039
+ // })
1040
+ // .on('mousemove', (event, datum) => {
1041
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
1042
+
1043
+ // subject.event$.next({
1044
+ // type: 'grid',
1045
+ // pluginName: name,
1046
+ // eventName: 'mousemove',
1047
+ // highlightTarget: data.highlightTarget,
1048
+ // datum: null,
1049
+ // gridIndex: 0,
1050
+ // series: [],
1051
+ // seriesIndex: -1,
1052
+ // seriesLabel: '',
1053
+ // group: data.event.group,
1054
+ // categoryIndex,
1055
+ // categoryLabel,
1056
+ // event,
1057
+ // data: data.computedData
1058
+ // })
1059
+ // })
1060
+ // .on('mouseout', (event, datum) => {
1061
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
1062
+
1063
+ // subject.event$.next({
1064
+ // type: 'grid',
1065
+ // pluginName: name,
1066
+ // eventName: 'mouseout',
1067
+ // highlightTarget: data.highlightTarget,
1068
+ // datum: null,
1069
+ // gridIndex: 0,
1070
+ // series: [],
1071
+ // seriesIndex: -1,
1072
+ // seriesLabel: '',
1073
+ // group: data.event.group,
1074
+ // categoryIndex,
1075
+ // categoryLabel,
1076
+ // event,
1077
+ // data: data.computedData
1078
+ // })
1079
+ // })
1080
+ // .on('click', (event, datum) => {
1081
+ // const { categoryIndex, categoryLabel } = data.gridGroupPositionFn(event)
1082
+
1083
+ // subject.event$.next({
1084
+ // type: 'grid',
1085
+ // pluginName: name,
1086
+ // eventName: 'click',
1087
+ // highlightTarget: data.highlightTarget,
1088
+ // datum: null,
1089
+ // gridIndex: 0,
1090
+ // series: [],
1091
+ // seriesIndex: -1,
1092
+ // seriesLabel: '',
1093
+ // group: data.event.group,
1094
+ // categoryIndex,
1095
+ // categoryLabel,
1096
+ // event,
1097
+ // data: data.computedData
1098
+ // })
1099
+ // })
1100
+ // })
1101
+
1102
+
1103
+
1104
+ const rootRectMouseout$ = d3EventObservable(rootRectSelection, 'mouseout').pipe(
1105
+ takeUntil(destroy$),
1106
+ )
1107
+
1108
+ combineLatest({
1109
+ rootRectMouseout: rootRectMouseout$,
1110
+ axesSelection: axesSelection$,
1111
+ }).pipe(
1112
+ takeUntil(destroy$),
1113
+ switchMap(async d => d)
1114
+ ).subscribe(data => {
1115
+ setTimeout(() => {
1116
+ // @Q@ workaround - 不知為何和 label 會有衝突,當滑鼠移動到 label 上時,會觸發 mouseout 事件
1117
+ if (isLabelMouseover == true) {
1118
+ return
1119
+ }
1120
+
1121
+ removeLine(data.axesSelection)
1122
+ removeLabel(data.axesSelection)
1123
+ })
1124
+ })
1125
+
1126
+ return () => {
1127
+ destroy$.next(undefined)
1128
+ rootRectSelection.remove()
1129
+ }
1130
+ }
1131
+ })