@orbcharts/core 3.0.2 → 3.0.4

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