@orbcharts/core 3.0.0-beta.1 → 3.0.0-beta.2
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.
- package/LICENSE +200 -200
- package/dist/orbcharts-core.es.js +4 -3
- package/dist/orbcharts-core.umd.js +1 -1
- package/lib/core-types.ts +7 -7
- package/package.json +42 -42
- package/src/AbstractChart.ts +57 -57
- package/src/GridChart.ts +24 -24
- package/src/MultiGridChart.ts +24 -24
- package/src/MultiValueChart.ts +24 -24
- package/src/RelationshipChart.ts +24 -24
- package/src/SeriesChart.ts +24 -24
- package/src/TreeChart.ts +24 -24
- package/src/base/createBaseChart.ts +505 -505
- package/src/base/createBasePlugin.ts +153 -153
- package/src/base/validators/chartOptionsValidator.ts +23 -23
- package/src/base/validators/chartParamsValidator.ts +133 -133
- package/src/base/validators/elementValidator.ts +13 -13
- package/src/base/validators/pluginsValidator.ts +14 -14
- package/src/defaults.ts +232 -232
- package/src/defineGridPlugin.ts +3 -3
- package/src/defineMultiGridPlugin.ts +3 -3
- package/src/defineMultiValuePlugin.ts +3 -3
- package/src/defineNoneDataPlugin.ts +4 -4
- package/src/defineRelationshipPlugin.ts +3 -3
- package/src/defineSeriesPlugin.ts +3 -3
- package/src/defineTreePlugin.ts +3 -3
- package/src/grid/computedDataFn.ts +129 -129
- package/src/grid/contextObserverCallback.ts +155 -155
- package/src/grid/dataFormatterValidator.ts +101 -101
- package/src/grid/dataValidator.ts +12 -12
- package/src/index.ts +20 -20
- package/src/multiGrid/computedDataFn.ts +123 -123
- package/src/multiGrid/contextObserverCallback.ts +41 -41
- package/src/multiGrid/dataFormatterValidator.ts +115 -115
- package/src/multiGrid/dataValidator.ts +12 -12
- package/src/multiValue/computedDataFn.ts +176 -176
- package/src/multiValue/contextObserverCallback.ts +12 -12
- package/src/multiValue/dataFormatterValidator.ts +9 -9
- package/src/multiValue/dataValidator.ts +9 -9
- package/src/relationship/computedDataFn.ts +125 -125
- package/src/relationship/contextObserverCallback.ts +12 -12
- package/src/relationship/dataFormatterValidator.ts +9 -9
- package/src/relationship/dataValidator.ts +9 -9
- package/src/series/computedDataFn.ts +88 -88
- package/src/series/contextObserverCallback.ts +100 -100
- package/src/series/dataFormatterValidator.ts +41 -41
- package/src/series/dataValidator.ts +12 -12
- package/src/tree/computedDataFn.ts +130 -130
- package/src/tree/contextObserverCallback.ts +61 -61
- package/src/tree/dataFormatterValidator.ts +13 -13
- package/src/tree/dataValidator.ts +13 -13
- package/src/utils/commonUtils.ts +55 -55
- package/src/utils/d3Utils.ts +108 -108
- package/src/utils/errorMessage.ts +42 -42
- package/src/utils/gridObservables.ts +614 -611
- package/src/utils/index.ts +9 -9
- package/src/utils/multiGridObservables.ts +366 -366
- package/src/utils/observables.ts +219 -219
- package/src/utils/orbchartsUtils.ts +352 -352
- package/src/utils/seriesObservables.ts +175 -175
- package/src/utils/treeObservables.ts +94 -94
- package/src/utils/validator.ts +125 -125
- package/tsconfig.base.json +13 -13
- package/tsconfig.json +2 -2
- package/vite-env.d.ts +6 -6
- package/vite.config.js +22 -22
@@ -1,100 +1,100 @@
|
|
1
|
-
import { map, shareReplay } from 'rxjs'
|
2
|
-
import type { ContextObserverCallback } from '../../lib/core-types'
|
3
|
-
import {
|
4
|
-
seriesDataMapObservable,
|
5
|
-
groupDataMapObservable } from '../utils/observables'
|
6
|
-
import { highlightObservable, textSizePxObservable } from '../utils/observables'
|
7
|
-
|
8
|
-
import {
|
9
|
-
separateSeriesObservable,
|
10
|
-
seriesVisibleComputedDataObservable,
|
11
|
-
seriesComputedLayoutDataObservable,
|
12
|
-
seriesLabelsObservable,
|
13
|
-
seriesContainerPositionObservable,
|
14
|
-
seriesContainerPositionMapObservable
|
15
|
-
} from '../utils/seriesObservables'
|
16
|
-
|
17
|
-
export const contextObserverCallback: ContextObserverCallback<'series'> = ({ subject, observer }) => {
|
18
|
-
|
19
|
-
const textSizePx$ = textSizePxObservable(observer.fullChartParams$).pipe(
|
20
|
-
shareReplay(1)
|
21
|
-
)
|
22
|
-
|
23
|
-
const separateSeries$ = separateSeriesObservable({
|
24
|
-
fullDataFormatter$: observer.fullDataFormatter$
|
25
|
-
})
|
26
|
-
|
27
|
-
const visibleComputedData$ = seriesVisibleComputedDataObservable({
|
28
|
-
computedData$: observer.computedData$,
|
29
|
-
})
|
30
|
-
|
31
|
-
const computedLayoutData$ = seriesComputedLayoutDataObservable({
|
32
|
-
computedData$: observer.computedData$,
|
33
|
-
fullDataFormatter$: observer.fullDataFormatter$
|
34
|
-
}).pipe(
|
35
|
-
shareReplay(1)
|
36
|
-
)
|
37
|
-
|
38
|
-
const visibleComputedLayoutData$ = seriesVisibleComputedDataObservable({
|
39
|
-
computedData$: computedLayoutData$,
|
40
|
-
})
|
41
|
-
|
42
|
-
const datumList$ = observer.computedData$.pipe(
|
43
|
-
map(d => d.flat())
|
44
|
-
).pipe(
|
45
|
-
shareReplay(1)
|
46
|
-
)
|
47
|
-
|
48
|
-
const seriesHighlight$ = highlightObservable({
|
49
|
-
datumList$,
|
50
|
-
fullChartParams$: observer.fullChartParams$,
|
51
|
-
event$: subject.event$
|
52
|
-
}).pipe(
|
53
|
-
shareReplay(1)
|
54
|
-
)
|
55
|
-
|
56
|
-
const seriesLabels$ = seriesLabelsObservable({
|
57
|
-
computedData$: observer.computedData$,
|
58
|
-
})
|
59
|
-
|
60
|
-
|
61
|
-
const SeriesDataMap$ = seriesDataMapObservable({
|
62
|
-
datumList$
|
63
|
-
}).pipe(
|
64
|
-
shareReplay(1)
|
65
|
-
)
|
66
|
-
|
67
|
-
const seriesContainerPosition$ = seriesContainerPositionObservable({
|
68
|
-
computedData$: observer.computedData$,
|
69
|
-
fullDataFormatter$: observer.fullDataFormatter$,
|
70
|
-
layout$: observer.layout$,
|
71
|
-
}).pipe(
|
72
|
-
shareReplay(1)
|
73
|
-
)
|
74
|
-
|
75
|
-
const SeriesContainerPositionMap$ = seriesContainerPositionMapObservable({
|
76
|
-
seriesContainerPosition$: seriesContainerPosition$,
|
77
|
-
seriesLabels$: seriesLabels$,
|
78
|
-
separateSeries$: separateSeries$,
|
79
|
-
}).pipe(
|
80
|
-
shareReplay(1)
|
81
|
-
)
|
82
|
-
|
83
|
-
return {
|
84
|
-
fullParams$: observer.fullParams$,
|
85
|
-
fullChartParams$: observer.fullChartParams$,
|
86
|
-
fullDataFormatter$: observer.fullDataFormatter$,
|
87
|
-
computedData$: observer.computedData$,
|
88
|
-
layout$: observer.layout$,
|
89
|
-
textSizePx$,
|
90
|
-
visibleComputedData$,
|
91
|
-
visibleComputedLayoutData$,
|
92
|
-
separateSeries$,
|
93
|
-
computedLayoutData$,
|
94
|
-
seriesHighlight$,
|
95
|
-
seriesLabels$,
|
96
|
-
SeriesDataMap$,
|
97
|
-
seriesContainerPosition$,
|
98
|
-
SeriesContainerPositionMap$,
|
99
|
-
}
|
100
|
-
}
|
1
|
+
import { map, shareReplay } from 'rxjs'
|
2
|
+
import type { ContextObserverCallback } from '../../lib/core-types'
|
3
|
+
import {
|
4
|
+
seriesDataMapObservable,
|
5
|
+
groupDataMapObservable } from '../utils/observables'
|
6
|
+
import { highlightObservable, textSizePxObservable } from '../utils/observables'
|
7
|
+
|
8
|
+
import {
|
9
|
+
separateSeriesObservable,
|
10
|
+
seriesVisibleComputedDataObservable,
|
11
|
+
seriesComputedLayoutDataObservable,
|
12
|
+
seriesLabelsObservable,
|
13
|
+
seriesContainerPositionObservable,
|
14
|
+
seriesContainerPositionMapObservable
|
15
|
+
} from '../utils/seriesObservables'
|
16
|
+
|
17
|
+
export const contextObserverCallback: ContextObserverCallback<'series'> = ({ subject, observer }) => {
|
18
|
+
|
19
|
+
const textSizePx$ = textSizePxObservable(observer.fullChartParams$).pipe(
|
20
|
+
shareReplay(1)
|
21
|
+
)
|
22
|
+
|
23
|
+
const separateSeries$ = separateSeriesObservable({
|
24
|
+
fullDataFormatter$: observer.fullDataFormatter$
|
25
|
+
})
|
26
|
+
|
27
|
+
const visibleComputedData$ = seriesVisibleComputedDataObservable({
|
28
|
+
computedData$: observer.computedData$,
|
29
|
+
})
|
30
|
+
|
31
|
+
const computedLayoutData$ = seriesComputedLayoutDataObservable({
|
32
|
+
computedData$: observer.computedData$,
|
33
|
+
fullDataFormatter$: observer.fullDataFormatter$
|
34
|
+
}).pipe(
|
35
|
+
shareReplay(1)
|
36
|
+
)
|
37
|
+
|
38
|
+
const visibleComputedLayoutData$ = seriesVisibleComputedDataObservable({
|
39
|
+
computedData$: computedLayoutData$,
|
40
|
+
})
|
41
|
+
|
42
|
+
const datumList$ = observer.computedData$.pipe(
|
43
|
+
map(d => d.flat())
|
44
|
+
).pipe(
|
45
|
+
shareReplay(1)
|
46
|
+
)
|
47
|
+
|
48
|
+
const seriesHighlight$ = highlightObservable({
|
49
|
+
datumList$,
|
50
|
+
fullChartParams$: observer.fullChartParams$,
|
51
|
+
event$: subject.event$
|
52
|
+
}).pipe(
|
53
|
+
shareReplay(1)
|
54
|
+
)
|
55
|
+
|
56
|
+
const seriesLabels$ = seriesLabelsObservable({
|
57
|
+
computedData$: observer.computedData$,
|
58
|
+
})
|
59
|
+
|
60
|
+
|
61
|
+
const SeriesDataMap$ = seriesDataMapObservable({
|
62
|
+
datumList$
|
63
|
+
}).pipe(
|
64
|
+
shareReplay(1)
|
65
|
+
)
|
66
|
+
|
67
|
+
const seriesContainerPosition$ = seriesContainerPositionObservable({
|
68
|
+
computedData$: observer.computedData$,
|
69
|
+
fullDataFormatter$: observer.fullDataFormatter$,
|
70
|
+
layout$: observer.layout$,
|
71
|
+
}).pipe(
|
72
|
+
shareReplay(1)
|
73
|
+
)
|
74
|
+
|
75
|
+
const SeriesContainerPositionMap$ = seriesContainerPositionMapObservable({
|
76
|
+
seriesContainerPosition$: seriesContainerPosition$,
|
77
|
+
seriesLabels$: seriesLabels$,
|
78
|
+
separateSeries$: separateSeries$,
|
79
|
+
}).pipe(
|
80
|
+
shareReplay(1)
|
81
|
+
)
|
82
|
+
|
83
|
+
return {
|
84
|
+
fullParams$: observer.fullParams$,
|
85
|
+
fullChartParams$: observer.fullChartParams$,
|
86
|
+
fullDataFormatter$: observer.fullDataFormatter$,
|
87
|
+
computedData$: observer.computedData$,
|
88
|
+
layout$: observer.layout$,
|
89
|
+
textSizePx$,
|
90
|
+
visibleComputedData$,
|
91
|
+
visibleComputedLayoutData$,
|
92
|
+
separateSeries$,
|
93
|
+
computedLayoutData$,
|
94
|
+
seriesHighlight$,
|
95
|
+
seriesLabels$,
|
96
|
+
SeriesDataMap$,
|
97
|
+
seriesContainerPosition$,
|
98
|
+
SeriesContainerPositionMap$,
|
99
|
+
}
|
100
|
+
}
|
@@ -1,42 +1,42 @@
|
|
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
|
-
gap: {
|
28
|
-
toBeTypes: ['number']
|
29
|
-
},
|
30
|
-
rowAmount: {
|
31
|
-
toBeTypes: ['number']
|
32
|
-
},
|
33
|
-
columnAmount: {
|
34
|
-
toBeTypes: ['number']
|
35
|
-
}
|
36
|
-
})
|
37
|
-
if (containerResult.status === 'error') {
|
38
|
-
return containerResult
|
39
|
-
}
|
40
|
-
}
|
41
|
-
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
|
+
gap: {
|
28
|
+
toBeTypes: ['number']
|
29
|
+
},
|
30
|
+
rowAmount: {
|
31
|
+
toBeTypes: ['number']
|
32
|
+
},
|
33
|
+
columnAmount: {
|
34
|
+
toBeTypes: ['number']
|
35
|
+
}
|
36
|
+
})
|
37
|
+
if (containerResult.status === 'error') {
|
38
|
+
return containerResult
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return result
|
42
42
|
}
|
@@ -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,130 +1,130 @@
|
|
1
|
-
import type { DataTree, DataTreeObj, DataTreeDatum, ComputedDataFn, ComputedDataTree } from '../../lib/core-types'
|
2
|
-
import { isPlainObject } from '../utils/commonUtils'
|
3
|
-
import { seriesColorPredicate } from '../utils/orbchartsUtils'
|
4
|
-
|
5
|
-
export const computedDataFn: ComputedDataFn<'tree'> = (context) => {
|
6
|
-
const { data = [], dataFormatter, chartParams } = context
|
7
|
-
|
8
|
-
// <categoryLabel, categoryIndex>
|
9
|
-
const CategoryIndexMap = new Map<string, number>(
|
10
|
-
dataFormatter.categoryLabels.map((label, index) => [label, index])
|
11
|
-
)
|
12
|
-
|
13
|
-
let computedBranchData: ComputedDataTree = {
|
14
|
-
id: '',
|
15
|
-
index: 0,
|
16
|
-
label: '',
|
17
|
-
description: '',
|
18
|
-
categoryIndex: 0,
|
19
|
-
categoryLabel: '',
|
20
|
-
color: '',
|
21
|
-
visible: true,
|
22
|
-
// tooltipContent: '',
|
23
|
-
data: {},
|
24
|
-
value: 0,
|
25
|
-
level: 0,
|
26
|
-
seq: 0,
|
27
|
-
children: []
|
28
|
-
}
|
29
|
-
|
30
|
-
try {
|
31
|
-
// 建立樹狀結構資料
|
32
|
-
const dataTreeObj: DataTreeObj = (function () {
|
33
|
-
if (isPlainObject(data) === true) {
|
34
|
-
// 原本就是樹狀結構則直接複製
|
35
|
-
// return structuredClone(data) as DataTreeObj
|
36
|
-
return JSON.parse(JSON.stringify(data)) as DataTreeObj
|
37
|
-
} else if (Array.isArray(data) === false) {
|
38
|
-
return {
|
39
|
-
id: ''
|
40
|
-
}
|
41
|
-
}
|
42
|
-
// -- 陣列格式轉物件 --
|
43
|
-
// let rootId = ''
|
44
|
-
let root: DataTreeDatum | undefined = undefined
|
45
|
-
// const DataMap: Map<string, DataTreeDatum> = new Map()
|
46
|
-
const ChildrenMap: Map<string, DataTreeDatum[]> = new Map()
|
47
|
-
;(data as DataTreeDatum[]).forEach(d => {
|
48
|
-
// DataMap.set(d.id, d)
|
49
|
-
|
50
|
-
if (!d.parent) {
|
51
|
-
// rootId = d.id
|
52
|
-
root = d
|
53
|
-
} else {
|
54
|
-
const children: DataTreeDatum[] = ChildrenMap.get(d.parent) ?? []
|
55
|
-
children.push(d)
|
56
|
-
ChildrenMap.set(d.parent!, children)
|
57
|
-
}
|
58
|
-
})
|
59
|
-
|
60
|
-
const createBranchData = (root: DataTreeDatum): DataTreeObj => {
|
61
|
-
return {
|
62
|
-
id: root.id,
|
63
|
-
label: root.label,
|
64
|
-
data: root.data,
|
65
|
-
// tooltipContent: root.tooltipContent,
|
66
|
-
value: root.value,
|
67
|
-
categoryLabel: root.categoryLabel,
|
68
|
-
children: (ChildrenMap.get(root.id) ?? []).map(d => {
|
69
|
-
// 遞迴
|
70
|
-
return createBranchData(d)
|
71
|
-
})
|
72
|
-
}
|
73
|
-
}
|
74
|
-
if (root) {
|
75
|
-
return createBranchData(root)
|
76
|
-
} else {
|
77
|
-
return {
|
78
|
-
id: ''
|
79
|
-
}
|
80
|
-
}
|
81
|
-
})()
|
82
|
-
|
83
|
-
let index = 0
|
84
|
-
|
85
|
-
const formatBranchData = (branch: DataTreeObj, level: number, seq: number): ComputedDataTree => {
|
86
|
-
const childLayer = level + 1
|
87
|
-
const categoryLabel: string | null = branch.categoryLabel ?? null
|
88
|
-
let categoryIndex = 0
|
89
|
-
if (categoryLabel != null) {
|
90
|
-
if (!CategoryIndexMap.has(categoryLabel)) {
|
91
|
-
CategoryIndexMap.set(categoryLabel, CategoryIndexMap.size)
|
92
|
-
}
|
93
|
-
categoryIndex = CategoryIndexMap.get(categoryLabel) ?? 0
|
94
|
-
}
|
95
|
-
|
96
|
-
const currentIndex = index
|
97
|
-
index++
|
98
|
-
const formattedBranchData: ComputedDataTree = {
|
99
|
-
id: branch.id,
|
100
|
-
index: currentIndex,
|
101
|
-
level,
|
102
|
-
seq,
|
103
|
-
label: branch.label ?? '',
|
104
|
-
description: branch.description ?? '',
|
105
|
-
categoryIndex,
|
106
|
-
categoryLabel,
|
107
|
-
color: seriesColorPredicate(categoryIndex, chartParams),
|
108
|
-
data: branch.data ?? {},
|
109
|
-
// tooltipContent: branch.tooltipContent ? branch.tooltipContent : dataFormatter.tooltipContentFormat(branch, level, seq, context),
|
110
|
-
value: branch.value,
|
111
|
-
visible: true, // 先給預設值
|
112
|
-
children: (branch.children ?? []).map((d, i) => {
|
113
|
-
// 遞迴
|
114
|
-
return formatBranchData(d, childLayer, i)
|
115
|
-
})
|
116
|
-
}
|
117
|
-
|
118
|
-
formattedBranchData.visible = dataFormatter.visibleFilter(formattedBranchData, context)
|
119
|
-
|
120
|
-
return formattedBranchData
|
121
|
-
}
|
122
|
-
computedBranchData = formatBranchData(dataTreeObj, 0, 0)
|
123
|
-
} catch (e) {
|
124
|
-
// console.error(e)
|
125
|
-
throw Error(e)
|
126
|
-
}
|
127
|
-
|
128
|
-
return computedBranchData
|
129
|
-
|
130
|
-
}
|
1
|
+
import type { DataTree, DataTreeObj, DataTreeDatum, ComputedDataFn, ComputedDataTree } from '../../lib/core-types'
|
2
|
+
import { isPlainObject } from '../utils/commonUtils'
|
3
|
+
import { seriesColorPredicate } from '../utils/orbchartsUtils'
|
4
|
+
|
5
|
+
export const computedDataFn: ComputedDataFn<'tree'> = (context) => {
|
6
|
+
const { data = [], dataFormatter, chartParams } = context
|
7
|
+
|
8
|
+
// <categoryLabel, categoryIndex>
|
9
|
+
const CategoryIndexMap = new Map<string, number>(
|
10
|
+
dataFormatter.categoryLabels.map((label, index) => [label, index])
|
11
|
+
)
|
12
|
+
|
13
|
+
let computedBranchData: ComputedDataTree = {
|
14
|
+
id: '',
|
15
|
+
index: 0,
|
16
|
+
label: '',
|
17
|
+
description: '',
|
18
|
+
categoryIndex: 0,
|
19
|
+
categoryLabel: '',
|
20
|
+
color: '',
|
21
|
+
visible: true,
|
22
|
+
// tooltipContent: '',
|
23
|
+
data: {},
|
24
|
+
value: 0,
|
25
|
+
level: 0,
|
26
|
+
seq: 0,
|
27
|
+
children: []
|
28
|
+
}
|
29
|
+
|
30
|
+
try {
|
31
|
+
// 建立樹狀結構資料
|
32
|
+
const dataTreeObj: DataTreeObj = (function () {
|
33
|
+
if (isPlainObject(data) === true) {
|
34
|
+
// 原本就是樹狀結構則直接複製
|
35
|
+
// return structuredClone(data) as DataTreeObj
|
36
|
+
return JSON.parse(JSON.stringify(data)) as DataTreeObj
|
37
|
+
} else if (Array.isArray(data) === false) {
|
38
|
+
return {
|
39
|
+
id: ''
|
40
|
+
}
|
41
|
+
}
|
42
|
+
// -- 陣列格式轉物件 --
|
43
|
+
// let rootId = ''
|
44
|
+
let root: DataTreeDatum | undefined = undefined
|
45
|
+
// const DataMap: Map<string, DataTreeDatum> = new Map()
|
46
|
+
const ChildrenMap: Map<string, DataTreeDatum[]> = new Map()
|
47
|
+
;(data as DataTreeDatum[]).forEach(d => {
|
48
|
+
// DataMap.set(d.id, d)
|
49
|
+
|
50
|
+
if (!d.parent) {
|
51
|
+
// rootId = d.id
|
52
|
+
root = d
|
53
|
+
} else {
|
54
|
+
const children: DataTreeDatum[] = ChildrenMap.get(d.parent) ?? []
|
55
|
+
children.push(d)
|
56
|
+
ChildrenMap.set(d.parent!, children)
|
57
|
+
}
|
58
|
+
})
|
59
|
+
|
60
|
+
const createBranchData = (root: DataTreeDatum): DataTreeObj => {
|
61
|
+
return {
|
62
|
+
id: root.id,
|
63
|
+
label: root.label,
|
64
|
+
data: root.data,
|
65
|
+
// tooltipContent: root.tooltipContent,
|
66
|
+
value: root.value,
|
67
|
+
categoryLabel: root.categoryLabel,
|
68
|
+
children: (ChildrenMap.get(root.id) ?? []).map(d => {
|
69
|
+
// 遞迴
|
70
|
+
return createBranchData(d)
|
71
|
+
})
|
72
|
+
}
|
73
|
+
}
|
74
|
+
if (root) {
|
75
|
+
return createBranchData(root)
|
76
|
+
} else {
|
77
|
+
return {
|
78
|
+
id: ''
|
79
|
+
}
|
80
|
+
}
|
81
|
+
})()
|
82
|
+
|
83
|
+
let index = 0
|
84
|
+
|
85
|
+
const formatBranchData = (branch: DataTreeObj, level: number, seq: number): ComputedDataTree => {
|
86
|
+
const childLayer = level + 1
|
87
|
+
const categoryLabel: string | null = branch.categoryLabel ?? null
|
88
|
+
let categoryIndex = 0
|
89
|
+
if (categoryLabel != null) {
|
90
|
+
if (!CategoryIndexMap.has(categoryLabel)) {
|
91
|
+
CategoryIndexMap.set(categoryLabel, CategoryIndexMap.size)
|
92
|
+
}
|
93
|
+
categoryIndex = CategoryIndexMap.get(categoryLabel) ?? 0
|
94
|
+
}
|
95
|
+
|
96
|
+
const currentIndex = index
|
97
|
+
index++
|
98
|
+
const formattedBranchData: ComputedDataTree = {
|
99
|
+
id: branch.id,
|
100
|
+
index: currentIndex,
|
101
|
+
level,
|
102
|
+
seq,
|
103
|
+
label: branch.label ?? '',
|
104
|
+
description: branch.description ?? '',
|
105
|
+
categoryIndex,
|
106
|
+
categoryLabel,
|
107
|
+
color: seriesColorPredicate(categoryIndex, chartParams),
|
108
|
+
data: branch.data ?? {},
|
109
|
+
// tooltipContent: branch.tooltipContent ? branch.tooltipContent : dataFormatter.tooltipContentFormat(branch, level, seq, context),
|
110
|
+
value: branch.value,
|
111
|
+
visible: true, // 先給預設值
|
112
|
+
children: (branch.children ?? []).map((d, i) => {
|
113
|
+
// 遞迴
|
114
|
+
return formatBranchData(d, childLayer, i)
|
115
|
+
})
|
116
|
+
}
|
117
|
+
|
118
|
+
formattedBranchData.visible = dataFormatter.visibleFilter(formattedBranchData, context)
|
119
|
+
|
120
|
+
return formattedBranchData
|
121
|
+
}
|
122
|
+
computedBranchData = formatBranchData(dataTreeObj, 0, 0)
|
123
|
+
} catch (e) {
|
124
|
+
// console.error(e)
|
125
|
+
throw Error(e)
|
126
|
+
}
|
127
|
+
|
128
|
+
return computedBranchData
|
129
|
+
|
130
|
+
}
|