@orbcharts/core 3.0.5 → 3.0.6

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 (68) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +2217 -2164
  3. package/dist/orbcharts-core.umd.js +5 -5
  4. package/lib/core-types.ts +7 -7
  5. package/package.json +46 -46
  6. package/src/AbstractChart.ts +57 -57
  7. package/src/GridChart.ts +24 -24
  8. package/src/MultiGridChart.ts +24 -24
  9. package/src/MultiValueChart.ts +24 -24
  10. package/src/RelationshipChart.ts +24 -24
  11. package/src/SeriesChart.ts +24 -24
  12. package/src/TreeChart.ts +24 -24
  13. package/src/base/createBaseChart.ts +524 -524
  14. package/src/base/createBasePlugin.ts +154 -154
  15. package/src/base/validators/chartOptionsValidator.ts +23 -23
  16. package/src/base/validators/chartParamsValidator.ts +133 -133
  17. package/src/base/validators/elementValidator.ts +13 -13
  18. package/src/base/validators/pluginsValidator.ts +14 -14
  19. package/src/defaults.ts +284 -284
  20. package/src/defineGridPlugin.ts +3 -3
  21. package/src/defineMultiGridPlugin.ts +3 -3
  22. package/src/defineMultiValuePlugin.ts +3 -3
  23. package/src/defineNoneDataPlugin.ts +4 -4
  24. package/src/defineRelationshipPlugin.ts +3 -3
  25. package/src/defineSeriesPlugin.ts +3 -3
  26. package/src/defineTreePlugin.ts +3 -3
  27. package/src/grid/computedDataFn.ts +129 -129
  28. package/src/grid/contextObserverCallback.ts +209 -201
  29. package/src/grid/dataFormatterValidator.ts +125 -125
  30. package/src/grid/dataValidator.ts +12 -12
  31. package/src/grid/gridObservables.ts +698 -694
  32. package/src/index.ts +20 -20
  33. package/src/multiGrid/computedDataFn.ts +123 -123
  34. package/src/multiGrid/contextObserverCallback.ts +109 -75
  35. package/src/multiGrid/dataFormatterValidator.ts +120 -120
  36. package/src/multiGrid/dataValidator.ts +12 -12
  37. package/src/multiGrid/multiGridObservables.ts +366 -357
  38. package/src/multiValue/computedDataFn.ts +113 -113
  39. package/src/multiValue/contextObserverCallback.ts +328 -328
  40. package/src/multiValue/dataFormatterValidator.ts +94 -94
  41. package/src/multiValue/dataValidator.ts +12 -12
  42. package/src/multiValue/multiValueObservables.ts +865 -865
  43. package/src/relationship/computedDataFn.ts +159 -159
  44. package/src/relationship/contextObserverCallback.ts +80 -80
  45. package/src/relationship/dataFormatterValidator.ts +13 -13
  46. package/src/relationship/dataValidator.ts +13 -13
  47. package/src/relationship/relationshipObservables.ts +84 -84
  48. package/src/series/computedDataFn.ts +88 -88
  49. package/src/series/contextObserverCallback.ts +132 -132
  50. package/src/series/dataFormatterValidator.ts +46 -46
  51. package/src/series/dataValidator.ts +12 -12
  52. package/src/series/seriesObservables.ts +209 -209
  53. package/src/tree/computedDataFn.ts +129 -129
  54. package/src/tree/contextObserverCallback.ts +58 -58
  55. package/src/tree/dataFormatterValidator.ts +13 -13
  56. package/src/tree/dataValidator.ts +13 -13
  57. package/src/tree/treeObservables.ts +105 -105
  58. package/src/utils/commonUtils.ts +55 -55
  59. package/src/utils/d3Scale.ts +198 -198
  60. package/src/utils/errorMessage.ts +40 -40
  61. package/src/utils/index.ts +3 -3
  62. package/src/utils/observables.ts +308 -308
  63. package/src/utils/orbchartsUtils.ts +396 -396
  64. package/src/utils/validator.ts +126 -126
  65. package/tsconfig.base.json +13 -13
  66. package/tsconfig.json +2 -2
  67. package/vite-env.d.ts +6 -6
  68. package/vite.config.js +22 -22
