@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,357 @@
1
+ import * as d3 from 'd3'
2
+ // import { Observable, merge, distinctUntilChanged, fromEvent } from 'rxjs'
3
+ import {
4
+ combineLatest,
5
+ distinctUntilChanged,
6
+ filter,
7
+ fromEvent,
8
+ map,
9
+ merge,
10
+ takeUntil,
11
+ shareReplay,
12
+ switchMap,
13
+ Subject,
14
+ Observable,
15
+ debounceTime
16
+ } from 'rxjs'
17
+ import type {
18
+ ModelType,
19
+ Theme,
20
+ ModelDatum
21
+ } from '@orbcharts/core'
22
+ import type {
23
+ ComputedDatum
24
+ } from '../types/ComputedData'
25
+ import type {
26
+ EventData
27
+ } from '@orbcharts/core'
28
+ import type {
29
+ Layout,
30
+ Padding,
31
+ GraphicStyles,
32
+ ContainerPositionScaled,
33
+ HighlightTarget,
34
+ Container
35
+ } from '../types/PluginParams'
36
+
37
+ // interface DatumUnknown {
38
+ // value: number | null
39
+ // id: string
40
+ // // label: string
41
+ // seriesLabel?: string // 要符合每一種computedData所以不一定會有seriesLabel
42
+ // groupLabel?: string // 要符合每一種computedData所以不一定會有groupLabel
43
+ // }
44
+
45
+ export function d3EventObservable(selection: d3.Selection<any, any, any, any>, event: any) {
46
+ // Start with an observable that will never emit
47
+ let obs: Observable<MouseEvent> = new Observable(() => {});
48
+ selection.each(function () {
49
+ // Create observables from each of the elements
50
+ const events: Observable<MouseEvent> = fromEvent(this, event);
51
+ // Merge the observables into one
52
+ obs = merge(obs, events);
53
+ });
54
+ return obs;
55
+ }
56
+
57
+ export function resizeObservable(elem: HTMLElement | Element): Observable<DOMRectReadOnly> {
58
+ return new Observable(subscriber => {
59
+ const ro = new ResizeObserver(entries => {
60
+ const entry = entries[0]
61
+ if (entry && entry.contentRect) {
62
+ subscriber.next(entry.contentRect)
63
+ }
64
+ })
65
+
66
+ ro.observe(elem)
67
+ return function unsubscribe() {
68
+ ro.unobserve(elem)
69
+ }
70
+ })
71
+ }
72
+
73
+ export function layoutObservable({size$, padding$}: {size$: Observable<{ width: number, height: number }>, padding$: Observable<Padding>}): Observable<Layout> {
74
+ return combineLatest({
75
+ size: size$,
76
+ padding: padding$
77
+ }).pipe(
78
+ debounceTime(0),
79
+ map(data => {
80
+ const width = data.size.width - data.padding.left - data.padding.right
81
+ const height = data.size.height - data.padding.top - data.padding.bottom
82
+ const layout: Layout = {
83
+ rootWidth: data.size.width,
84
+ rootHeight: data.size.height,
85
+ width: width > 0 ? width : 0,
86
+ height: height > 0 ? height : 0,
87
+ left: data.padding.left,
88
+ right: data.padding.right,
89
+ top: data.padding.top,
90
+ bottom: data.padding.bottom
91
+ }
92
+ return layout
93
+ }),
94
+ distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),
95
+ shareReplay(1)
96
+ )
97
+ }
98
+
99
+ interface HighlightTargetValue {
100
+ id: string | null
101
+ label: string | null
102
+ series: string | null
103
+ // group: string | null
104
+ category: string | null
105
+ // highlightDefault: string | null
106
+ }
107
+
108
+ // 通用 highlight Observable
109
+ export const highlightObservable = <T extends ModelType, D>({ datumList$, styles$, event$ }: {
110
+ datumList$: Observable<D[]>
111
+ styles$: Observable<GraphicStyles>
112
+ event$: Observable<EventData<T>>
113
+ }): Observable<D[]> => {
114
+ const destroy$ = new Subject()
115
+
116
+ // 預設的highlight
117
+ const highlightDefault$: Observable<HighlightTargetValue> = styles$.pipe(
118
+ takeUntil(destroy$),
119
+ map(d => d.highlightDefault || null),
120
+ distinctUntilChanged(),
121
+ map(highlightDefault => {
122
+ return {
123
+ id: highlightDefault,
124
+ label: highlightDefault,
125
+ series: highlightDefault,
126
+ category: highlightDefault,
127
+ // highlightDefault
128
+ } as HighlightTargetValue
129
+ }),
130
+ shareReplay(1)
131
+ )
132
+
133
+ const highlightTarget$: Observable<HighlightTarget> = styles$.pipe(
134
+ takeUntil(destroy$),
135
+ map(d => d.highlightTarget),
136
+ distinctUntilChanged(),
137
+ shareReplay(1)
138
+ )
139
+
140
+ // 事件觸發的highlight
141
+ const highlightMouseover$: Observable<HighlightTargetValue> = highlightTarget$.pipe(
142
+ switchMap(highlightTarget => {
143
+ return event$.pipe(
144
+ takeUntil(destroy$),
145
+ // filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove'),
146
+ filter(d => d.eventName === 'mouseover'),
147
+ // distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
148
+ map(d => {
149
+
150
+ // const d = _d as any
151
+ // console.log('mouseover event', d)
152
+ return d.target
153
+ ? {
154
+ id: d.target.id,
155
+ label: null, // label有可能重覆所以不做判斷
156
+ series: highlightTarget === 'series' ? d.target.series : null,
157
+ category: highlightTarget === 'category' ? (d.target as ModelDatum<'grid' | 'multivariate' | 'graph' | 'tree'>).category : null,
158
+ // highlightDefault: null
159
+ } as HighlightTargetValue
160
+ : {
161
+ id: null,
162
+ label: null,
163
+ series: null,
164
+ // group: null,
165
+ category: null,
166
+ // highlightDefault: null
167
+ } as HighlightTargetValue
168
+ })
169
+ )
170
+ })
171
+ )
172
+
173
+ const highlightMouseout$ = event$.pipe(
174
+ takeUntil(destroy$),
175
+ filter(d => d.eventName === 'mouseout'),
176
+ // distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
177
+ // map(d => {
178
+ // return { id: '', label: '' }
179
+ // })
180
+ switchMap(d => highlightDefault$)
181
+ )
182
+
183
+ // function getDatumIds (datumList: ComputedDatum<T>[], id: string | null) {
184
+ // const datum = datumList.find(d => (d as ComputedDatumBase).id === id)
185
+ // return datum ? [datum] : []
186
+ // }
187
+ function getDatumIds (datumList: ComputedDatum<T>[], id: string | null, label: string | null) {
188
+ return id == null && label == null
189
+ ? []
190
+ : datumList.filter(d => d.id === id || d.name === label)
191
+ }
192
+
193
+ function getSeriesIds (datumList: ComputedDatum<T>[], seriesLabel: string | null) {
194
+ return seriesLabel == null
195
+ ? []
196
+ : datumList.filter(d => (d as ComputedDatum<"series">).series === seriesLabel)
197
+ }
198
+
199
+ // function getGroupIds (datumList: ComputedDatum<T>[], groupLabel: string | null) {
200
+ // return groupLabel == null
201
+ // ? []
202
+ // : datumList.filter(d => (d as ComputedDatum<"grid">).category === groupLabel)
203
+ // }
204
+
205
+ function getCategoryIds (datumList: ComputedDatum<T>[], category: string | null) {
206
+ return category == null
207
+ ? []
208
+ : datumList.filter(d => (d as ComputedDatum<"multivariate" | "graph" | "tree">).category === category)
209
+ }
210
+
211
+ return new Observable<D[]>(subscriber => {
212
+ combineLatest({
213
+ target: merge(highlightMouseover$, highlightMouseout$, highlightDefault$),
214
+ datumList: datumList$,
215
+ styles: styles$,
216
+ }).pipe(
217
+ takeUntil(destroy$),
218
+ debounceTime(0),
219
+ ).subscribe(data => {
220
+ let datumList: ComputedDatum<T>[] = []
221
+ if (data.styles.highlightTarget === 'datum') {
222
+ datumList = getDatumIds(data.datumList as ComputedDatum<T>[], data.target.id, data.target.label)
223
+ } else if (data.styles.highlightTarget === 'series') {
224
+ datumList = getSeriesIds(data.datumList as ComputedDatum<T>[], data.target.series)
225
+ // } else if (data.styles.highlightTarget === 'group') {
226
+ // datumList = getGroupIds(data.datumList as ComputedDatum<T>[], data.target.group)
227
+ } else if (data.styles.highlightTarget === 'category') {
228
+ datumList = getCategoryIds(data.datumList as ComputedDatum<T>[], data.target.category)
229
+ }
230
+ subscriber.next(datumList as D[])
231
+ })
232
+
233
+ return function unsubscribe () {
234
+ destroy$.next(undefined)
235
+ }
236
+ })
237
+ }
238
+
239
+ export const seriesDataMapObservable = <DatumType extends ComputedDatum<'series' | 'grid'>>({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
240
+ return datumList$.pipe(
241
+ map(data => {
242
+ const SeriesDataMap: Map<string, DatumType[]> = new Map()
243
+ data.forEach(d => {
244
+ const seriesData = SeriesDataMap.get(d.series) ?? []
245
+ seriesData.push(d)
246
+ SeriesDataMap.set(d.series, seriesData)
247
+ })
248
+ return SeriesDataMap
249
+ })
250
+ )
251
+ }
252
+
253
+ // export const groupDataMapObservable = <DatumType extends ComputedDatum<'grid'>> ({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
254
+ // return datumList$.pipe(
255
+ // map(data => {
256
+ // const GroupDataMap: Map<string, DatumType[]> = new Map()
257
+ // data.forEach(d => {
258
+ // const groupData = GroupDataMap.get(d.category) ?? []
259
+ // groupData.push(d)
260
+ // GroupDataMap.set(d.category, groupData)
261
+ // })
262
+ // return GroupDataMap
263
+ // })
264
+ // )
265
+ // }
266
+
267
+ export const categoryDataMapObservable = <DatumType extends ComputedDatum<'multivariate' | 'graph' | 'tree'>> ({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
268
+ return datumList$.pipe(
269
+ map(data => {
270
+ const GroupDataMap: Map<string, DatumType[]> = new Map()
271
+ data
272
+ .filter(d => d.category != null)
273
+ .forEach(d => {
274
+ const groupData = GroupDataMap.get(d.category) ?? []
275
+ groupData.push(d)
276
+ GroupDataMap.set(d.category, groupData)
277
+ })
278
+ return GroupDataMap
279
+ })
280
+ )
281
+ }
282
+
283
+ export const fontSizePxObservable = (chartParams$: Observable<Theme>) => {
284
+ return chartParams$.pipe(
285
+ map(d => d.fontSize),
286
+ distinctUntilChanged(),
287
+ map(data => {
288
+ let value = NaN
289
+ if (typeof data === 'string') {
290
+ if (data.includes('rem')) {
291
+ const rootFontSizePx = parseFloat(getComputedStyle(document.documentElement).fontSize)
292
+ const num = parseFloat(data)
293
+ value = num * rootFontSizePx
294
+ } else if (data.includes('px')) {
295
+ value = parseFloat(data)
296
+ }
297
+ } else if (typeof data === 'number') {
298
+ return data
299
+ }
300
+ return value ? value : 14 // default
301
+ })
302
+ )
303
+ }
304
+
305
+ export const containerSizeObservable = ({ layout$, containerPosition$, container$ }: {
306
+ layout$: Observable<Layout>
307
+ containerPosition$: Observable<ContainerPositionScaled[]>
308
+ container$: Observable<Container>
309
+ }) => {
310
+ const rowAmount$ = containerPosition$.pipe(
311
+ map(containerPosition => {
312
+ const maxRowIndex = containerPosition.reduce((acc, current) => {
313
+ return current.rowIndex > acc ? current.rowIndex : acc
314
+ }, 0)
315
+ return maxRowIndex + 1
316
+ }),
317
+ distinctUntilChanged(),
318
+ )
319
+
320
+ const columnAmount$ = containerPosition$.pipe(
321
+ map(containerPosition => {
322
+ const maxColumnIndex = containerPosition.reduce((acc, current) => {
323
+ return current.columnIndex > acc ? current.columnIndex : acc
324
+ }, 0)
325
+ return maxColumnIndex + 1
326
+ }),
327
+ distinctUntilChanged()
328
+ )
329
+
330
+ return combineLatest({
331
+ layout: layout$,
332
+ rowAmount: rowAmount$,
333
+ columnAmount: columnAmount$,
334
+ container: container$
335
+ }).pipe(
336
+ debounceTime(0),
337
+ map(data => {
338
+ // const width = (data.layout.rootWidth / data.columnAmount) - (data.layout.left + data.layout.right)
339
+ // const height = (data.layout.rootHeight / data.rowAmount) - (data.layout.top + data.layout.bottom)
340
+ const columnGap = data.container.columnGap === 'auto'
341
+ ? data.layout.left + data.layout.right
342
+ : data.container.columnGap
343
+ const rowGap = data.container.rowGap === 'auto'
344
+ ? data.layout.top + data.layout.bottom
345
+ : data.container.rowGap
346
+ const width = (data.layout.rootWidth - data.layout.left - data.layout.right - (columnGap * (data.columnAmount - 1))) / data.columnAmount
347
+ const height = (data.layout.rootHeight - data.layout.top - data.layout.bottom - (rowGap * (data.rowAmount - 1))) / data.rowAmount
348
+
349
+ return {
350
+ width,
351
+ height
352
+ }
353
+ }),
354
+ distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height),
355
+ // shareReplay(1)
356
+ )
357
+ }
@@ -0,0 +1,335 @@
1
+ import type {
2
+ // AxisPosition,
3
+ ColorType,
4
+ Theme,
5
+ ModelDatum,
6
+ ModelDatumBase,
7
+ ModelDatumSeries,
8
+ ModelType,
9
+
10
+ // ChartParams,
11
+ // ComputedDatumBase,
12
+ // ComputedDatumBaseValue,
13
+ // ComputedDatumBaseSeries,
14
+ // ComputedDatumBaseCategory
15
+ } from '@orbcharts/core'
16
+ import { Layout, Container, ContainerPosition, ContainerPositionScaled } from '../types/PluginParams'
17
+ import { getMinMax } from './commonUtils'
18
+ import { isLightColor } from './d3Utils'
19
+ import { createLayerClassName } from '@orbcharts/core'
20
+ import type { AxisPosition } from '../types/PluginParams'
21
+ import type { ComputedDatum } from '../types/ComputedData'
22
+
23
+ // 取得最小及最大值 - datum格式陣列資料
24
+ export function getMinMaxValue<T extends ModelType> (data: ComputedDatum<T>[]): [number, number] {
25
+ const arr = data
26
+ .filter(d => d.value != null && d.visible != false)
27
+ .map(d => d.value as number)
28
+ return getMinMax(arr)
29
+ }
30
+
31
+ // // 取得最小及最大值 - Series Data
32
+ // export function getMinMaxSeries (data: ModelDatum<'series'>[][]): [number, number] {
33
+ // const flatData: ModelDatum<'series'>[] = data[0] && Array.isArray((data as (DataSeriesValue | DataSeriesDatum)[][])[0])
34
+ // ? data.flat()
35
+ // : data as (DataSeriesValue | DataSeriesDatum)[]
36
+ // const arr = flatData
37
+ // .filter(d => (d == null || (isPlainObject(d) && (d as DataSeriesDatum).value == null)) === false) // 過濾掉null &
38
+ // .map(d => typeof d === 'number' ? d : d.value )
39
+ // return getMinMax(arr)
40
+ // }
41
+
42
+ // // 取得最小及最大值 - Grid Data
43
+ // export function getMinMaxGrid (data: DataGrid): [number, number] {
44
+ // const flatData: (DataGridValue | DataGridDatum)[] = data.flat()
45
+ // const arr = flatData
46
+ // .filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
47
+ // .map(d => typeof d === 'number' ? d : d.value )
48
+ // return getMinMax(arr)
49
+ // }
50
+
51
+ // // 取得最小及最大值 - MultiGrid Data
52
+ // export function getMinMaxMultiGrid (data: DataMultiGrid): [number, number] {
53
+ // const flatData: (DataGridValue | DataGridDatum)[] = data.flat().flat()
54
+ // const arr = flatData
55
+ // .filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
56
+ // .map(d => typeof d === 'number' ? d : d.value )
57
+ // return getMinMax(arr)
58
+ // }
59
+
60
+ // // 取得最小及最大值 - MultiValue Data
61
+ // export function getMinMaxMultiValue (data: DataMultiValue, valueIndex: number): [number, number] {
62
+ // const arr: number[] = data
63
+ // .map(d => {
64
+ // if (Array.isArray(d)) {
65
+ // return d[valueIndex] ?? null
66
+ // } else if (isPlainObject(d)) {
67
+ // return (d as DataMultiValueDatum).value[valueIndex] ?? null
68
+ // } else {
69
+ // return null
70
+ // }
71
+ // })
72
+ // .filter(d => d != null)
73
+ // return getMinMax(arr)
74
+ // }
75
+
76
+ // export function getMinMaxMultiValueXY ({ data, minX, maxX, minY, maxY }: {
77
+ // data: ComputedXYDatumMultiValue[][]
78
+ // minX: number
79
+ // maxX: number
80
+ // minY: number
81
+ // maxY: number
82
+ // }) {
83
+ // let filteredData: ComputedXYDatumMultiValue[][] = []
84
+ // let minXDatum: ComputedXYDatumMultiValue | null = null
85
+ // let maxXDatum: ComputedXYDatumMultiValue | null = null
86
+ // let minYDatum: ComputedXYDatumMultiValue | null = null
87
+ // let maxYDatum: ComputedXYDatumMultiValue | null = null
88
+
89
+ // for (let categoryData of data) {
90
+ // for (let datum of categoryData) {
91
+ // if (datum.axisX >= minX && datum.axisX <= maxX && datum.axisY >= minY && datum.axisY <= maxY) {
92
+ // filteredData.push(categoryData)
93
+ // if (minXDatum == null || datum.axisX < minXDatum.axisX) {
94
+ // minXDatum = datum
95
+ // }
96
+ // if (maxXDatum == null || datum.axisX > maxXDatum.axisX) {
97
+ // maxXDatum = datum
98
+ // }
99
+ // if (minYDatum == null || datum.axisY < minYDatum.axisY) {
100
+ // minYDatum = datum
101
+ // }
102
+ // if (maxYDatum == null || datum.axisY > maxYDatum.axisY) {
103
+ // maxYDatum = datum
104
+ // }
105
+ // }
106
+ // }
107
+ // }
108
+
109
+ // return {
110
+ // minXDatum,
111
+ // maxXDatum,
112
+ // minYDatum,
113
+ // maxYDatum,
114
+ // filteredData
115
+ // }
116
+ // }
117
+
118
+ export function getColorScheme (themeColorScheme: 'light' | 'dark' | 'auto') {
119
+ if (themeColorScheme === 'auto') {
120
+ const MediaQueryList = window.matchMedia('(prefers-color-scheme: dark)')
121
+ return MediaQueryList.matches ? 'dark' : 'light'
122
+ } else {
123
+ return themeColorScheme
124
+ }
125
+ }
126
+
127
+ // 取得colorType顏色
128
+ export function getColor (colorType: ColorType, theme: Theme) {
129
+ const colorScheme = getColorScheme(theme.colorScheme)
130
+ const colors = theme.colors[colorScheme]
131
+ if (colorType === 'data') {
132
+ return colors.data[0] // default label color
133
+ } else if (colorType === 'dataContrast') {
134
+ return isLightColor(colors.data[0]) // default label color
135
+ ? colors.dataContrast[1]
136
+ : colors.dataContrast[0]
137
+ }
138
+ return colorType == 'none'
139
+ ? 'none'
140
+ : colors[colorType] != undefined
141
+ ? colors[colorType]
142
+ : colors.primary // 如果比對不到
143
+ }
144
+
145
+ // export function getSeriesValueColor () {
146
+
147
+ // }
148
+
149
+ // export function getCategoryValueColor ({ datum, colorType, fullChartParams }: { datum: ComputedDatumBaseCategory, colorType: ColorType, fullChartParams: ChartParams }) {
150
+
151
+ // }
152
+
153
+ // // 取得Series顏色
154
+ // export function getSeriesColor (seriesIndex: number, fullChartParams: ChartParams) {
155
+ // const colorIndex = seriesIndex < fullChartParams.colors[fullChartParams.colorScheme].series.length
156
+ // ? seriesIndex
157
+ // : seriesIndex % fullChartParams.colors[fullChartParams.colorScheme].series.length
158
+ // return fullChartParams.colors[fullChartParams.colorScheme].series[colorIndex]
159
+ // }
160
+
161
+ // 取得Datum顏色
162
+ export function getDatumColor ({ datum, colorType, theme }: { datum: ModelDatumBase, colorType: ColorType, theme: Theme }) {
163
+ const colors = theme.colors[getColorScheme(theme.colorScheme)]
164
+
165
+ if (colorType === 'data') {
166
+ const datumColor: string | undefined = (datum as unknown as ModelDatumSeries).color
167
+ if (datumColor) {
168
+ return datumColor
169
+ } else {
170
+ // default label color
171
+ return colors.data[0]
172
+ }
173
+ } else if (colorType === 'dataContrast') {
174
+ const datumColor: string | undefined = (datum as unknown as ModelDatumSeries).color
175
+ if (datumColor) {
176
+ return isLightColor(datumColor)
177
+ ? colors.dataContrast[1]
178
+ : colors.dataContrast[0]
179
+ } else {
180
+ // default label color
181
+ return isLightColor(colors.data[0])
182
+ ? colors.dataContrast[1]
183
+ : colors.dataContrast[0]
184
+ }
185
+ }
186
+ // 對應colorType設定的顏色
187
+ return colorType == 'none'
188
+ ? 'none'
189
+ : colors[colorType] != undefined
190
+ ? colors[colorType]
191
+ : colors.primary
192
+ }
193
+
194
+ export function seriesColorPredicate (seriesIndex: number, theme: Theme) {
195
+ const colorScheme = getColorScheme(theme.colorScheme)
196
+ return seriesIndex < theme.colors[colorScheme].data.length
197
+ ? theme.colors[colorScheme].data[seriesIndex]
198
+ : theme.colors[colorScheme].data[
199
+ seriesIndex % theme.colors[colorScheme].data.length
200
+ ]
201
+ }
202
+
203
+ export function createClassName (pluginName: string, layerName: string, elementName: string, modifier?: string) {
204
+ const modifierText = modifier ? `--${modifier}` : ''
205
+ return `${createLayerClassName(pluginName, layerName)}__${elementName}${modifierText}`
206
+ }
207
+
208
+ export function createUniID (pluginName: string, layerName: string, elementName: string) {
209
+ const textLength = 5
210
+ // 英文+數字
211
+ const randomText: string = Math.random().toString(36).substr(2, textLength)
212
+
213
+ return createClassName(pluginName, layerName, elementName, randomText)
214
+ }
215
+
216
+
217
+ export function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
218
+ xAxisPosition: AxisPosition
219
+ yAxisPosition: AxisPosition
220
+ width: number
221
+ height: number
222
+ }) {
223
+ if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
224
+ return { width, height }
225
+ } else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
226
+ return {
227
+ width: height,
228
+ height: width
229
+ }
230
+ }
231
+ }
232
+
233
+ // export function getTicks (minValue: number, maxValue: number, defaultTicks: number | null) {
234
+ // let valueLength = maxValue - minValue
235
+ // if (defaultTicks === null) {
236
+ // if (valueLength <= 1) {
237
+ // return 1
238
+ // } else {
239
+ // // d3.js自動判斷
240
+ // return null
241
+ // }
242
+ // } else if (valueLength < defaultTicks) {
243
+ // return Math.ceil(valueLength)
244
+ // } else {
245
+ // return defaultTicks
246
+ // }
247
+ // }
248
+
249
+
250
+
251
+ // 計算預設欄列數量
252
+ // 規則1.rowAmount*columnAmount要大於或等於amount,並且數字要盡可能小
253
+ // 規則2.columnAmount要大於或等於rowAmount,並且數字要盡可能小
254
+ function calcGridDimensions (amount: number): { rowAmount: number; columnAmount: number } {
255
+ let rowAmount = Math.floor(Math.sqrt(amount))
256
+ let columnAmount = Math.ceil(amount / rowAmount)
257
+ while (rowAmount * columnAmount < amount) {
258
+ columnAmount++
259
+ }
260
+ return { rowAmount, columnAmount }
261
+ }
262
+
263
+ export function calcContainerPosition (layout: Layout, container: Container, amount: number): ContainerPosition[] {
264
+ // const { gap } = container
265
+ const columnGap = container.columnGap === 'auto'
266
+ ? layout.left + layout.right
267
+ : container.columnGap
268
+ const rowGap = container.rowGap === 'auto'
269
+ ? layout.top + layout.bottom
270
+ : container.rowGap
271
+ const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
272
+ // 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
273
+ ? container
274
+ // 否則計算一個合適的預設值
275
+ : calcGridDimensions(amount)
276
+
277
+ return new Array(amount).fill(null).map((_, index) => {
278
+ const columnIndex = index % columnAmount
279
+ const rowIndex = Math.floor(index / columnAmount)
280
+
281
+ const width = (layout.width - (columnGap * (columnAmount - 1))) / columnAmount
282
+ const height = (layout.height - (rowGap * (rowAmount - 1))) / rowAmount
283
+ const x = columnIndex * width + (columnIndex * columnGap)
284
+ const y = rowIndex * height + (rowIndex * rowGap)
285
+ // const translate: [number, number] = [x, y]
286
+
287
+ return {
288
+ slotIndex: index,
289
+ rowIndex,
290
+ columnIndex,
291
+ // translate,
292
+ startX: x,
293
+ startY: y,
294
+ centerX: x + width / 2,
295
+ centerY: y + height / 2,
296
+ width,
297
+ height
298
+ }
299
+ })
300
+ }
301
+
302
+ export function calcContainerPositionScaled (layout: Layout, container: Container, amount: number): ContainerPositionScaled[] {
303
+ // const { gap } = container
304
+ const columnGap = container.columnGap === 'auto'
305
+ ? layout.left + layout.right
306
+ : container.columnGap
307
+ const rowGap = container.rowGap === 'auto'
308
+ ? layout.top + layout.bottom
309
+ : container.rowGap
310
+ const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
311
+ // 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
312
+ ? container
313
+ // 否則計算一個合適的預設值
314
+ : calcGridDimensions(amount)
315
+
316
+ return new Array(amount).fill(null).map((_, index) => {
317
+ const columnIndex = index % columnAmount
318
+ const rowIndex = Math.floor(index / columnAmount)
319
+
320
+ const width = (layout.width - (columnGap * (columnAmount - 1))) / columnAmount
321
+ const height = (layout.height - (rowGap * (rowAmount - 1))) / rowAmount
322
+ const x = columnIndex * width + (columnIndex * columnGap)
323
+ const y = rowIndex * height + (rowIndex * rowGap)
324
+ const translate: [number, number] = [x, y]
325
+ const scale: [number, number] = [width / layout.width, height / layout.height]
326
+
327
+ return {
328
+ slotIndex: index,
329
+ rowIndex,
330
+ columnIndex,
331
+ translate,
332
+ scale
333
+ }
334
+ })
335
+ }