@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,686 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ map,
5
+ switchMap,
6
+ debounceTime,
7
+ takeUntil,
8
+ distinctUntilChanged,
9
+ Observable,
10
+ Subject,
11
+ iif
12
+ } from 'rxjs'
13
+ import type { Theme, EventData, ColorType } from '@orbcharts/core'
14
+ import type { ScatterPlotPluginParams, ScatterPlotExtendContext, XYAuxParams, ComputedXYDataMultivariate } from '../types'
15
+ import { defineSVGLayer } from '@orbcharts/core'
16
+ import { validateObject } from '@orbcharts/core'
17
+ import { DEFAULT_X_Y_AUX_PARAMS } from "../defaults"
18
+ import { multivariateSelectionsObservable } from "../../../utils/multivariateObservables"
19
+ import { getColor, getDatumColor } from '../../../utils/orbchartsUtils'
20
+ import { createClassName, createUniID } from '../../../utils/orbchartsUtils'
21
+ import type { ContainerPosition, GraphicStyles, Layout } from '../../../types/PluginParams'
22
+ import { multivariateXYPositionObservable } from '../../../utils/multivariateObservables'
23
+ import { LAYER_INDEX_OF_AUX } from '../../../const/layerIndex'
24
+ import { d3EventObservable } from '../../../utils/observables'
25
+ import { renderTspansOnAxis } from '../../../utils/d3Graphics'
26
+ import { parseTickFormatValue } from '../../../utils/d3Utils'
27
+ import { measureTextWidth } from '../../../utils/commonUtils'
28
+
29
+ interface LineDatum {
30
+ id: string
31
+ x1: number
32
+ x2: number
33
+ y1: number
34
+ y2: number
35
+ dashArray: string
36
+ colorType: ColorType
37
+ }
38
+
39
+ interface LabelDatum {
40
+ id: string
41
+ text: string
42
+ textArr: string[]
43
+ textWidth: number
44
+ textHeight: number
45
+ colorType: ColorType
46
+ textColorType: ColorType
47
+ x: number
48
+ y: number
49
+ rectWidth: number
50
+ rectHeight: number
51
+ rectX: number
52
+ rectY: number
53
+ textX: number
54
+ textY: number
55
+ }
56
+
57
+ const pluginName = 'ScatterPlot'
58
+ const layerName = 'XYAux'
59
+ const labelClassName = createClassName(pluginName, layerName, 'label-box')
60
+
61
+
62
+ function createLineData ({ axisX, axisY, layout, layerParams }: {
63
+ axisX: number
64
+ axisY: number
65
+ layout: Layout
66
+ layerParams: XYAuxParams
67
+ }): LineDatum[] {
68
+ if ((axisX >= 0 && axisX <= layout.width && axisY >= 0 && axisY <= layout.height) === false) {
69
+ return []
70
+ }
71
+ return [
72
+ {
73
+ id: 'line-x',
74
+ x1: axisX,
75
+ x2: axisX,
76
+ y1: 0,
77
+ y2: layout.height,
78
+ dashArray: layerParams.xAxis.lineDashArray ?? 'none',
79
+ colorType: layerParams.xAxis.lineColorType
80
+ },
81
+ {
82
+ id: 'line-0',
83
+ x1: 0,
84
+ x2: layout.width,
85
+ y1: axisY,
86
+ y2: axisY,
87
+ dashArray: layerParams.yAxis.lineDashArray ?? 'none',
88
+ colorType: layerParams.yAxis.lineColorType
89
+ }
90
+ ]
91
+ }
92
+
93
+ function createLabelData ({ axisX, axisY, xValue, yValue, layerParams, fontSizePx, layout, columnAmount, rowAmount }: {
94
+ axisX: number
95
+ axisY: number
96
+ xValue: number
97
+ yValue: number
98
+ layerParams: XYAuxParams
99
+ fontSizePx: number
100
+ layout: Layout
101
+ columnAmount: number
102
+ rowAmount: number
103
+ }): LabelDatum[] {
104
+ if ((axisX >= 0 && axisX <= layout.width && axisY >= 0 && axisY <= layout.height) === false) {
105
+ return []
106
+ }
107
+ const rectPaddingWidth = 6
108
+ const rectPaddingHeight = 3
109
+
110
+ // x
111
+ const xX = axisX
112
+ const xY = layout.height + (layerParams.xAxis.labelPadding * rowAmount) // rowAmount 是為了把外部 container 的變形逆轉回來
113
+ const xText = parseTickFormatValue(xValue, layerParams.xAxis.labelTextFormat)
114
+ const xTextArr = xText.split('\n')
115
+ const xMaxLengthText = xTextArr.reduce((acc, current) => current.length > acc.length ? current : acc, '')
116
+ const xTextWidth = measureTextWidth(xMaxLengthText, fontSizePx)
117
+ const xTextHeight = fontSizePx * xTextArr.length
118
+ const xRectWidth = xTextWidth + (rectPaddingWidth * 2)
119
+ const xRectHeight = xTextHeight + (rectPaddingHeight * 2)
120
+ const xRectX = - xRectWidth / 2
121
+ const xRectY = - rectPaddingHeight
122
+ const xTextX = xRectX + rectPaddingWidth
123
+ const xTextY = xRectY + rectPaddingHeight
124
+ // y
125
+ const yX = - (layerParams.yAxis.labelPadding * columnAmount) // columnAmount 是為了把外部 container 的變形逆轉回來
126
+ const yY = axisY
127
+ const yText = parseTickFormatValue(yValue, layerParams.yAxis.labelTextFormat)
128
+ const yTextArr = yText.split('\n')
129
+ const yMaxLengthText = yTextArr.reduce((acc, current) => current.length > acc.length ? current : acc, '')
130
+ const yTextWidth = measureTextWidth(yMaxLengthText, fontSizePx)
131
+ const yTextHeight = fontSizePx * yTextArr.length
132
+ const yRectWidth = yTextWidth + (rectPaddingWidth * 2)
133
+ const yRectHeight = yTextHeight + (rectPaddingHeight * 2)
134
+ const yRectX = - yTextWidth - rectPaddingWidth
135
+ const yRectY = - rectPaddingHeight - yTextHeight / 2
136
+ const yTextX = yRectX + rectPaddingWidth
137
+ const yTextY = yRectY + rectPaddingHeight
138
+ return [
139
+ {
140
+ id: 'label-x',
141
+ x: xX,
142
+ y: xY,
143
+ text: xText,
144
+ textArr: xTextArr,
145
+ textWidth: xTextWidth,
146
+ textHeight: xTextHeight,
147
+ colorType: layerParams.xAxis.labelColorType,
148
+ textColorType: layerParams.xAxis.labelTextColorType,
149
+ rectWidth: xRectWidth,
150
+ rectHeight: xRectHeight,
151
+ rectX: xRectX,
152
+ rectY: xRectY,
153
+ textX: xTextX,
154
+ textY: xTextY
155
+ },
156
+ {
157
+ id: 'label-y',
158
+ x: yX,
159
+ y: yY,
160
+ text: yText,
161
+ textArr: yTextArr,
162
+ textWidth: yTextWidth,
163
+ textHeight: yTextHeight,
164
+ colorType: layerParams.yAxis.labelColorType,
165
+ textColorType: layerParams.xAxis.labelTextColorType,
166
+ rectWidth: yRectWidth,
167
+ rectHeight: yRectHeight,
168
+ rectX: yRectX,
169
+ rectY: yRectY,
170
+ textX: yTextX,
171
+ textY: yTextY
172
+ }
173
+ ]
174
+ }
175
+
176
+ function renderLine ({ selection, pluginName, lineData, theme }: {
177
+ selection: d3.Selection<any, string, any, unknown>
178
+ pluginName: string
179
+ lineData: LineDatum[]
180
+ theme: Theme
181
+ }) {
182
+ const gClassName = createClassName(pluginName, layerName, 'auxline')
183
+ const auxLineSelection = selection
184
+ .selectAll<SVGLineElement, LineDatum>(`line.${gClassName}`)
185
+ .data(lineData)
186
+ .join(
187
+ enter => {
188
+ return enter
189
+ .append('line')
190
+ .classed(gClassName, true)
191
+ .style('stroke-width', 1)
192
+ .style('pointer-events', 'none')
193
+ .style('vector-effect', 'non-scaling-stroke')
194
+ .attr('x1', d => d.x1)
195
+ .attr('y1', d => d.y1)
196
+ .attr('x2', d => d.x2)
197
+ .attr('y2', d => d.y2)
198
+ },
199
+ update => {
200
+ const updateSelection = update
201
+ .transition()
202
+ .duration(50)
203
+ .attr('x1', d => d.x1)
204
+ .attr('y1', d => d.y1)
205
+ .attr('x2', d => d.x2)
206
+ .attr('y2', d => d.y2)
207
+ return updateSelection
208
+ },
209
+ exit => exit.remove()
210
+ )
211
+ .style('stroke', d => getColor(d.colorType, theme))
212
+ .style('stroke-dasharray', d => d.dashArray)
213
+
214
+ return auxLineSelection
215
+ }
216
+
217
+ function removeLine (selection: d3.Selection<any, string, any, unknown>) {
218
+ const update = selection
219
+ .selectAll<SVGLineElement, LineDatum>('line')
220
+ .data([])
221
+
222
+ update.exit().remove()
223
+ }
224
+
225
+ function renderLabel ({ selection, labelData, layerParams, theme, textReverseTransform, fontSizePx }: {
226
+ selection: d3.Selection<any, string, any, unknown>
227
+ labelData: LabelDatum[]
228
+ layerParams: XYAuxParams
229
+ theme: Theme
230
+ // gridAxesReverseTransformValue: string
231
+ textReverseTransform: string
232
+ fontSizePx: number
233
+ }) {
234
+ // const rectHeight = fontSizePx + 6
235
+
236
+ const axisLabelSelection = selection
237
+ .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
238
+ .data(labelData)
239
+ .join(
240
+ enter => {
241
+ return enter
242
+ .append('g')
243
+ .classed(labelClassName, true)
244
+ .style('cursor', 'pointer')
245
+ .attr("transform", (d, i) => {
246
+ return `translate(${d.x}, ${d.y})`
247
+ })
248
+ },
249
+ update => {
250
+ const updateSelection = update
251
+ .transition()
252
+ .duration(50)
253
+ .attr("transform", (d, i) => {
254
+ return `translate(${d.x}, ${d.y})`
255
+ })
256
+ return updateSelection
257
+ },
258
+ exit => exit.remove()
259
+ )
260
+ .each((datum, i, n) => {
261
+ // // const rectWidth = measureTextWidth(datum.text, fontSizePx) + 12
262
+ // const rectWidth = datum.textWidth + 12
263
+ // const rectHeight = datum.textHeight + 6
264
+ // // -- label偏移位置 --
265
+ // let rectX = - rectWidth / 2
266
+ // let rectY = 2
267
+
268
+ // -- rect --
269
+ d3.select(n[i])
270
+ .selectAll<SVGRectElement, LabelDatum>('rect')
271
+ .data([datum])
272
+ .join(
273
+ enter => enter.append('rect')
274
+ .style('cursor', 'pointer')
275
+ .attr('rx', 5)
276
+ .attr('ry', 5),
277
+ update => update,
278
+ exit => exit.remove()
279
+ )
280
+ .attr('width', d => `${d.rectWidth}px`)
281
+ .attr('height', d => `${d.rectHeight}px`)
282
+ .attr('fill', d => getColor(d.colorType, theme))
283
+ .attr('x', d => d.rectX)
284
+ .attr('y', d => d.rectY)
285
+ .style('transform', textReverseTransform)
286
+
287
+ // -- text --
288
+ d3.select(n[i])
289
+ .selectAll<SVGTextElement, LabelDatum>('text')
290
+ .data([datum])
291
+ .join(
292
+ enter => enter.append('text')
293
+ .style('dominant-baseline', 'hanging')
294
+ .style('cursor', 'pointer')
295
+ .style('pointer-events', 'none'),
296
+ update => update,
297
+ exit => exit.remove()
298
+ )
299
+ .style('transform', textReverseTransform)
300
+ .attr('fill', d => getColor(d.textColorType, theme))
301
+ .attr('font-size', theme.fontSize)
302
+ .attr('x', d => d.textX)
303
+ .attr('y', d => d.textY)
304
+ .each((d, i, n) => {
305
+ renderTspansOnAxis(d3.select(n[i]), {
306
+ textArr: datum.textArr,
307
+ textSizePx: fontSizePx,
308
+ categoryAxisPosition: i === 0
309
+ ? 'bottom' // x axis
310
+ : 'left', // y axis
311
+ isContainerRotated: false
312
+ })
313
+ })
314
+ })
315
+
316
+ return axisLabelSelection
317
+ }
318
+
319
+ function removeLabel (selection: d3.Selection<any, string, any, unknown>) {
320
+ const gUpdate = selection
321
+ .selectAll<SVGGElement, LabelDatum>(`g.${labelClassName}`)
322
+ .data([])
323
+
324
+ gUpdate.exit().remove()
325
+ }
326
+
327
+ export const XYAux = defineSVGLayer<ScatterPlotExtendContext, ScatterPlotPluginParams, XYAuxParams>({
328
+ name: layerName,
329
+ defaultParams: DEFAULT_X_Y_AUX_PARAMS,
330
+ layerIndex: LAYER_INDEX_OF_AUX,
331
+ initShow: true,
332
+ validator: (params) => {
333
+ const result = validateObject(params, {
334
+ xAxis: {
335
+ toBeTypes: ['object']
336
+ },
337
+ yAxis: {
338
+ toBeTypes: ['object']
339
+ }
340
+ })
341
+ if (params.xAxis) {
342
+ const forceResult = validateObject(params.xAxis, {
343
+ showLine: {
344
+ toBeTypes: ['boolean']
345
+ },
346
+ showLabel: {
347
+ toBeTypes: ['boolean']
348
+ },
349
+ lineDashArray: {
350
+ toBeTypes: ['string']
351
+ },
352
+ lineColorType: {
353
+ toBeOption: 'ColorType'
354
+ },
355
+ labelColorType: {
356
+ toBeOption: 'ColorType'
357
+ },
358
+ labelTextColorType: {
359
+ toBeOption: 'ColorType'
360
+ },
361
+ labelTextFormat: {
362
+ toBeTypes: ['string', 'Function']
363
+ },
364
+ labelPadding: {
365
+ toBeTypes: ['number']
366
+ },
367
+ })
368
+ if (forceResult.status === 'error') {
369
+ return forceResult
370
+ }
371
+ }
372
+ if (params.yAxis) {
373
+ const forceResult = validateObject(params.yAxis, {
374
+ showLine: {
375
+ toBeTypes: ['boolean']
376
+ },
377
+ showLabel: {
378
+ toBeTypes: ['boolean']
379
+ },
380
+ lineDashArray: {
381
+ toBeTypes: ['string']
382
+ },
383
+ lineColorType: {
384
+ toBeOption: 'ColorType'
385
+ },
386
+ labelColorType: {
387
+ toBeOption: 'ColorType'
388
+ },
389
+ labelTextColorType: {
390
+ toBeOption: 'ColorType'
391
+ },
392
+ labelTextFormat: {
393
+ toBeTypes: ['string', 'Function']
394
+ },
395
+ labelPadding: {
396
+ toBeTypes: ['number']
397
+ },
398
+ })
399
+ if (forceResult.status === 'error') {
400
+ return forceResult
401
+ }
402
+ }
403
+ return result
404
+ },
405
+ setup: ({ svgG, pluginParams$, layerParams$, context }) => {
406
+
407
+ const destroy$ = new Subject()
408
+
409
+ context.layout$
410
+ .pipe(
411
+ takeUntil(destroy$)
412
+ )
413
+ .subscribe(layout => {
414
+ d3.select(svgG)
415
+ .attr('transform', `translate(${layout.left}, ${layout.top})`)
416
+ })
417
+
418
+ let isLabelMouseover: boolean = false
419
+
420
+ const rootSelection = d3.select(context.svg)
421
+
422
+ const rootRectSelection: d3.Selection<SVGRectElement, any, any, any> = rootSelection
423
+ .insert('rect', 'g')
424
+ .classed(createClassName(pluginName, layerName, 'rect'), true)
425
+ .attr('opacity', 0)
426
+
427
+ // const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
428
+ // .append('g')
429
+
430
+ const {
431
+ seriesSelection$,
432
+ axesSelection$,
433
+ defsSelection$,
434
+ graphicGSelection$
435
+ } = multivariateSelectionsObservable({
436
+ selection: d3.select(svgG),
437
+ pluginName,
438
+ layerName,
439
+ clipPathID: 'XYAuxClipPath',
440
+ seriesLabels$: context.isSeriesSeprate$.pipe(
441
+ switchMap(isSeriesSeprate => {
442
+ return iif(
443
+ () => isSeriesSeprate,
444
+ context.seriesLabels$,
445
+ // 如果沒分開的話只取一筆
446
+ context.seriesLabels$.pipe(
447
+ map(d => [d[0]])
448
+ )
449
+ )
450
+ })
451
+ ),
452
+ containerPosition$: context.containerPosition$,
453
+ graphicTransform$: context.graphicTransform$
454
+ })
455
+
456
+ context.layout$.pipe(
457
+ takeUntil(destroy$),
458
+ ).subscribe(d => {
459
+ rootRectSelection
460
+ .attr('width', d.rootWidth)
461
+ .attr('height', d.rootHeight)
462
+ })
463
+
464
+ // const highlightTarget$ = context.fullChartParams$.pipe(
465
+ // takeUntil(destroy$),
466
+ // map(d => d.highlightTarget),
467
+ // distinctUntilChanged()
468
+ // )
469
+
470
+ // const rootMousemove$: Observable<any> = d3EventObservable(rootSelection, 'mousemove')
471
+ // .pipe(
472
+ // takeUntil(destroy$),
473
+ // debounceTime(10)
474
+ // )
475
+
476
+ // let r = 0
477
+ // rootMousemove$.subscribe(d => {
478
+ // r++
479
+ // console.log('r:', r)
480
+ // })
481
+
482
+ const columnAmount$ = context.containerPosition$.pipe(
483
+ map(containerPosition => {
484
+ const maxColumnIndex = containerPosition.reduce((acc, current) => {
485
+ return current.columnIndex > acc ? current.columnIndex : acc
486
+ }, 0)
487
+ return maxColumnIndex + 1
488
+ }),
489
+ distinctUntilChanged()
490
+ )
491
+
492
+ const rowAmount$ = context.containerPosition$.pipe(
493
+ map(containerPosition => {
494
+ const maxRowIndex = containerPosition.reduce((acc, current) => {
495
+ return current.rowIndex > acc ? current.rowIndex : acc
496
+ }, 0)
497
+ return maxRowIndex + 1
498
+ }),
499
+ distinctUntilChanged()
500
+ )
501
+
502
+ const textReverseTransform$ = context.containerPosition$.pipe(
503
+ takeUntil(destroy$),
504
+ debounceTime(0),
505
+ map(containerPosition => {
506
+ // const axesRotateXYReverseValue = `rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
507
+ // const axesRotateReverseValue = `rotate(${data.gridAxesReverseTransform.rotate}deg)`
508
+ const containerScaleReverseValue = `scale(${1 / containerPosition[0].scale[0]}, ${1 / containerPosition[0].scale[1]})`
509
+ // 抵消最外層scale
510
+ return `${containerScaleReverseValue}`
511
+ }),
512
+ distinctUntilChanged()
513
+ )
514
+
515
+ const xyPosition$ = multivariateXYPositionObservable({
516
+ rootSelection,
517
+ xAxis$: context.zoomedXAxis$,
518
+ yAxis$: context.yAxis$,
519
+ xyValueIndex$: context.xyValueIndex$,
520
+ filteredXYMinMaxData$: context.filteredXYMinMaxData$,
521
+ containerPosition$: context.containerPosition$,
522
+ containerSize$: context.containerSize$,
523
+ layout$: context.layout$
524
+ }).pipe(
525
+ takeUntil(destroy$)
526
+ )
527
+
528
+ combineLatest({
529
+ axesSelection: axesSelection$,
530
+ // rootMousemove: rootMousemove$,
531
+ layout: context.layout$,
532
+ xyPosition: xyPosition$,
533
+ // computedData: context.computedData$,
534
+ layerParams: layerParams$,
535
+ theme: context.theme$,
536
+ // highlightTarget: highlightTarget$,
537
+ textReverseTransform: textReverseTransform$,
538
+ // CategoryDataMap: context.CategoryDataMap$,
539
+ fontSizePx: context.fontSizePx$,
540
+ columnAmount: columnAmount$,
541
+ rowAmount: rowAmount$
542
+ }).pipe(
543
+ takeUntil(destroy$),
544
+ debounceTime(0),
545
+ ).subscribe(data => {
546
+ // 依event的座標取得group資料
547
+ const { x, y, xValue, yValue } = data.xyPosition
548
+
549
+ const lineData = createLineData({
550
+ axisX: x,
551
+ axisY: y,
552
+ layout: data.layout,
553
+ layerParams: data.layerParams,
554
+ })
555
+ renderLine({
556
+ selection: data.axesSelection,
557
+ pluginName,
558
+ lineData,
559
+ theme: data.theme
560
+ })
561
+ const labelData = createLabelData({
562
+ axisX: x,
563
+ axisY: y,
564
+ xValue,
565
+ yValue,
566
+ layerParams: data.layerParams,
567
+ fontSizePx: data.fontSizePx,
568
+ layout: data.layout,
569
+ columnAmount: data.columnAmount,
570
+ rowAmount: data.rowAmount
571
+ })
572
+ const labelSelection = renderLabel({
573
+ selection: data.axesSelection,
574
+ labelData,
575
+ layerParams: data.layerParams,
576
+ theme: data.theme,
577
+ textReverseTransform: data.textReverseTransform,
578
+ fontSizePx: data.fontSizePx
579
+ })
580
+
581
+ // label的事件
582
+ // labelSelection
583
+ // .on('mouseover', (event, datum) => {
584
+ // event.stopPropagation()
585
+ // // const { groupIndex, groupLabel } = data.xyPositionFn(event)
586
+
587
+ // isLabelMouseover = true
588
+
589
+ // subject.event$.next({
590
+ // type: 'multivariate',
591
+ // eventName: 'mouseover',
592
+ // pluginName,
593
+ // highlightTarget: data.highlightTarget,
594
+ // datum,
595
+ // category: [],
596
+ // categoryIndex: -1,
597
+ // categoryLabel: '',
598
+ // data: data.computedData,
599
+ // event,
600
+ // })
601
+ // })
602
+ // .on('mousemove', (event, datum) => {
603
+ // event.stopPropagation()
604
+ // // const { groupIndex, groupLabel } = data.xyPositionFn(event)
605
+
606
+ // subject.event$.next({
607
+ // type: 'multivariate',
608
+ // eventName: 'mousemove',
609
+ // pluginName,
610
+ // highlightTarget: data.highlightTarget,
611
+ // datum,
612
+ // category: [],
613
+ // categoryIndex: -1,
614
+ // categoryLabel: '',
615
+ // data: data.computedData,
616
+ // event,
617
+ // })
618
+ // })
619
+ // .on('mouseout', (event, datum) => {
620
+ // event.stopPropagation()
621
+ // // const { groupIndex, groupLabel } = data.xyPositionFn(event)
622
+
623
+ // isLabelMouseover = false
624
+
625
+ // subject.event$.next({
626
+ // type: 'multivariate',
627
+ // eventName: 'mouseout',
628
+ // pluginName,
629
+ // highlightTarget: data.highlightTarget,
630
+ // datum,
631
+ // category: [],
632
+ // categoryIndex: -1,
633
+ // categoryLabel: '',
634
+ // data: data.computedData,
635
+ // event,
636
+ // })
637
+ // })
638
+ // .on('click', (event, datum) => {
639
+ // event.stopPropagation()
640
+ // // const { groupIndex, groupLabel } = data.xyPositionFn(event)
641
+
642
+ // subject.event$.next({
643
+ // type: 'multivariate',
644
+ // eventName: 'click',
645
+ // pluginName,
646
+ // highlightTarget: data.highlightTarget,
647
+ // datum,
648
+ // category: [],
649
+ // categoryIndex: -1,
650
+ // categoryLabel: '',
651
+ // data: data.computedData,
652
+ // event,
653
+ // })
654
+ // })
655
+
656
+ })
657
+
658
+
659
+ const rootRectMouseout$ = d3EventObservable(rootRectSelection, 'mouseout').pipe(
660
+ takeUntil(destroy$),
661
+ )
662
+
663
+ combineLatest({
664
+ rootRectMouseout: rootRectMouseout$,
665
+ axesSelection: axesSelection$,
666
+ }).pipe(
667
+ takeUntil(destroy$),
668
+ debounceTime(0)
669
+ ).subscribe(data => {
670
+ setTimeout(() => {
671
+ // // @Q@ workaround - 不知為何和 label 會有衝突,當滑鼠移動到 label 上時,會觸發 mouseout 事件
672
+ // if (isLabelMouseover == true) {
673
+ // return
674
+ // }
675
+
676
+ removeLine(data.axesSelection)
677
+ removeLabel(data.axesSelection)
678
+ })
679
+ })
680
+
681
+ return () => {
682
+ destroy$.next(undefined)
683
+ rootRectSelection.remove()
684
+ }
685
+ }
686
+ })