@orbcharts/core 3.0.4 → 3.0.5

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 (69) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +1685 -1636
  3. package/dist/orbcharts-core.umd.js +4 -4
  4. package/dist/src/series/seriesObservables.d.ts +18 -7
  5. package/lib/core-types.ts +7 -7
  6. package/package.json +46 -46
  7. package/src/AbstractChart.ts +57 -57
  8. package/src/GridChart.ts +24 -24
  9. package/src/MultiGridChart.ts +24 -24
  10. package/src/MultiValueChart.ts +24 -24
  11. package/src/RelationshipChart.ts +24 -24
  12. package/src/SeriesChart.ts +24 -24
  13. package/src/TreeChart.ts +24 -24
  14. package/src/base/createBaseChart.ts +524 -524
  15. package/src/base/createBasePlugin.ts +154 -154
  16. package/src/base/validators/chartOptionsValidator.ts +23 -23
  17. package/src/base/validators/chartParamsValidator.ts +133 -133
  18. package/src/base/validators/elementValidator.ts +13 -13
  19. package/src/base/validators/pluginsValidator.ts +14 -14
  20. package/src/defaults.ts +284 -283
  21. package/src/defineGridPlugin.ts +3 -3
  22. package/src/defineMultiGridPlugin.ts +3 -3
  23. package/src/defineMultiValuePlugin.ts +3 -3
  24. package/src/defineNoneDataPlugin.ts +4 -4
  25. package/src/defineRelationshipPlugin.ts +3 -3
  26. package/src/defineSeriesPlugin.ts +3 -3
  27. package/src/defineTreePlugin.ts +3 -3
  28. package/src/grid/computedDataFn.ts +129 -129
  29. package/src/grid/contextObserverCallback.ts +201 -201
  30. package/src/grid/dataFormatterValidator.ts +125 -125
  31. package/src/grid/dataValidator.ts +12 -12
  32. package/src/grid/gridObservables.ts +694 -718
  33. package/src/index.ts +20 -20
  34. package/src/multiGrid/computedDataFn.ts +123 -123
  35. package/src/multiGrid/contextObserverCallback.ts +75 -75
  36. package/src/multiGrid/dataFormatterValidator.ts +120 -120
  37. package/src/multiGrid/dataValidator.ts +12 -12
  38. package/src/multiGrid/multiGridObservables.ts +357 -401
  39. package/src/multiValue/computedDataFn.ts +113 -113
  40. package/src/multiValue/contextObserverCallback.ts +328 -328
  41. package/src/multiValue/dataFormatterValidator.ts +94 -94
  42. package/src/multiValue/dataValidator.ts +12 -12
  43. package/src/multiValue/multiValueObservables.ts +865 -1219
  44. package/src/relationship/computedDataFn.ts +159 -159
  45. package/src/relationship/contextObserverCallback.ts +80 -80
  46. package/src/relationship/dataFormatterValidator.ts +13 -13
  47. package/src/relationship/dataValidator.ts +13 -13
  48. package/src/relationship/relationshipObservables.ts +84 -84
  49. package/src/series/computedDataFn.ts +88 -88
  50. package/src/series/contextObserverCallback.ts +132 -107
  51. package/src/series/dataFormatterValidator.ts +46 -46
  52. package/src/series/dataValidator.ts +12 -12
  53. package/src/series/seriesObservables.ts +209 -175
  54. package/src/tree/computedDataFn.ts +129 -129
  55. package/src/tree/contextObserverCallback.ts +58 -58
  56. package/src/tree/dataFormatterValidator.ts +13 -13
  57. package/src/tree/dataValidator.ts +13 -13
  58. package/src/tree/treeObservables.ts +105 -105
  59. package/src/utils/commonUtils.ts +55 -55
  60. package/src/utils/d3Scale.ts +198 -198
  61. package/src/utils/errorMessage.ts +40 -40
  62. package/src/utils/index.ts +3 -3
  63. package/src/utils/observables.ts +308 -293
  64. package/src/utils/orbchartsUtils.ts +396 -396
  65. package/src/utils/validator.ts +126 -126
  66. package/tsconfig.base.json +13 -13
  67. package/tsconfig.json +2 -2
  68. package/vite-env.d.ts +6 -6
  69. package/vite.config.js +22 -22