@@ -1,309 +1,309 @@
1
- import {
2
- combineLatest,
3
- distinctUntilChanged,
4
- filter,
5
- map,
6
- merge,
7
- takeUntil,
8
- shareReplay,
9
- switchMap,
10
- Subject,
11
- Observable } from 'rxjs'
12
- import type {
13
- ChartType,
14
- ChartParams,
15
- ComputedDatumBase,
16
- ComputedDataTypeMap,
17
- ComputedDatumTypeMap,
18
- ContainerPositionScaled,
19
- DataFormatterContainer,
20
- DataFormatterTypeMap,
21
- EventTypeMap,
22
- HighlightTarget,
23
- Layout,
24
- TransformData } from '../../lib/core-types'
25
-
26
- // interface DatumUnknown {
27
- // value: number | null
28
- // id: string
29
- // // label: string
30
- // seriesLabel?: string // 要符合每一種computedData所以不一定會有seriesLabel
31
- // groupLabel?: string // 要符合每一種computedData所以不一定會有groupLabel
32
- // }
33
-
34
- export function resizeObservable(elem: HTMLElement | Element): Observable<DOMRectReadOnly> {
35
- return new Observable(subscriber => {
36
- const ro = new ResizeObserver(entries => {
37
- const entry = entries[0]
38
- if (entry && entry.contentRect) {
39
- subscriber.next(entry.contentRect)
40
- }
41
- })
42
-
43
- ro.observe(elem)
44
- return function unsubscribe() {
45
- ro.unobserve(elem)
46
- }
47
- })
48
- }
49
-
50
- interface HighlightTargetValue {
51
- id: string | null
52
- label: string | null
53
- seriesLabel: string | null
54
- groupLabel: string | null
55
- categoryLabel: string | null
56
- highlightDefault: string | null
57
- }
58
-
59
- // 通用 highlight Observable
60
- export const highlightObservable = <T extends ChartType, D>({ datumList$, fullChartParams$, event$ }: {
61
- datumList$: Observable<D[]>
62
- fullChartParams$: Observable<ChartParams>
63
- event$: Subject<EventTypeMap<T>>
64
- }): Observable<D[]> => {
65
- const destroy$ = new Subject()
66
-
67
- // 預設的highlight
68
- const highlightDefault$: Observable<HighlightTargetValue> = fullChartParams$.pipe(
69
- takeUntil(destroy$),
70
- map(d => d.highlightDefault),
71
- distinctUntilChanged(),
72
- map(highlightDefault => {
73
- return {
74
- id: null,
75
- label: null,
76
- seriesLabel: null,
77
- groupLabel: null,
78
- categoryLabel: null,
79
- highlightDefault
80
- } as HighlightTargetValue
81
- }),
82
- shareReplay(1)
83
- )
84
-
85
- const highlightTarget$: Observable<HighlightTarget> = fullChartParams$.pipe(
86
- takeUntil(destroy$),
87
- map(d => d.highlightTarget),
88
- distinctUntilChanged(),
89
- shareReplay(1)
90
- )
91
-
92
- // 事件觸發的highlight
93
- const highlightMouseover$: Observable<HighlightTargetValue> = highlightTarget$.pipe(
94
- switchMap(highlightTarget => {
95
- return event$.pipe(
96
- takeUntil(destroy$),
97
- // filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove'),
98
- filter(d => d.eventName === 'mouseover'),
99
- // distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
100
- map(_d => {
101
- const d = _d as any
102
- return d.datum
103
- ? {
104
- id: d.datum.id,
105
- label: null, // label有可能重覆所以不做判斷
106
- seriesLabel: highlightTarget === 'series' ? d.datum.seriesLabel : null,
107
- groupLabel: highlightTarget === 'group' ? d.datum.groupLabel : null,
108
- categoryLabel: highlightTarget === 'category' ? d.datum.categoryLabel : null,
109
- highlightDefault: null
110
- } as HighlightTargetValue
111
- : {
112
- id: null,
113
- label: null,
114
- seriesLabel: null,
115
- groupLabel: null,
116
- categoryLabel: null,
117
- highlightDefault: null
118
- } as HighlightTargetValue
119
- })
120
- )
121
- })
122
- )
123
-
124
- const highlightMouseout$ = event$.pipe(
125
- takeUntil(destroy$),
126
- filter(d => d.eventName === 'mouseout'),
127
- // distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
128
- // map(d => {
129
- // return { id: '', label: '' }
130
- // })
131
- switchMap(d => highlightDefault$)
132
- )
133
-
134
- // function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null) {
135
- // const datum = datumList.find(d => (d as ComputedDatumBase).id === id)
136
- // return datum ? [datum] : []
137
- // }
138
- function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null, label: string | null) {
139
- return id == null && label == null
140
- ? []
141
- : datumList.filter(d => (d as ComputedDatumBase).id === id || (d as ComputedDatumBase).label === label)
142
- }
143
-
144
- function getSeriesIds (datumList: ComputedDatumTypeMap<T>[], seriesLabel: string | null) {
145
- return seriesLabel == null
146
- ? []
147
- : datumList.filter(d => (d as ComputedDatumTypeMap<"series">).seriesLabel === seriesLabel)
148
- }
149
-
150
- function getGroupIds (datumList: ComputedDatumTypeMap<T>[], groupLabel: string | null) {
151
- return groupLabel == null
152
- ? []
153
- : datumList.filter(d => (d as ComputedDatumTypeMap<"grid">).groupLabel === groupLabel)
154
- }
155
-
156
- function getCategoryIds (datumList: ComputedDatumTypeMap<T>[], categoryLabel: string | null) {
157
- return categoryLabel == null
158
- ? []
159
- : datumList.filter(d => (d as ComputedDatumTypeMap<"multiValue" | "relationship" | "tree">).categoryLabel === categoryLabel)
160
- }
161
-
162
- return new Observable<D[]>(subscriber => {
163
- combineLatest({
164
- target: merge(highlightMouseover$, highlightMouseout$, highlightDefault$),
165
- datumList: datumList$,
166
- fullChartParams: fullChartParams$,
167
- }).pipe(
168
- takeUntil(destroy$),
169
- switchMap(async d => d)
170
- ).subscribe(data => {
171
- let datumList: ComputedDatumTypeMap<T>[] = []
172
- if (data.fullChartParams.highlightTarget === 'datum') {
173
- datumList = getDatumIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.id, data.target.label)
174
- } else if (data.fullChartParams.highlightTarget === 'series') {
175
- datumList = getSeriesIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.seriesLabel)
176
- } else if (data.fullChartParams.highlightTarget === 'group') {
177
- datumList = getGroupIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.groupLabel)
178
- } else if (data.fullChartParams.highlightTarget === 'category') {
179
- datumList = getCategoryIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.categoryLabel)
180
- }
181
-
182
- subscriber.next(datumList as D[])
183
- })
184
-
185
- return function unsubscribe () {
186
- destroy$.next(undefined)
187
- }
188
- })
189
- }
190
-
191
- export const seriesDataMapObservable = <DatumType extends ComputedDatumTypeMap<'series' | 'grid'>>({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
192
- return datumList$.pipe(
193
- map(data => {
194
- const SeriesDataMap: Map<string, DatumType[]> = new Map()
195
- data.forEach(d => {
196
- const seriesData = SeriesDataMap.get(d.seriesLabel) ?? []
197
- seriesData.push(d)
198
- SeriesDataMap.set(d.seriesLabel, seriesData)
199
- })
200
- return SeriesDataMap
201
- })
202
- )
203
- }
204
-
205
- export const groupDataMapObservable = <DatumType extends ComputedDatumTypeMap<'grid'>> ({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
206
- return datumList$.pipe(
207
- map(data => {
208
- const GroupDataMap: Map<string, DatumType[]> = new Map()
209
- data.forEach(d => {
210
- const groupData = GroupDataMap.get(d.groupLabel) ?? []
211
- groupData.push(d)
212
- GroupDataMap.set(d.groupLabel, groupData)
213
- })
214
- return GroupDataMap
215
- })
216
- )
217
- }
218
-
219
- export const categoryDataMapObservable = <DatumType extends ComputedDatumTypeMap<'multiValue' | 'relationship' | 'tree'>> ({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
220
- return datumList$.pipe(
221
- map(data => {
222
- const GroupDataMap: Map<string, DatumType[]> = new Map()
223
- data
224
- .filter(d => d.categoryLabel != null)
225
- .forEach(d => {
226
- const groupData = GroupDataMap.get(d.categoryLabel) ?? []
227
- groupData.push(d)
228
- GroupDataMap.set(d.categoryLabel, groupData)
229
- })
230
- return GroupDataMap
231
- })
232
- )
233
- }
234
-
235
- export const textSizePxObservable = (chartParams$: Observable<ChartParams>) => {
236
- return chartParams$.pipe(
237
- map(d => d.styles.textSize),
238
- distinctUntilChanged(),
239
- map(data => {
240
- let value = NaN
241
- if (typeof data === 'string') {
242
- if (data.includes('rem')) {
243
- const rootFontSizePx = parseFloat(getComputedStyle(document.documentElement).fontSize)
244
- const num = parseFloat(data)
245
- value = num * rootFontSizePx
246
- } else if (data.includes('px')) {
247
- value = parseFloat(data)
248
- }
249
- } else if (typeof data === 'number') {
250
- return data
251
- }
252
- return value ? value : 14 // default
253
- })
254
- )
255
- }
256
-
257
- export const containerSizeObservable = ({ layout$, containerPosition$, container$ }: {
258
- layout$: Observable<Layout>
259
- containerPosition$: Observable<ContainerPositionScaled[]>
260
- container$: Observable<DataFormatterContainer>
261
- }) => {
262
- const rowAmount$ = containerPosition$.pipe(
263
- map(containerPosition => {
264
- const maxRowIndex = containerPosition.reduce((acc, current) => {
265
- return current.rowIndex > acc ? current.rowIndex : acc
266
- }, 0)
267
- return maxRowIndex + 1
268
- }),
269
- distinctUntilChanged(),
270
- )
271
-
272
- const columnAmount$ = containerPosition$.pipe(
273
- map(containerPosition => {
274
- const maxColumnIndex = containerPosition.reduce((acc, current) => {
275
- return current.columnIndex > acc ? current.columnIndex : acc
276
- }, 0)
277
- return maxColumnIndex + 1
278
- }),
279
- distinctUntilChanged()
280
- )
281
-
282
- return combineLatest({
283
- layout: layout$,
284
- rowAmount: rowAmount$,
285
- columnAmount: columnAmount$,
286
- container: container$
287
- }).pipe(
288
- switchMap(async (d) => d),
289
- map(data => {
290
- // const width = (data.layout.rootWidth / data.columnAmount) - (data.layout.left + data.layout.right)
291
- // const height = (data.layout.rootHeight / data.rowAmount) - (data.layout.top + data.layout.bottom)
292
- const columnGap = data.container.columnGap === 'auto'
293
- ? data.layout.left + data.layout.right
294
- : data.container.columnGap
295
- const rowGap = data.container.rowGap === 'auto'
296
- ? data.layout.top + data.layout.bottom
297
- : data.container.rowGap
298
- const width = (data.layout.rootWidth - data.layout.left - data.layout.right - (columnGap * (data.columnAmount - 1))) / data.columnAmount
299
- const height = (data.layout.rootHeight - data.layout.top - data.layout.bottom - (rowGap * (data.rowAmount - 1))) / data.rowAmount
300
-
301
- return {
302
- width,
303
- height
304
- }
305
- }),
306
- distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height),
307
- // shareReplay(1)
308
- )
1
+ import {
2
+ combineLatest,
3
+ distinctUntilChanged,
4
+ filter,
5
+ map,
6
+ merge,
7
+ takeUntil,
8
+ shareReplay,
9
+ switchMap,
10
+ Subject,
11
+ Observable } from 'rxjs'
12
+ import type {
13
+ ChartType,
14
+ ChartParams,
15
+ ComputedDatumBase,
16
+ ComputedDataTypeMap,
17
+ ComputedDatumTypeMap,
18
+ ContainerPositionScaled,
19
+ DataFormatterContainer,
20
+ DataFormatterTypeMap,
21
+ EventTypeMap,
22
+ HighlightTarget,
23
+ Layout,
24
+ TransformData } from '../../lib/core-types'
25
+
26
+ // interface DatumUnknown {
27
+ // value: number | null
28
+ // id: string
29
+ // // label: string
30
+ // seriesLabel?: string // 要符合每一種computedData所以不一定會有seriesLabel
31
+ // groupLabel?: string // 要符合每一種computedData所以不一定會有groupLabel
32
+ // }
33
+
34
+ export function resizeObservable(elem: HTMLElement | Element): Observable<DOMRectReadOnly> {
35
+ return new Observable(subscriber => {
36
+ const ro = new ResizeObserver(entries => {
37
+ const entry = entries[0]
38
+ if (entry && entry.contentRect) {
39
+ subscriber.next(entry.contentRect)
40
+ }
41
+ })
42
+
43
+ ro.observe(elem)
44
+ return function unsubscribe() {
45
+ ro.unobserve(elem)
46
+ }
47
+ })
48
+ }
49
+
50
+ interface HighlightTargetValue {
51
+ id: string | null
52
+ label: string | null
53
+ seriesLabel: string | null
54
+ groupLabel: string | null
55
+ categoryLabel: string | null
56
+ highlightDefault: string | null
57
+ }
58
+
59
+ // 通用 highlight Observable
60
+ export const highlightObservable = <T extends ChartType, D>({ datumList$, fullChartParams$, event$ }: {
61
+ datumList$: Observable<D[]>
62
+ fullChartParams$: Observable<ChartParams>
63
+ event$: Subject<EventTypeMap<T>>
64
+ }): Observable<D[]> => {
65
+ const destroy$ = new Subject()
66
+
67
+ // 預設的highlight
68
+ const highlightDefault$: Observable<HighlightTargetValue> = fullChartParams$.pipe(
69
+ takeUntil(destroy$),
70
+ map(d => d.highlightDefault),
71
+ distinctUntilChanged(),
72
+ map(highlightDefault => {
73
+ return {
74
+ id: null,
75
+ label: null,
76
+ seriesLabel: null,
77
+ groupLabel: null,
78
+ categoryLabel: null,
79
+ highlightDefault
80
+ } as HighlightTargetValue
81
+ }),
82
+ shareReplay(1)
83
+ )
84
+
85
+ const highlightTarget$: Observable<HighlightTarget> = fullChartParams$.pipe(
86
+ takeUntil(destroy$),
87
+ map(d => d.highlightTarget),
88
+ distinctUntilChanged(),
89
+ shareReplay(1)
90
+ )
91
+
92
+ // 事件觸發的highlight
93
+ const highlightMouseover$: Observable<HighlightTargetValue> = highlightTarget$.pipe(
94
+ switchMap(highlightTarget => {
95
+ return event$.pipe(
96
+ takeUntil(destroy$),
97
+ // filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove'),
98
+ filter(d => d.eventName === 'mouseover'),
99
+ // distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
100
+ map(_d => {
101
+ const d = _d as any
102
+ return d.datum
103
+ ? {
104
+ id: d.datum.id,
105
+ label: null, // label有可能重覆所以不做判斷
106
+ seriesLabel: highlightTarget === 'series' ? d.datum.seriesLabel : null,
107
+ groupLabel: highlightTarget === 'group' ? d.datum.groupLabel : null,
108
+ categoryLabel: highlightTarget === 'category' ? d.datum.categoryLabel : null,
109
+ highlightDefault: null
110
+ } as HighlightTargetValue
111
+ : {
112
+ id: null,
113
+ label: null,
114
+ seriesLabel: null,
115
+ groupLabel: null,
116
+ categoryLabel: null,
117
+ highlightDefault: null
118
+ } as HighlightTargetValue
119
+ })
120
+ )
121
+ })
122
+ )
123
+
124
+ const highlightMouseout$ = event$.pipe(
125
+ takeUntil(destroy$),
126
+ filter(d => d.eventName === 'mouseout'),
127
+ // distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
128
+ // map(d => {
129
+ // return { id: '', label: '' }
130
+ // })
131
+ switchMap(d => highlightDefault$)
132
+ )
133
+
134
+ // function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null) {
135
+ // const datum = datumList.find(d => (d as ComputedDatumBase).id === id)
136
+ // return datum ? [datum] : []
137
+ // }
138
+ function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null, label: string | null) {
139
+ return id == null && label == null
140
+ ? []
141
+ : datumList.filter(d => (d as ComputedDatumBase).id === id || (d as ComputedDatumBase).label === label)
142
+ }
143
+
144
+ function getSeriesIds (datumList: ComputedDatumTypeMap<T>[], seriesLabel: string | null) {
145
+ return seriesLabel == null
146
+ ? []
147
+ : datumList.filter(d => (d as ComputedDatumTypeMap<"series">).seriesLabel === seriesLabel)
148
+ }
149
+
150
+ function getGroupIds (datumList: ComputedDatumTypeMap<T>[], groupLabel: string | null) {
151
+ return groupLabel == null
152
+ ? []
153
+ : datumList.filter(d => (d as ComputedDatumTypeMap<"grid">).groupLabel === groupLabel)
154
+ }
155
+
156
+ function getCategoryIds (datumList: ComputedDatumTypeMap<T>[], categoryLabel: string | null) {
157
+ return categoryLabel == null
158
+ ? []
159
+ : datumList.filter(d => (d as ComputedDatumTypeMap<"multiValue" | "relationship" | "tree">).categoryLabel === categoryLabel)
160
+ }
161
+
162
+ return new Observable<D[]>(subscriber => {
163
+ combineLatest({
164
+ target: merge(highlightMouseover$, highlightMouseout$, highlightDefault$),
165
+ datumList: datumList$,
166
+ fullChartParams: fullChartParams$,
167
+ }).pipe(
168
+ takeUntil(destroy$),
169
+ switchMap(async d => d)
170
+ ).subscribe(data => {
171
+ let datumList: ComputedDatumTypeMap<T>[] = []
172
+ if (data.fullChartParams.highlightTarget === 'datum') {
173
+ datumList = getDatumIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.id, data.target.label)
174
+ } else if (data.fullChartParams.highlightTarget === 'series') {
175
+ datumList = getSeriesIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.seriesLabel)
176
+ } else if (data.fullChartParams.highlightTarget === 'group') {
177
+ datumList = getGroupIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.groupLabel)
178
+ } else if (data.fullChartParams.highlightTarget === 'category') {
179
+ datumList = getCategoryIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.categoryLabel)
180
+ }
181
+
182
+ subscriber.next(datumList as D[])
183
+ })
184
+
185
+ return function unsubscribe () {
186
+ destroy$.next(undefined)
187
+ }
188
+ })
189
+ }
190
+
191
+ export const seriesDataMapObservable = <DatumType extends ComputedDatumTypeMap<'series' | 'grid'>>({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
192
+ return datumList$.pipe(
193
+ map(data => {
194
+ const SeriesDataMap: Map<string, DatumType[]> = new Map()
195
+ data.forEach(d => {
196
+ const seriesData = SeriesDataMap.get(d.seriesLabel) ?? []
197
+ seriesData.push(d)
198
+ SeriesDataMap.set(d.seriesLabel, seriesData)
199
+ })
200
+ return SeriesDataMap
201
+ })
202
+ )
203
+ }
204
+
205
+ export const groupDataMapObservable = <DatumType extends ComputedDatumTypeMap<'grid'>> ({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
206
+ return datumList$.pipe(
207
+ map(data => {
208
+ const GroupDataMap: Map<string, DatumType[]> = new Map()
209
+ data.forEach(d => {
210
+ const groupData = GroupDataMap.get(d.groupLabel) ?? []
211
+ groupData.push(d)
212
+ GroupDataMap.set(d.groupLabel, groupData)
213
+ })
214
+ return GroupDataMap
215
+ })
216
+ )
217
+ }
218
+
219
+ export const categoryDataMapObservable = <DatumType extends ComputedDatumTypeMap<'multiValue' | 'relationship' | 'tree'>> ({ datumList$ }: { datumList$: Observable<DatumType[]> }) => {
220
+ return datumList$.pipe(
221
+ map(data => {
222
+ const GroupDataMap: Map<string, DatumType[]> = new Map()
223
+ data
224
+ .filter(d => d.categoryLabel != null)
225
+ .forEach(d => {
226
+ const groupData = GroupDataMap.get(d.categoryLabel) ?? []
227
+ groupData.push(d)
228
+ GroupDataMap.set(d.categoryLabel, groupData)
229
+ })
230
+ return GroupDataMap
231
+ })
232
+ )
233
+ }
234
+
235
+ export const textSizePxObservable = (chartParams$: Observable<ChartParams>) => {
236
+ return chartParams$.pipe(
237
+ map(d => d.styles.textSize),
238
+ distinctUntilChanged(),
239
+ map(data => {
240
+ let value = NaN
241
+ if (typeof data === 'string') {
242
+ if (data.includes('rem')) {
243
+ const rootFontSizePx = parseFloat(getComputedStyle(document.documentElement).fontSize)
244
+ const num = parseFloat(data)
245
+ value = num * rootFontSizePx
246
+ } else if (data.includes('px')) {
247
+ value = parseFloat(data)
248
+ }
249
+ } else if (typeof data === 'number') {
250
+ return data
251
+ }
252
+ return value ? value : 14 // default
253
+ })
254
+ )
255
+ }
256
+
257
+ export const containerSizeObservable = ({ layout$, containerPosition$, container$ }: {
258
+ layout$: Observable<Layout>
259
+ containerPosition$: Observable<ContainerPositionScaled[]>
260
+ container$: Observable<DataFormatterContainer>
261
+ }) => {
262
+ const rowAmount$ = containerPosition$.pipe(
263
+ map(containerPosition => {
264
+ const maxRowIndex = containerPosition.reduce((acc, current) => {
265
+ return current.rowIndex > acc ? current.rowIndex : acc
266
+ }, 0)
267
+ return maxRowIndex + 1
268
+ }),
269
+ distinctUntilChanged(),
270
+ )
271
+
272
+ const columnAmount$ = containerPosition$.pipe(
273
+ map(containerPosition => {
274
+ const maxColumnIndex = containerPosition.reduce((acc, current) => {
275
+ return current.columnIndex > acc ? current.columnIndex : acc
276
+ }, 0)
277
+ return maxColumnIndex + 1
278
+ }),
279
+ distinctUntilChanged()
280
+ )
281
+
282
+ return combineLatest({
283
+ layout: layout$,
284
+ rowAmount: rowAmount$,
285
+ columnAmount: columnAmount$,
286
+ container: container$
287
+ }).pipe(
288
+ switchMap(async (d) => d),
289
+ map(data => {
290
+ // const width = (data.layout.rootWidth / data.columnAmount) - (data.layout.left + data.layout.right)
291
+ // const height = (data.layout.rootHeight / data.rowAmount) - (data.layout.top + data.layout.bottom)
292
+ const columnGap = data.container.columnGap === 'auto'
293
+ ? data.layout.left + data.layout.right
294
+ : data.container.columnGap
295
+ const rowGap = data.container.rowGap === 'auto'
296
+ ? data.layout.top + data.layout.bottom
297
+ : data.container.rowGap
298
+ const width = (data.layout.rootWidth - data.layout.left - data.layout.right - (columnGap * (data.columnAmount - 1))) / data.columnAmount
299
+ const height = (data.layout.rootHeight - data.layout.top - data.layout.bottom - (rowGap * (data.rowAmount - 1))) / data.rowAmount
300
+
301
+ return {
302
+ width,
303
+ height
304
+ }
305
+ }),
306
+ distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height),
307
+ // shareReplay(1)
308
+ )
309
309
  }