@orbcharts/core 3.0.3 → 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 (70) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +1896 -1847
  3. package/dist/orbcharts-core.umd.js +5 -5
  4. package/dist/src/series/seriesObservables.d.ts +18 -7
  5. package/dist/src/utils/errorMessage.d.ts +1 -4
  6. package/lib/core-types.ts +7 -7
  7. package/package.json +46 -46
  8. package/src/AbstractChart.ts +57 -57
  9. package/src/GridChart.ts +24 -24
  10. package/src/MultiGridChart.ts +24 -24
  11. package/src/MultiValueChart.ts +24 -24
  12. package/src/RelationshipChart.ts +24 -24
  13. package/src/SeriesChart.ts +24 -24
  14. package/src/TreeChart.ts +24 -24
  15. package/src/base/createBaseChart.ts +524 -526
  16. package/src/base/createBasePlugin.ts +154 -154
  17. package/src/base/validators/chartOptionsValidator.ts +23 -23
  18. package/src/base/validators/chartParamsValidator.ts +133 -133
  19. package/src/base/validators/elementValidator.ts +13 -13
  20. package/src/base/validators/pluginsValidator.ts +14 -14
  21. package/src/defaults.ts +284 -283
  22. package/src/defineGridPlugin.ts +3 -3
  23. package/src/defineMultiGridPlugin.ts +3 -3
  24. package/src/defineMultiValuePlugin.ts +3 -3
  25. package/src/defineNoneDataPlugin.ts +4 -4
  26. package/src/defineRelationshipPlugin.ts +3 -3
  27. package/src/defineSeriesPlugin.ts +3 -3
  28. package/src/defineTreePlugin.ts +3 -3
  29. package/src/grid/computedDataFn.ts +129 -129
  30. package/src/grid/contextObserverCallback.ts +201 -201
  31. package/src/grid/dataFormatterValidator.ts +125 -125
  32. package/src/grid/dataValidator.ts +12 -12
  33. package/src/grid/gridObservables.ts +694 -718
  34. package/src/index.ts +20 -20
  35. package/src/multiGrid/computedDataFn.ts +123 -123
  36. package/src/multiGrid/contextObserverCallback.ts +75 -75
  37. package/src/multiGrid/dataFormatterValidator.ts +120 -120
  38. package/src/multiGrid/dataValidator.ts +12 -12
  39. package/src/multiGrid/multiGridObservables.ts +357 -401
  40. package/src/multiValue/computedDataFn.ts +113 -113
  41. package/src/multiValue/contextObserverCallback.ts +328 -328
  42. package/src/multiValue/dataFormatterValidator.ts +94 -94
  43. package/src/multiValue/dataValidator.ts +12 -12
  44. package/src/multiValue/multiValueObservables.ts +865 -1219
  45. package/src/relationship/computedDataFn.ts +159 -159
  46. package/src/relationship/contextObserverCallback.ts +80 -80
  47. package/src/relationship/dataFormatterValidator.ts +13 -13
  48. package/src/relationship/dataValidator.ts +13 -13
  49. package/src/relationship/relationshipObservables.ts +84 -84
  50. package/src/series/computedDataFn.ts +88 -88
  51. package/src/series/contextObserverCallback.ts +132 -107
  52. package/src/series/dataFormatterValidator.ts +46 -46
  53. package/src/series/dataValidator.ts +12 -12
  54. package/src/series/seriesObservables.ts +209 -175
  55. package/src/tree/computedDataFn.ts +129 -129
  56. package/src/tree/contextObserverCallback.ts +58 -58
  57. package/src/tree/dataFormatterValidator.ts +13 -13
  58. package/src/tree/dataValidator.ts +13 -13
  59. package/src/tree/treeObservables.ts +105 -105
  60. package/src/utils/commonUtils.ts +55 -55
  61. package/src/utils/d3Scale.ts +198 -198
  62. package/src/utils/errorMessage.ts +40 -43
  63. package/src/utils/index.ts +3 -3
  64. package/src/utils/observables.ts +308 -293
  65. package/src/utils/orbchartsUtils.ts +396 -396
  66. package/src/utils/validator.ts +126 -126
  67. package/tsconfig.base.json +13 -13
  68. package/tsconfig.json +2 -2
  69. package/vite-env.d.ts +6 -6
  70. 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
  }