@@ -1,47 +1,47 @@
1
- import type { DataFormatterValidator, DataFormatterTypeMap } from '../../lib/core-types'
2
- import { validateColumns } from '../utils/validator'
3
-
4
- export const dataFormatterValidator: DataFormatterValidator<'series'> = (dataFormatter: DataFormatterTypeMap<'series'>) => {
5
- const result = validateColumns(dataFormatter, {
6
- visibleFilter: {
7
- toBeTypes: ['Function']
8
- },
9
- sort: {
10
- toBeTypes: ['Function', 'null']
11
- },
12
- seriesLabels: {
13
- toBeTypes: ['string[]']
14
- },
15
- container: {
16
- toBeTypes: ['object']
17
- },
18
- separateSeries: {
19
- toBeTypes: ['boolean']
20
- },
21
- sumSeries: {
22
- toBeTypes: ['boolean']
23
- }
24
- })
25
- if (dataFormatter.container) {
26
- const containerResult = validateColumns(dataFormatter.container, {
27
- columnAmount: {
28
- toBeTypes: ['number']
29
- },
30
- rowAmount: {
31
- toBeTypes: ['number']
32
- },
33
- columnGap: {
34
- toBe: '"auto" | number',
35
- test: (value: any) => value === 'auto' || typeof value === 'number'
36
- },
37
- rowGap: {
38
- toBe: '"auto" | number',
39
- test: (value: any) => value === 'auto' || typeof value === 'number'
40
- },
41
- })
42
- if (containerResult.status === 'error') {
43
- return containerResult
44
- }
45
- }
46
- return result
1
+ import type { DataFormatterValidator, DataFormatterTypeMap } from '../../lib/core-types'
2
+ import { validateColumns } from '../utils/validator'
3
+
4
+ export const dataFormatterValidator: DataFormatterValidator<'series'> = (dataFormatter: DataFormatterTypeMap<'series'>) => {
5
+ const result = validateColumns(dataFormatter, {
6
+ visibleFilter: {
7
+ toBeTypes: ['Function']
8
+ },
9
+ sort: {
10
+ toBeTypes: ['Function', 'null']
11
+ },
12
+ seriesLabels: {
13
+ toBeTypes: ['string[]']
14
+ },
15
+ container: {
16
+ toBeTypes: ['object']
17
+ },
18
+ separateSeries: {
19
+ toBeTypes: ['boolean']
20
+ },
21
+ sumSeries: {
22
+ toBeTypes: ['boolean']
23
+ }
24
+ })
25
+ if (dataFormatter.container) {
26
+ const containerResult = validateColumns(dataFormatter.container, {
27
+ columnAmount: {
28
+ toBeTypes: ['number']
29
+ },
30
+ rowAmount: {
31
+ toBeTypes: ['number']
32
+ },
33
+ columnGap: {
34
+ toBe: '"auto" | number',
35
+ test: (value: any) => value === 'auto' || typeof value === 'number'
36
+ },
37
+ rowGap: {
38
+ toBe: '"auto" | number',
39
+ test: (value: any) => value === 'auto' || typeof value === 'number'
40
+ },
41
+ })
42
+ if (containerResult.status === 'error') {
43
+ return containerResult
44
+ }
45
+ }
46
+ return result
47
47
  }
@@ -1,13 +1,13 @@
1
- import type { DataValidator, DataTypeMap } from '../../lib/core-types'
2
- import { validateColumns } from '../utils/validator'
3
-
4
- export const dataValidator: DataValidator<'series'> = (data: DataTypeMap<'series'>) => {
5
- const result = validateColumns({ data }, {
6
- data: {
7
- toBe: '(DataSeriesDatum | DataSeriesValue)[][] | (DataSeriesDatum | DataSeriesValue)[]',
8
- // 畢免資料量過大檢查不完,不深度檢查
9
- test: (value) => Array.isArray(value)
10
- }
11
- })
12
- return result
1
+ import type { DataValidator, DataTypeMap } from '../../lib/core-types'
2
+ import { validateColumns } from '../utils/validator'
3
+
4
+ export const dataValidator: DataValidator<'series'> = (data: DataTypeMap<'series'>) => {
5
+ const result = validateColumns({ data }, {
6
+ data: {
7
+ toBe: '(DataSeriesDatum | DataSeriesValue)[][] | (DataSeriesDatum | DataSeriesValue)[]',
8
+ // 畢免資料量過大檢查不完,不深度檢查
9
+ test: (value) => Array.isArray(value)
10
+ }
11
+ })
12
+ return result
13
13
  }
@@ -1,176 +1,210 @@
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
- ChartParams,
14
- ComputedDatumSeries,
15
- ComputedDataTypeMap,
16
- DataFormatterTypeMap,
17
- ContainerPosition,
18
- Layout } from '../../lib/core-types'
19
- import { calcContainerPosition } from '../utils/orbchartsUtils'
20
-
21
- export const separateSeriesObservable = ({ fullDataFormatter$ }: { fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>> }) => {
22
- return fullDataFormatter$.pipe(
23
- map(data => data.separateSeries),
24
- distinctUntilChanged(),
25
- )
26
- }
27
-
28
- export const seriesLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'series'>> }) => {
29
- return computedData$.pipe(
30
- map(data => {
31
- return data
32
- .filter(series => series.length)
33
- .map(series => {
34
- return series[0].seriesLabel
35
- })
36
- }),
37
- distinctUntilChanged((a, b) => {
38
- return JSON.stringify(a).length === JSON.stringify(b).length
39
- }),
40
- )
41
- }
42
-
43
- export const seriesVisibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'series'>> }) => {
44
- return computedData$.pipe(
45
- map(data => {
46
- return data.map(series => {
47
- return series.filter(datum => datum.visible != false)
48
- })
49
- })
50
- )
51
- }
52
-
53
- export const seriesComputedSortedDataObservable = ({ computedData$, fullDataFormatter$ }: {
54
- computedData$: Observable<ComputedDataTypeMap<'series'>>,
55
- fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>>
56
- }) => {
57
- return combineLatest({
58
- computedData: computedData$,
59
- fullDataFormatter: fullDataFormatter$
60
- }).pipe(
61
- switchMap(async (d) => d),
62
- map(data => {
63
- const sumData: ComputedDatumSeries[][] = data.fullDataFormatter.sumSeries == true
64
- ? data.computedData.map(d => {
65
- return [
66
- // 加總為一筆資料
67
- d.reduce((acc, current) => {
68
- if (acc == null) {
69
- return current // 取得第一筆資料
70
- }
71
- acc.value = acc.value + current.value
72
- return acc
73
- }, null)
74
- ]
75
- })
76
- : data.computedData
77
-
78
- return data.fullDataFormatter.separateSeries == true
79
- // 有拆分的話每個series為一組
80
- ? sumData
81
- .map(series => {
82
- return series.sort((a, b) => a.seq - b.seq)
83
- })
84
- // 無拆分的話所有資料為一組
85
- : [
86
- sumData
87
- .flat()
88
- .sort((a, b) => a.seq - b.seq)
89
- ]
90
- })
91
- )
92
- }
93
-
94
-
95
- // 所有container位置(對應series)
96
- export const seriesContainerPositionObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
97
- computedData$: Observable<ComputedDataTypeMap<'series'>>
98
- fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>>
99
- layout$: Observable<Layout>
100
- }): Observable<ContainerPosition[]> => {
101
-
102
- const gridContainerPosition$ = combineLatest({
103
- computedData: computedData$,
104
- fullDataFormatter: fullDataFormatter$,
105
- layout: layout$,
106
- }).pipe(
107
- switchMap(async (d) => d),
108
- map(data => {
109
-
110
- if (data.fullDataFormatter.separateSeries) {
111
- // -- 依slotIndexes計算 --
112
- return calcContainerPosition(data.layout, data.fullDataFormatter.container, data.computedData.length)
113
- // return data.computedData.map((seriesData, seriesIndex) => {
114
- // const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
115
- // const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
116
- // const { startX, startY, centerX, centerY, width, height } = calcContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
117
- // return {
118
- // slotIndex: seriesIndex,
119
- // rowIndex,
120
- // columnIndex,
121
- // startX,
122
- // startY,
123
- // centerX,
124
- // centerY,
125
- // width,
126
- // height,
127
- // }
128
- // })
129
- } else {
130
- // -- 無拆分 --
131
- return calcContainerPosition(data.layout, data.fullDataFormatter.container, 1)
132
- // const columnIndex = 0
133
- // const rowIndex = 0
134
- // return data.computedData.map((seriesData, seriesIndex) => {
135
- // const { startX, startY, centerX, centerY, width, height } = calcContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
136
- // return {
137
- // slotIndex: 0,
138
- // rowIndex,
139
- // columnIndex,
140
- // startX,
141
- // startY,
142
- // centerX,
143
- // centerY,
144
- // width,
145
- // height,
146
- // }
147
- // })
148
- }
149
- })
150
- )
151
-
152
- return gridContainerPosition$
153
- }
154
-
155
- export const seriesContainerPositionMapObservable = ({ seriesContainerPosition$, seriesLabels$, separateSeries$ }: {
156
- seriesContainerPosition$: Observable<ContainerPosition[]>
157
- seriesLabels$: Observable<string[]>
158
- separateSeries$: Observable<boolean>
159
- }) => {
160
- return combineLatest({
161
- seriesContainerPosition: seriesContainerPosition$,
162
- seriesLabels: seriesLabels$,
163
- separateSeries: separateSeries$,
164
- }).pipe(
165
- switchMap(async (d) => d),
166
- map(data => {
167
- return data.separateSeries
168
- ? new Map<string, ContainerPosition>(data.seriesLabels.map((seriesLabel, seriesIndex) => {
169
- return [seriesLabel, data.seriesContainerPosition[seriesIndex] ?? data.seriesContainerPosition[0]]
170
- }))
171
- : new Map<string, ContainerPosition>(data.seriesLabels.map((seriesLabel, seriesIndex) => {
172
- return [seriesLabel, data.seriesContainerPosition[0]]
173
- }))
174
- })
175
- )
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
+ ChartParams,
14
+ ComputedDatumSeries,
15
+ ComputedDataTypeMap,
16
+ DataFormatterTypeMap,
17
+ ContainerPosition,
18
+ Layout } from '../../lib/core-types'
19
+ import { calcContainerPosition } from '../utils/orbchartsUtils'
20
+
21
+ export const datumLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'series'>> }) => {
22
+ const DatumLabels = new Set<string>()
23
+ return computedData$.pipe(
24
+ map(data => {
25
+ data.forEach(series => {
26
+ series.forEach(datum => {
27
+ DatumLabels.add(datum.label)
28
+ })
29
+ })
30
+ return Array.from(DatumLabels)
31
+ }),
32
+ )
33
+ }
34
+
35
+ export const separateSeriesObservable = ({ fullDataFormatter$ }: { fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>> }) => {
36
+ return fullDataFormatter$.pipe(
37
+ map(data => data.separateSeries),
38
+ distinctUntilChanged(),
39
+ )
40
+ }
41
+
42
+ export const separateLabelObservable = ({ fullDataFormatter$ }: { fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>> }) => {
43
+ return fullDataFormatter$.pipe(
44
+ map(data => data.separateLabel),
45
+ distinctUntilChanged(),
46
+ )
47
+ }
48
+
49
+ export const sumSeriesObservable = ({ fullDataFormatter$ }: { fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>> }) => {
50
+ return fullDataFormatter$.pipe(
51
+ map(data => data.sumSeries),
52
+ distinctUntilChanged(),
53
+ )
54
+ }
55
+
56
+ export const seriesLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'series'>> }) => {
57
+ return computedData$.pipe(
58
+ map(data => {
59
+ return data
60
+ .filter(series => series.length)
61
+ .map(series => {
62
+ return series[0].seriesLabel
63
+ })
64
+ }),
65
+ distinctUntilChanged((a, b) => {
66
+ return JSON.stringify(a) === JSON.stringify(b)
67
+ }),
68
+ )
69
+ }
70
+
71
+ export const seriesVisibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'series'>> }) => {
72
+ return computedData$.pipe(
73
+ map(data => {
74
+ return data.map(series => {
75
+ return series.filter(datum => datum.visible != false)
76
+ })
77
+ })
78
+ )
79
+ }
80
+
81
+ export const seriesComputedSortedDataObservable = ({ computedData$, separateSeries$, separateLabel$, sumSeries$, datumLabels$ }: {
82
+ computedData$: Observable<ComputedDataTypeMap<'series'>>,
83
+ separateSeries$: Observable<boolean>,
84
+ separateLabel$: Observable<boolean>,
85
+ sumSeries$: Observable<boolean>,
86
+ datumLabels$: Observable<string[]>
87
+ }) => {
88
+ return combineLatest({
89
+ computedData: computedData$,
90
+ separateSeries: separateSeries$,
91
+ separateLabel: separateLabel$,
92
+ sumSeries: sumSeries$,
93
+ datumLabels: datumLabels$,
94
+ }).pipe(
95
+ switchMap(async (d) => d),
96
+ map(data => {
97
+
98
+ // sum series
99
+ const sumData: ComputedDatumSeries[][] = data.sumSeries == true
100
+ ? data.computedData.map(d => {
101
+ return [
102
+ // 加總為一筆資料
103
+ d.reduce((acc, current) => {
104
+ if (acc == null) {
105
+ // * 取得第一筆資料
106
+ return current
107
+ }
108
+ // 加總 value
109
+ acc.value = acc.value + current.value
110
+ return acc
111
+ }, null)
112
+ ]
113
+ })
114
+ : data.computedData
115
+
116
+ // separate series
117
+ const separateSeriesData: ComputedDatumSeries[][] = data.separateSeries == true
118
+ // 有拆分的話每個series為一組
119
+ ? sumData
120
+ // 無拆分的話所有資料為一組
121
+ : [sumData.flat()]
122
+
123
+ // separate label
124
+ const separateLabelData: ComputedDatumSeries[][] = data.separateLabel == true
125
+ // 有拆分的話每個label為一組
126
+ ? (() => {
127
+ // datumLabel 的 index 對應
128
+ const datumLabelIndexMap = data.datumLabels.reduce((acc, datumLabel, index) => {
129
+ acc[datumLabel] = index
130
+ return acc
131
+ }, {} as { [key: string]: number })
132
+
133
+ return separateSeriesData
134
+ .map(series => {
135
+ return series.reduce((acc, current) => {
136
+ const index = datumLabelIndexMap[current.label]
137
+ if (acc[index] == null) {
138
+ acc[index] = []
139
+ }
140
+ acc[index].push(current)
141
+ return acc
142
+ }, [] as ComputedDatumSeries[][])
143
+ })
144
+ .flat()
145
+ })()
146
+ // 無拆分
147
+ : separateSeriesData
148
+
149
+ return data.separateSeries == true && data.separateLabel == true
150
+ // 全部拆分時全部一起排序
151
+ ? separateLabelData
152
+ .sort((a, b) => a[0].seq - b[0].seq)
153
+ // 依各個 container 排序
154
+ : separateLabelData
155
+ .map(series => {
156
+ return series.sort((a, b) => a.seq - b.seq)
157
+ })
158
+ })
159
+ )
160
+ }
161
+
162
+
163
+ // 所有container位置(對應series)
164
+ export const seriesContainerPositionObservable = ({ computedSortedData$, fullDataFormatter$, layout$ }: {
165
+ computedSortedData$: Observable<ComputedDatumSeries[][]>
166
+ fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>>
167
+ layout$: Observable<Layout>
168
+ }): Observable<ContainerPosition[]> => {
169
+
170
+ const gridContainerPosition$ = combineLatest({
171
+ computedSortedData: computedSortedData$,
172
+ fullDataFormatter: fullDataFormatter$,
173
+ layout: layout$,
174
+ }).pipe(
175
+ switchMap(async (d) => d),
176
+ map(data => {
177
+
178
+ // 已分類資料的分類數量
179
+ const amount = data.computedSortedData.length
180
+
181
+ return calcContainerPosition(data.layout, data.fullDataFormatter.container, amount)
182
+ })
183
+ )
184
+
185
+ return gridContainerPosition$
186
+ }
187
+
188
+ export const datumContainerPositionMapObservable = ({ seriesContainerPosition$, computedSortedData$ }: {
189
+ seriesContainerPosition$: Observable<ContainerPosition[]>
190
+ computedSortedData$: Observable<ComputedDatumSeries[][]>
191
+ }) => {
192
+ return combineLatest({
193
+ seriesContainerPosition: seriesContainerPosition$,
194
+ computedSortedData: computedSortedData$,
195
+ }).pipe(
196
+ switchMap(async (d) => d),
197
+ map(data => {
198
+ return new Map<string, ContainerPosition>(
199
+ data.computedSortedData
200
+ .map((series, seriesIndex) => {
201
+ return series.map(datum => {
202
+ const m: [string, ContainerPosition] = [datum.id, data.seriesContainerPosition[seriesIndex]]
203
+ return m
204
+ })
205
+ })
206
+ .flat()
207
+ )
208
+ })
209
+ )
176
210
  }