@orbcharts/core 3.0.0-beta.1 → 3.0.0-beta.11
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/dist/orbcharts-core.es.js +3271 -2862
- package/dist/orbcharts-core.umd.js +4 -4
- package/dist/src/defaults.d.ts +24 -23
- package/dist/src/utils/d3Scale.d.ts +28 -0
- package/dist/src/utils/gridObservables.d.ts +29 -19
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/multiGridObservables.d.ts +2 -2
- package/dist/src/utils/multiValueObservables.d.ts +73 -0
- package/dist/src/utils/orbchartsUtils.d.ts +24 -10
- package/dist/src/utils/relationshipObservables.d.ts +13 -0
- package/dist/src/utils/seriesObservables.d.ts +4 -4
- package/dist/src/utils/treeObservables.d.ts +2 -5
- package/package.json +2 -2
- package/src/GridChart.ts +2 -2
- package/src/MultiGridChart.ts +2 -2
- package/src/MultiValueChart.ts +2 -2
- package/src/RelationshipChart.ts +2 -2
- package/src/SeriesChart.ts +2 -2
- package/src/TreeChart.ts +2 -2
- package/src/base/createBaseChart.ts +13 -13
- package/src/base/validators/chartParamsValidator.ts +6 -6
- package/src/defaults.ts +87 -47
- package/src/grid/computedDataFn.ts +4 -4
- package/src/grid/contextObserverCallback.ts +58 -37
- package/src/grid/dataFormatterValidator.ts +14 -14
- package/src/multiGrid/computedDataFn.ts +2 -2
- package/src/multiValue/computedDataFn.ts +81 -147
- package/src/multiValue/contextObserverCallback.ts +150 -2
- package/src/relationship/computedDataFn.ts +94 -60
- package/src/relationship/contextObserverCallback.ts +68 -0
- package/src/tree/computedDataFn.ts +9 -10
- package/src/tree/contextObserverCallback.ts +6 -9
- package/src/utils/d3Scale.ts +198 -0
- package/src/utils/gridObservables.ts +320 -248
- package/src/utils/index.ts +1 -1
- package/src/utils/multiGridObservables.ts +75 -49
- package/src/utils/multiValueObservables.ts +662 -0
- package/src/utils/observables.ts +30 -12
- package/src/utils/orbchartsUtils.ts +90 -65
- package/src/utils/relationshipObservables.ts +85 -0
- package/src/utils/seriesObservables.ts +7 -7
- package/src/utils/treeObservables.ts +44 -33
- package/src/utils/validator.ts +5 -4
- package/dist/src/utils/d3Utils.d.ts +0 -19
- package/src/utils/d3Utils.ts +0 -108
package/src/utils/observables.ts
CHANGED
@@ -45,6 +45,15 @@ export function resizeObservable(elem: HTMLElement | Element): Observable<DOMRec
|
|
45
45
|
})
|
46
46
|
}
|
47
47
|
|
48
|
+
interface HighlightTargetValue {
|
49
|
+
id: string | null
|
50
|
+
label: string | null
|
51
|
+
seriesLabel: string | null
|
52
|
+
groupLabel: string | null
|
53
|
+
categoryLabel: string | null
|
54
|
+
highlightDefault: string | null
|
55
|
+
}
|
56
|
+
|
48
57
|
// 通用 highlight Observable
|
49
58
|
export const highlightObservable = <T extends ChartType, D>({ datumList$, fullChartParams$, event$ }: {
|
50
59
|
datumList$: Observable<D[]>
|
@@ -54,11 +63,12 @@ export const highlightObservable = <T extends ChartType, D>({ datumList$, fullCh
|
|
54
63
|
const destroy$ = new Subject()
|
55
64
|
|
56
65
|
// 預設的highlight
|
57
|
-
const highlightDefault
|
66
|
+
const highlightDefault$: Observable<HighlightTargetValue> = fullChartParams$.pipe(
|
58
67
|
takeUntil(destroy$),
|
59
68
|
map(d => {
|
60
69
|
return {
|
61
70
|
id: null,
|
71
|
+
label: null,
|
62
72
|
seriesLabel: null,
|
63
73
|
groupLabel: null,
|
64
74
|
categoryLabel: null,
|
@@ -69,22 +79,25 @@ export const highlightObservable = <T extends ChartType, D>({ datumList$, fullCh
|
|
69
79
|
)
|
70
80
|
|
71
81
|
// 事件觸發的highlight
|
72
|
-
const highlightMouseover
|
82
|
+
const highlightMouseover$: Observable<HighlightTargetValue> = event$.pipe(
|
73
83
|
takeUntil(destroy$),
|
74
84
|
// filter(d => d.eventName === 'mouseover' || d.eventName === 'mousemove'),
|
75
85
|
filter(d => d.eventName === 'mouseover'),
|
76
86
|
// distinctUntilChanged((prev, current) => prev.eventName === current.eventName)
|
77
|
-
map(
|
78
|
-
|
87
|
+
map(_d => {
|
88
|
+
const d = _d as any
|
89
|
+
return d.datum
|
79
90
|
? {
|
80
|
-
id:
|
81
|
-
|
82
|
-
|
83
|
-
|
91
|
+
id: d.datum.id,
|
92
|
+
label: d.datum.label,
|
93
|
+
seriesLabel: d.datum.seriesLabel,
|
94
|
+
groupLabel: d.datum.groupLabel,
|
95
|
+
categoryLabel: d.datum.categoryLabel,
|
84
96
|
highlightDefault: null
|
85
97
|
}
|
86
98
|
: {
|
87
99
|
id: null,
|
100
|
+
label: null,
|
88
101
|
seriesLabel: null,
|
89
102
|
groupLabel: null,
|
90
103
|
categoryLabel: null,
|
@@ -102,9 +115,14 @@ export const highlightObservable = <T extends ChartType, D>({ datumList$, fullCh
|
|
102
115
|
switchMap(d => highlightDefault$)
|
103
116
|
)
|
104
117
|
|
105
|
-
function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null) {
|
106
|
-
|
107
|
-
|
118
|
+
// function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null) {
|
119
|
+
// const datum = datumList.find(d => (d as ComputedDatumBase).id === id)
|
120
|
+
// return datum ? [datum] : []
|
121
|
+
// }
|
122
|
+
function getDatumIds (datumList: ComputedDatumTypeMap<T>[], id: string | null, label: string | null) {
|
123
|
+
return id == null && label == null
|
124
|
+
? []
|
125
|
+
: datumList.filter(d => (d as ComputedDatumBase).id === id || (d as ComputedDatumBase).label === label)
|
108
126
|
}
|
109
127
|
|
110
128
|
function getSeriesIds (datumList: ComputedDatumTypeMap<T>[], seriesLabel: string | null) {
|
@@ -136,7 +154,7 @@ export const highlightObservable = <T extends ChartType, D>({ datumList$, fullCh
|
|
136
154
|
).subscribe(data => {
|
137
155
|
let datumList: ComputedDatumTypeMap<T>[] = []
|
138
156
|
if (data.fullChartParams.highlightTarget === 'datum') {
|
139
|
-
datumList = getDatumIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.id)
|
157
|
+
datumList = getDatumIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.id, data.target.label)
|
140
158
|
} else if (data.fullChartParams.highlightTarget === 'series') {
|
141
159
|
datumList = getSeriesIds(data.datumList as ComputedDatumTypeMap<T>[], data.target.seriesLabel)
|
142
160
|
} else if (data.fullChartParams.highlightTarget === 'group') {
|
@@ -13,11 +13,12 @@ import type {
|
|
13
13
|
DataMultiValue,
|
14
14
|
DataMultiValueDatum,
|
15
15
|
DataMultiValueValue,
|
16
|
+
ComputedLayoutDatumMultiValue,
|
16
17
|
DataFormatterContainer,
|
17
18
|
SeriesDirection,
|
18
19
|
DataFormatterGridGrid,
|
19
|
-
|
20
|
-
|
20
|
+
ContainerPosition,
|
21
|
+
ContainerPositionScaled,
|
21
22
|
Layout
|
22
23
|
} from '../../lib/core-types'
|
23
24
|
import { isPlainObject } from './commonUtils'
|
@@ -29,8 +30,11 @@ export function formatValueToLabel (value: any, valueFormatter: string | ((text:
|
|
29
30
|
return d3.format(valueFormatter as string)!(value)
|
30
31
|
}
|
31
32
|
|
32
|
-
export function createDefaultDatumId (chartTypeOrPrefix: string, levelOneIndex: number, levelTwoIndex
|
33
|
-
let text = `${chartTypeOrPrefix}_${levelOneIndex}
|
33
|
+
export function createDefaultDatumId (chartTypeOrPrefix: string, levelOneIndex: number, levelTwoIndex?: number, levelThreeIndex?: number) {
|
34
|
+
let text = `${chartTypeOrPrefix}_${levelOneIndex}`
|
35
|
+
if (levelTwoIndex != null) {
|
36
|
+
text += `_${levelTwoIndex}`
|
37
|
+
}
|
34
38
|
if (levelThreeIndex != null) {
|
35
39
|
text += `_${levelThreeIndex}`
|
36
40
|
}
|
@@ -45,6 +49,11 @@ export function createDefaultGroupLabel (chartTypeOrPrefix: string, groupIndex:
|
|
45
49
|
return `${chartTypeOrPrefix}_group${groupIndex}`
|
46
50
|
}
|
47
51
|
|
52
|
+
export function createDefaultCategoryLabel () {
|
53
|
+
// return `${chartTypeOrPrefix}_category`
|
54
|
+
return '' // 空值
|
55
|
+
}
|
56
|
+
|
48
57
|
export function createGridSeriesLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'grid' }: {
|
49
58
|
transposedDataGrid: DataGridDatum[][],
|
50
59
|
dataFormatterGrid: DataFormatterGridGrid
|
@@ -114,76 +123,125 @@ export function createMultiGridGroupLabels ({ transposedDataGrid, dataFormatterG
|
|
114
123
|
}
|
115
124
|
|
116
125
|
// 取得最小及最大值 - 數字陣列
|
117
|
-
export function
|
118
|
-
const
|
126
|
+
export function getMinMax (data: number[]): [number, number] {
|
127
|
+
const defaultMinMax: [number, number] = [0, 0] // default
|
119
128
|
if (!data.length) {
|
120
|
-
return
|
129
|
+
return defaultMinMax
|
121
130
|
}
|
122
|
-
const
|
131
|
+
const minMax: [number, number] = data.reduce((prev, current) => {
|
123
132
|
// [min, max]
|
124
133
|
return [
|
125
134
|
current < prev[0] ? current : prev[0],
|
126
135
|
current > prev[1] ? current : prev[1]
|
127
136
|
]
|
128
137
|
}, [data[0], data[0]])
|
129
|
-
return
|
138
|
+
return minMax
|
130
139
|
}
|
131
140
|
|
132
141
|
// 取得最小及最大值 - datum格式陣列資料
|
133
|
-
export function
|
142
|
+
export function getMinMaxValue (data: DatumValue[]): [number, number] {
|
134
143
|
const arr = data
|
135
144
|
.filter(d => d != null && d.value != null)
|
136
145
|
.map(d => d.value )
|
137
|
-
return
|
146
|
+
return getMinMax(arr)
|
138
147
|
}
|
139
148
|
|
140
149
|
// 取得最小及最大值 - Series Data
|
141
|
-
export function
|
150
|
+
export function getMinMaxSeries (data: DataSeries): [number, number] {
|
142
151
|
const flatData: (DataSeriesValue | DataSeriesDatum)[] = data[0] && Array.isArray((data as (DataSeriesValue | DataSeriesDatum)[][])[0])
|
143
152
|
? data.flat()
|
144
153
|
: data as (DataSeriesValue | DataSeriesDatum)[]
|
145
154
|
const arr = flatData
|
146
155
|
.filter(d => (d == null || (isPlainObject(d) && (d as DataSeriesDatum).value == null)) === false) // 過濾掉null &
|
147
156
|
.map(d => typeof d === 'number' ? d : d.value )
|
148
|
-
return
|
157
|
+
return getMinMax(arr)
|
149
158
|
}
|
150
159
|
|
151
160
|
// 取得最小及最大值 - Grid Data
|
152
|
-
export function
|
161
|
+
export function getMinMaxGrid (data: DataGrid): [number, number] {
|
153
162
|
const flatData: (DataGridValue | DataGridDatum)[] = data.flat()
|
154
163
|
const arr = flatData
|
155
164
|
.filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
|
156
165
|
.map(d => typeof d === 'number' ? d : d.value )
|
157
|
-
return
|
166
|
+
return getMinMax(arr)
|
158
167
|
}
|
159
168
|
|
160
169
|
// 取得最小及最大值 - MultiGrid Data
|
161
|
-
export function
|
170
|
+
export function getMinMaxMultiGrid (data: DataMultiGrid): [number, number] {
|
162
171
|
const flatData: (DataGridValue | DataGridDatum)[] = data.flat().flat()
|
163
172
|
const arr = flatData
|
164
173
|
.filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
|
165
174
|
.map(d => typeof d === 'number' ? d : d.value )
|
166
|
-
return
|
175
|
+
return getMinMax(arr)
|
167
176
|
}
|
168
177
|
|
169
178
|
// 取得最小及最大值 - MultiValue Data
|
170
|
-
export function
|
171
|
-
const
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
179
|
+
export function getMinMaxMultiValue (data: DataMultiValue, valueIndex: number): [number, number] {
|
180
|
+
const arr: number[] = data
|
181
|
+
.map(d => {
|
182
|
+
if (Array.isArray(d)) {
|
183
|
+
return d[valueIndex] ?? null
|
184
|
+
} else if (isPlainObject(d)) {
|
185
|
+
return (d as DataMultiValueDatum).value[valueIndex] ?? null
|
186
|
+
} else {
|
187
|
+
return null
|
188
|
+
}
|
189
|
+
})
|
190
|
+
.filter(d => d != null)
|
191
|
+
return getMinMax(arr)
|
192
|
+
}
|
193
|
+
|
194
|
+
export function getMinMaxMultiValueXY ({ data, minX, maxX, minY, maxY }: {
|
195
|
+
data: ComputedLayoutDatumMultiValue[][]
|
196
|
+
minX: number
|
197
|
+
maxX: number
|
198
|
+
minY: number
|
199
|
+
maxY: number
|
200
|
+
}) {
|
201
|
+
let filteredData: ComputedLayoutDatumMultiValue[][] = []
|
202
|
+
let minXDatum: ComputedLayoutDatumMultiValue | null = null
|
203
|
+
let maxXDatum: ComputedLayoutDatumMultiValue | null = null
|
204
|
+
let minYDatum: ComputedLayoutDatumMultiValue | null = null
|
205
|
+
let maxYDatum: ComputedLayoutDatumMultiValue | null = null
|
206
|
+
|
207
|
+
for (let categoryData of data) {
|
208
|
+
for (let datum of categoryData) {
|
209
|
+
if (datum.axisX >= minX && datum.axisX <= maxX && datum.axisY >= minY && datum.axisY <= maxY) {
|
210
|
+
filteredData.push(categoryData)
|
211
|
+
if (minXDatum == null || datum.axisX < minXDatum.axisX) {
|
212
|
+
minXDatum = datum
|
213
|
+
}
|
214
|
+
if (maxXDatum == null || datum.axisX > maxXDatum.axisX) {
|
215
|
+
maxXDatum = datum
|
216
|
+
}
|
217
|
+
if (minYDatum == null || datum.axisY < minYDatum.axisY) {
|
218
|
+
minYDatum = datum
|
219
|
+
}
|
220
|
+
if (maxYDatum == null || datum.axisY > maxYDatum.axisY) {
|
221
|
+
maxYDatum = datum
|
222
|
+
}
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
return {
|
228
|
+
minXDatum,
|
229
|
+
maxXDatum,
|
230
|
+
minYDatum,
|
231
|
+
maxYDatum,
|
232
|
+
filteredData
|
233
|
+
}
|
176
234
|
}
|
177
235
|
|
178
236
|
// @Q@ 待處理
|
179
237
|
// // 取得最小及最大值 - Relationship Data
|
180
|
-
// export function
|
238
|
+
// export function getMinMaxRelationship (data: DataRelationship, target: 'nodes' | 'edges' = 'nodes'): [number, number] {
|
181
239
|
|
182
240
|
// }
|
183
241
|
|
184
242
|
// @Q@ 待處理
|
185
243
|
// // 取得最小及最大值 - Tree Data
|
186
|
-
// export function
|
244
|
+
// export function getMinMaxTree (data: DataTree): [number, number] {
|
187
245
|
|
188
246
|
// }
|
189
247
|
|
@@ -213,31 +271,13 @@ export function transposeData<T> (seriesDirection: SeriesDirection, data: T[][])
|
|
213
271
|
|
214
272
|
|
215
273
|
export function seriesColorPredicate (seriesIndex: number, chartParams: ChartParams) {
|
216
|
-
return seriesIndex < chartParams.colors[chartParams.colorScheme].
|
217
|
-
? chartParams.colors[chartParams.colorScheme].
|
218
|
-
: chartParams.colors[chartParams.colorScheme].
|
219
|
-
seriesIndex % chartParams.colors[chartParams.colorScheme].
|
274
|
+
return seriesIndex < chartParams.colors[chartParams.colorScheme].label.length
|
275
|
+
? chartParams.colors[chartParams.colorScheme].label[seriesIndex]
|
276
|
+
: chartParams.colors[chartParams.colorScheme].label[
|
277
|
+
seriesIndex % chartParams.colors[chartParams.colorScheme].label.length
|
220
278
|
]
|
221
279
|
}
|
222
280
|
|
223
|
-
// export function calcSeriesContainerPosition (layout: Layout, container: DataFormatterContainer, rowIndex: number, columnIndex: number) {
|
224
|
-
// const { gap, rowAmount, columnAmount } = container
|
225
|
-
// const width = (layout.width - (gap * (columnAmount - 1))) / columnAmount
|
226
|
-
// const height = (layout.height - (gap * (rowAmount - 1))) / rowAmount
|
227
|
-
// const x = columnIndex * width + (columnIndex * gap)
|
228
|
-
// const y = rowIndex * height + (rowIndex * gap)
|
229
|
-
// // const translate: [number, number] = [x, y]
|
230
|
-
|
231
|
-
// return {
|
232
|
-
// // translate,
|
233
|
-
// startX: x,
|
234
|
-
// startY: y,
|
235
|
-
// centerX: x + width / 2,
|
236
|
-
// centerY: y + height / 2,
|
237
|
-
// width,
|
238
|
-
// height
|
239
|
-
// }
|
240
|
-
// }
|
241
281
|
|
242
282
|
// 計算預設欄列數量
|
243
283
|
// 規則1.rowAmount*columnAmount要大於或等於amount,並且數字要盡可能小
|
@@ -251,7 +291,7 @@ function calcGridDimensions (amount: number): { rowAmount: number; columnAmount:
|
|
251
291
|
return { rowAmount, columnAmount }
|
252
292
|
}
|
253
293
|
|
254
|
-
export function calcSeriesContainerLayout (layout: Layout, container: DataFormatterContainer, amount: number):
|
294
|
+
export function calcSeriesContainerLayout (layout: Layout, container: DataFormatterContainer, amount: number): ContainerPosition[] {
|
255
295
|
const { gap } = container
|
256
296
|
const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
|
257
297
|
// 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
|
@@ -284,22 +324,7 @@ export function calcSeriesContainerLayout (layout: Layout, container: DataFormat
|
|
284
324
|
})
|
285
325
|
}
|
286
326
|
|
287
|
-
|
288
|
-
// const { gap, rowAmount, columnAmount } = container
|
289
|
-
// const width = (layout.width - (gap * (columnAmount - 1))) / columnAmount
|
290
|
-
// const height = (layout.height - (gap * (rowAmount - 1))) / rowAmount
|
291
|
-
// const x = columnIndex * width + (columnIndex * gap)
|
292
|
-
// const y = rowIndex * height + (rowIndex * gap)
|
293
|
-
// const translate: [number, number] = [x, y]
|
294
|
-
// const scale: [number, number] = [width / layout.width, height / layout.height]
|
295
|
-
|
296
|
-
// return {
|
297
|
-
// translate,
|
298
|
-
// scale
|
299
|
-
// }
|
300
|
-
// }
|
301
|
-
|
302
|
-
export function calcGridContainerLayout (layout: Layout, container: DataFormatterContainer, amount: number): GridContainerPosition[] {
|
327
|
+
export function calcGridContainerLayout (layout: Layout, container: DataFormatterContainer, amount: number): ContainerPositionScaled[] {
|
303
328
|
const { gap } = container
|
304
329
|
const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
|
305
330
|
// 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
|
@@ -318,7 +343,7 @@ export function calcGridContainerLayout (layout: Layout, container: DataFormatte
|
|
318
343
|
const translate: [number, number] = [x, y]
|
319
344
|
const scale: [number, number] = [width / layout.width, height / layout.height]
|
320
345
|
|
321
|
-
return {
|
346
|
+
return {
|
322
347
|
slotIndex: index,
|
323
348
|
rowIndex,
|
324
349
|
columnIndex,
|
@@ -0,0 +1,85 @@
|
|
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
|
+
ComputedDataRelationship,
|
15
|
+
ComputedDataTypeMap,
|
16
|
+
ComputedNode,
|
17
|
+
ComputedEdge,
|
18
|
+
DataFormatterTree } from '../../lib/core-types'
|
19
|
+
|
20
|
+
|
21
|
+
export const categoryLabelsObservable = (
|
22
|
+
CategoryNodeMap$: Observable<Map<string, ComputedNode[]>>,
|
23
|
+
CategoryEdgeMap$: Observable<Map<string, ComputedEdge[]>>
|
24
|
+
): Observable<string[]> => {
|
25
|
+
return combineLatest({
|
26
|
+
CategoryNodeMap: CategoryNodeMap$,
|
27
|
+
CategoryEdgeMap: CategoryEdgeMap$
|
28
|
+
}).pipe(
|
29
|
+
switchMap(async d => d),
|
30
|
+
map(data => {
|
31
|
+
return [...Array.from(data.CategoryNodeMap.keys()), ...Array.from(data.CategoryEdgeMap.keys())]
|
32
|
+
}),
|
33
|
+
distinctUntilChanged((a, b) => {
|
34
|
+
return JSON.stringify(a).length === JSON.stringify(b).length
|
35
|
+
}),
|
36
|
+
)
|
37
|
+
}
|
38
|
+
|
39
|
+
export const NodeMapObservable = (computedData$: Observable<ComputedDataRelationship>) => {
|
40
|
+
return computedData$.pipe(
|
41
|
+
map(data => {
|
42
|
+
const nodeMap = new Map<string, ComputedNode>()
|
43
|
+
data.nodes.forEach(node => {
|
44
|
+
nodeMap.set(node.id, node)
|
45
|
+
})
|
46
|
+
return nodeMap
|
47
|
+
}),
|
48
|
+
)
|
49
|
+
}
|
50
|
+
|
51
|
+
export const EdgeMapObservable = (computedData$: Observable<ComputedDataRelationship>) => {
|
52
|
+
return computedData$.pipe(
|
53
|
+
map(data => {
|
54
|
+
const edgeMap = new Map<string, ComputedEdge>()
|
55
|
+
data.edges.forEach(edge => {
|
56
|
+
edgeMap.set(edge.id, edge)
|
57
|
+
})
|
58
|
+
return edgeMap
|
59
|
+
}),
|
60
|
+
)
|
61
|
+
}
|
62
|
+
|
63
|
+
// 所有可見的節點
|
64
|
+
export const relationshipVisibleComputedDataObservable = ({ computedData$, NodeMap$ }: {
|
65
|
+
computedData$: Observable<ComputedDataRelationship>
|
66
|
+
NodeMap$: Observable<Map<string, ComputedNode>>
|
67
|
+
}) => {
|
68
|
+
return combineLatest({
|
69
|
+
computedData: computedData$,
|
70
|
+
NodeMap: NodeMap$
|
71
|
+
}).pipe(
|
72
|
+
switchMap(async d => d),
|
73
|
+
map(data => {
|
74
|
+
return {
|
75
|
+
nodes: data.computedData.nodes.filter(node => node.visible),
|
76
|
+
edges: data.computedData.edges
|
77
|
+
.filter(edge => edge.visible)
|
78
|
+
// 依照節點是否存在篩選
|
79
|
+
.filter(edge => {
|
80
|
+
return data.NodeMap.has(edge.startNode.id) && data.NodeMap.has(edge.endNode.id)
|
81
|
+
})
|
82
|
+
}
|
83
|
+
})
|
84
|
+
)
|
85
|
+
}
|
@@ -14,7 +14,7 @@ import type {
|
|
14
14
|
ComputedDatumSeries,
|
15
15
|
ComputedDataTypeMap,
|
16
16
|
DataFormatterTypeMap,
|
17
|
-
|
17
|
+
ContainerPosition,
|
18
18
|
Layout } from '../../lib/core-types'
|
19
19
|
import { calcSeriesContainerLayout } from './orbchartsUtils'
|
20
20
|
|
@@ -97,7 +97,7 @@ export const seriesContainerPositionObservable = ({ computedData$, fullDataForma
|
|
97
97
|
computedData$: Observable<ComputedDataTypeMap<'series'>>
|
98
98
|
fullDataFormatter$: Observable<DataFormatterTypeMap<'series'>>
|
99
99
|
layout$: Observable<Layout>
|
100
|
-
}): Observable<
|
100
|
+
}): Observable<ContainerPosition[]> => {
|
101
101
|
|
102
102
|
const gridContainerPosition$ = combineLatest({
|
103
103
|
computedData: computedData$,
|
@@ -113,7 +113,7 @@ export const seriesContainerPositionObservable = ({ computedData$, fullDataForma
|
|
113
113
|
// return data.computedData.map((seriesData, seriesIndex) => {
|
114
114
|
// const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
|
115
115
|
// const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
|
116
|
-
// const { startX, startY, centerX, centerY, width, height } =
|
116
|
+
// const { startX, startY, centerX, centerY, width, height } = calcContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
|
117
117
|
// return {
|
118
118
|
// slotIndex: seriesIndex,
|
119
119
|
// rowIndex,
|
@@ -132,7 +132,7 @@ export const seriesContainerPositionObservable = ({ computedData$, fullDataForma
|
|
132
132
|
// const columnIndex = 0
|
133
133
|
// const rowIndex = 0
|
134
134
|
// return data.computedData.map((seriesData, seriesIndex) => {
|
135
|
-
// const { startX, startY, centerX, centerY, width, height } =
|
135
|
+
// const { startX, startY, centerX, centerY, width, height } = calcContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
|
136
136
|
// return {
|
137
137
|
// slotIndex: 0,
|
138
138
|
// rowIndex,
|
@@ -153,7 +153,7 @@ export const seriesContainerPositionObservable = ({ computedData$, fullDataForma
|
|
153
153
|
}
|
154
154
|
|
155
155
|
export const seriesContainerPositionMapObservable = ({ seriesContainerPosition$, seriesLabels$, separateSeries$ }: {
|
156
|
-
seriesContainerPosition$: Observable<
|
156
|
+
seriesContainerPosition$: Observable<ContainerPosition[]>
|
157
157
|
seriesLabels$: Observable<string[]>
|
158
158
|
separateSeries$: Observable<boolean>
|
159
159
|
}) => {
|
@@ -165,10 +165,10 @@ export const seriesContainerPositionMapObservable = ({ seriesContainerPosition$,
|
|
165
165
|
switchMap(async (d) => d),
|
166
166
|
map(data => {
|
167
167
|
return data.separateSeries
|
168
|
-
? new Map<string,
|
168
|
+
? new Map<string, ContainerPosition>(data.seriesLabels.map((seriesLabel, seriesIndex) => {
|
169
169
|
return [seriesLabel, data.seriesContainerPosition[seriesIndex] ?? data.seriesContainerPosition[0]]
|
170
170
|
}))
|
171
|
-
: new Map<string,
|
171
|
+
: new Map<string, ContainerPosition>(data.seriesLabels.map((seriesLabel, seriesIndex) => {
|
172
172
|
return [seriesLabel, data.seriesContainerPosition[0]]
|
173
173
|
}))
|
174
174
|
})
|
@@ -34,42 +34,53 @@ export const nodeListObservable = ({ computedData$ }: { computedData$: Observabl
|
|
34
34
|
)
|
35
35
|
}
|
36
36
|
|
37
|
-
export const
|
38
|
-
|
39
|
-
|
40
|
-
}) => {
|
37
|
+
// export const categoryLabelsObservable = ({ nodeList$, fullDataFormatter$ }: {
|
38
|
+
// nodeList$: Observable<ComputedDataTree[]>
|
39
|
+
// fullDataFormatter$: Observable<DataFormatterTree>
|
40
|
+
// }) => {
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
// const categoryLabels$ = fullDataFormatter$.pipe(
|
43
|
+
// map(d => d.categoryLabels),
|
44
|
+
// distinctUntilChanged((a, b) => {
|
45
|
+
// return JSON.stringify(a).length === JSON.stringify(b).length
|
46
|
+
// }),
|
47
|
+
// )
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
49
|
+
// return combineLatest({
|
50
|
+
// nodeList: nodeList$,
|
51
|
+
// categoryLabels: categoryLabels$
|
52
|
+
// }).pipe(
|
53
|
+
// switchMap(async d => d),
|
54
|
+
// map(data => {
|
55
|
+
// const CurrentLabelSet = new Set(data.categoryLabels)
|
56
|
+
// const ExistLabelSet = new Set(
|
57
|
+
// data.nodeList.filter(node => node.visible).map(node => node.categoryLabel)
|
58
|
+
// )
|
59
|
+
// // 加入已存在的label(data.nodeList有,但是dataFormatter.categoryLabels沒有)
|
60
|
+
// Array.from(ExistLabelSet).forEach(label => {
|
61
|
+
// if (!CurrentLabelSet.has(label)) {
|
62
|
+
// CurrentLabelSet.add(label)
|
63
|
+
// }
|
64
|
+
// })
|
65
|
+
// // 移除不存在的label(dataFormatter.categoryLabels有,但是data.nodeList沒有)
|
66
|
+
// Array.from(CurrentLabelSet).forEach(label => {
|
67
|
+
// if (!ExistLabelSet.has(label)) {
|
68
|
+
// ExistLabelSet.delete(label)
|
69
|
+
// }
|
70
|
+
// })
|
71
71
|
|
72
|
-
|
72
|
+
// return Array.from(CurrentLabelSet)
|
73
|
+
// }),
|
74
|
+
// distinctUntilChanged((a, b) => {
|
75
|
+
// return JSON.stringify(a).length === JSON.stringify(b).length
|
76
|
+
// }),
|
77
|
+
// )
|
78
|
+
// }
|
79
|
+
|
80
|
+
export const categoryLabelsObservable = (CategoryDataMap$: Observable<Map<string, ComputedDataTree[]>>) => {
|
81
|
+
return CategoryDataMap$.pipe(
|
82
|
+
map(data => {
|
83
|
+
return Array.from(data.keys())
|
73
84
|
}),
|
74
85
|
distinctUntilChanged((a, b) => {
|
75
86
|
return JSON.stringify(a).length === JSON.stringify(b).length
|
package/src/utils/validator.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import type {
|
2
|
+
ColorType,
|
2
3
|
ValidatorResult,
|
3
4
|
ToBeTypes,
|
4
5
|
ToBeOption,
|
@@ -40,14 +41,14 @@ function getInvalidColumn<T> (data: T, rules: Partial<ValidatorRule<T>>) {
|
|
40
41
|
}
|
41
42
|
// "toBeOption" 的測試
|
42
43
|
const testOption: {[key in ToBeOption]: (value: any) => boolean} = {
|
43
|
-
ColorType: (value:
|
44
|
+
ColorType: (value: ColorType) => {
|
44
45
|
return value === 'none'
|
45
|
-
|| value === '
|
46
|
+
|| value === 'label'
|
46
47
|
|| value === 'primary'
|
47
48
|
|| value === 'secondary'
|
48
|
-
|| value === '
|
49
|
+
|| value === 'labelContrast'
|
49
50
|
|| value === 'background'
|
50
|
-
}
|
51
|
+
},
|
51
52
|
}
|
52
53
|
|
53
54
|
const failColumn = Object.keys(data).find((columnName: string) => {
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import * as d3 from 'd3';
|
2
|
-
export declare const createAxisLinearScale: ({ maxValue, minValue, axisWidth, scaleDomain, scaleRange, }: {
|
3
|
-
maxValue: number;
|
4
|
-
minValue: number;
|
5
|
-
axisWidth: number;
|
6
|
-
scaleDomain: [number | "min" | "auto", number | "max" | "auto"];
|
7
|
-
scaleRange: [number, number];
|
8
|
-
}) => d3.ScaleLinear<number, number, never>;
|
9
|
-
export declare const createAxisPointScale: ({ axisLabels, axisWidth, padding }: {
|
10
|
-
axisLabels: string[];
|
11
|
-
axisWidth: number;
|
12
|
-
padding?: number;
|
13
|
-
}) => d3.ScalePoint<string>;
|
14
|
-
export declare const createAxisQuantizeScale: ({ axisLabels, axisWidth, padding, reverse }: {
|
15
|
-
axisLabels: string[] | Date[];
|
16
|
-
axisWidth: number;
|
17
|
-
padding?: number;
|
18
|
-
reverse?: boolean;
|
19
|
-
}) => d3.ScaleQuantize<number, never>;
|