@orbcharts/core 3.0.0-beta.9 → 3.0.0
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 +2779 -2398
- package/dist/orbcharts-core.umd.js +4 -4
- package/dist/src/defaults.d.ts +2 -1
- package/dist/src/utils/gridObservables.d.ts +8 -4
- package/dist/src/utils/index.d.ts +0 -3
- package/dist/src/utils/multiGridObservables.d.ts +3 -2
- package/dist/src/utils/multiValueObservables.d.ts +76 -29
- package/dist/src/utils/observables.d.ts +8 -1
- package/dist/src/utils/orbchartsUtils.d.ts +9 -9
- package/dist/src/utils/seriesObservables.d.ts +1 -1
- package/package.json +2 -2
- package/src/base/createBaseChart.ts +4 -3
- package/src/base/createBasePlugin.ts +5 -4
- package/src/base/validators/chartParamsValidator.ts +4 -4
- package/src/defaults.ts +54 -10
- package/src/grid/contextObserverCallback.ts +31 -9
- package/src/grid/dataFormatterValidator.ts +42 -23
- package/src/multiGrid/contextObserverCallback.ts +38 -7
- package/src/multiValue/computedDataFn.ts +4 -1
- package/src/multiValue/contextObserverCallback.ts +159 -43
- package/src/multiValue/dataFormatterValidator.ts +85 -5
- package/src/multiValue/dataValidator.ts +9 -6
- package/src/relationship/computedDataFn.ts +37 -22
- package/src/relationship/dataFormatterValidator.ts +10 -6
- package/src/relationship/dataValidator.ts +10 -6
- package/src/series/contextObserverCallback.ts +18 -11
- package/src/tree/dataValidator.ts +1 -1
- package/src/utils/gridObservables.ts +32 -10
- package/src/utils/index.ts +3 -3
- package/src/utils/multiGridObservables.ts +34 -25
- package/src/utils/multiValueObservables.ts +479 -97
- package/src/utils/observables.ts +77 -15
- package/src/utils/orbchartsUtils.ts +9 -9
- package/src/utils/seriesObservables.ts +4 -4
- package/src/utils/validator.ts +1 -1
@@ -18,41 +18,50 @@ import type {
|
|
18
18
|
ComputedDatumTypeMap,
|
19
19
|
ComputedDataMultiValue,
|
20
20
|
ComputedDatumMultiValue,
|
21
|
+
ComputedDatumWithSumMultiValue,
|
22
|
+
ContainerSize,
|
21
23
|
DataFormatterTypeMap,
|
22
24
|
DataFormatterMultiValue,
|
23
|
-
|
24
|
-
|
25
|
-
|
25
|
+
DataFormatterXYAxis,
|
26
|
+
ComputedXYDatumMultiValue,
|
27
|
+
ComputedXYDataMultiValue,
|
26
28
|
ContainerPositionScaled,
|
27
29
|
HighlightTarget,
|
28
30
|
Layout,
|
29
31
|
TransformData } from '../../lib/core-types'
|
30
32
|
import { getMinMax, getMinMaxMultiValue } from './orbchartsUtils'
|
31
33
|
import { createValueToAxisScale, createLabelToAxisScale, createAxisToLabelIndexScale } from './d3Scale'
|
32
|
-
import {
|
34
|
+
import { calcContainerPositionScaled } from './orbchartsUtils'
|
33
35
|
|
34
|
-
export const
|
35
|
-
|
36
|
+
export const xyMinMaxObservable = ({ computedData$, xyValueIndex$ }: {
|
37
|
+
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
38
|
+
xyValueIndex$: Observable<[number, number]>
|
39
|
+
}) => {
|
40
|
+
return combineLatest({
|
41
|
+
computedData: computedData$,
|
42
|
+
xyValueIndex: xyValueIndex$,
|
43
|
+
}).pipe(
|
36
44
|
map(data => {
|
37
|
-
const flatData = data.flat()
|
38
|
-
const [minX, maxX] = getMinMax(flatData.map(d => d.value[0]))
|
39
|
-
const [minY, maxY] = getMinMax(flatData.map(d => d.value[1]))
|
45
|
+
const flatData = data.computedData.flat()
|
46
|
+
const [minX, maxX] = getMinMax(flatData.map(d => d.value[data.xyValueIndex[0]]))
|
47
|
+
const [minY, maxY] = getMinMax(flatData.map(d => d.value[data.xyValueIndex[1]]))
|
40
48
|
return { minX, maxX, minY, maxY }
|
41
49
|
})
|
42
50
|
)
|
43
51
|
}
|
44
52
|
|
45
|
-
export const
|
53
|
+
export const computedXYDataObservable = ({ computedData$, xyMinMax$, xyValueIndex$, fullDataFormatter$, layout$ }: {
|
46
54
|
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
47
|
-
|
55
|
+
xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
|
56
|
+
xyValueIndex$: Observable<[number, number]>
|
48
57
|
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
49
58
|
layout$: Observable<Layout>
|
50
|
-
}): Observable<
|
59
|
+
}): Observable<ComputedXYDataMultiValue> => {
|
51
60
|
|
52
61
|
// 未篩選範圍前的 scale
|
53
|
-
function createOriginXScale (
|
54
|
-
let maxValue =
|
55
|
-
let minValue =
|
62
|
+
function createOriginXScale (xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }, layout: Layout) {
|
63
|
+
let maxValue = xyMinMax.maxX
|
64
|
+
let minValue = xyMinMax.minX
|
56
65
|
if (minValue === maxValue && maxValue === 0) {
|
57
66
|
// 避免最大及最小值相同造成無法計算scale
|
58
67
|
maxValue = 1
|
@@ -69,9 +78,9 @@ export const multiValueComputedLayoutDataObservable = ({ computedData$, minMaxXY
|
|
69
78
|
}
|
70
79
|
|
71
80
|
// 未篩選範圍及visible前的 scale
|
72
|
-
function createOriginYScale (
|
73
|
-
let maxValue =
|
74
|
-
let minValue =
|
81
|
+
function createOriginYScale (xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }, layout: Layout) {
|
82
|
+
let maxValue = xyMinMax.maxY
|
83
|
+
let minValue = xyMinMax.minY
|
75
84
|
if (minValue === maxValue && maxValue === 0) {
|
76
85
|
// 避免最大及最小值相同造成無法計算scale
|
77
86
|
maxValue = 1
|
@@ -90,24 +99,25 @@ export const multiValueComputedLayoutDataObservable = ({ computedData$, minMaxXY
|
|
90
99
|
|
91
100
|
return combineLatest({
|
92
101
|
computedData: computedData$,
|
93
|
-
|
102
|
+
xyMinMax: xyMinMax$,
|
103
|
+
xyValueIndex: xyValueIndex$,
|
94
104
|
fullDataFormatter: fullDataFormatter$,
|
95
105
|
layout: layout$
|
96
106
|
}).pipe(
|
97
107
|
switchMap(async d => d),
|
98
108
|
map(data => {
|
99
109
|
|
100
|
-
const xScale = createOriginXScale(data.
|
101
|
-
const yScale = createOriginYScale(data.
|
110
|
+
const xScale = createOriginXScale(data.xyMinMax, data.layout)
|
111
|
+
const yScale = createOriginYScale(data.xyMinMax, data.layout)
|
102
112
|
|
103
113
|
return data.computedData
|
104
114
|
.map((categoryData, categoryIndex) => {
|
105
115
|
return categoryData.map((datum, datumIndex) => {
|
106
116
|
return {
|
107
117
|
...datum,
|
108
|
-
axisX: xScale(datum.value[0] ?? 0),
|
118
|
+
axisX: xScale(datum.value[data.xyValueIndex[0]] ?? 0),
|
109
119
|
// axisY: data.layout.height - yScale(datum.value[1] ?? 0), // y軸的繪圖座標是從上到下,所以反轉
|
110
|
-
axisY: yScale(datum.value[1] ?? 0), // y軸的繪圖座標是從上到下,所以反轉
|
120
|
+
axisY: yScale(datum.value[data.xyValueIndex[1]] ?? 0), // y軸的繪圖座標是從上到下,所以反轉
|
111
121
|
}
|
112
122
|
})
|
113
123
|
})
|
@@ -122,8 +132,8 @@ export const multiValueComputedLayoutDataObservable = ({ computedData$, minMaxXY
|
|
122
132
|
// const destroy$ = new Subject()
|
123
133
|
|
124
134
|
// function calcAxesTransform ({ xAxis, yAxis, width, height }: {
|
125
|
-
// xAxis:
|
126
|
-
// yAxis:
|
135
|
+
// xAxis: DataFormatterXYAxis,
|
136
|
+
// yAxis: DataFormatterXYAxis,
|
127
137
|
// width: number,
|
128
138
|
// height: number
|
129
139
|
// }): TransformData {
|
@@ -258,7 +268,7 @@ export const multiValueComputedLayoutDataObservable = ({ computedData$, minMaxXY
|
|
258
268
|
// })
|
259
269
|
// }
|
260
270
|
|
261
|
-
// export const
|
271
|
+
// export const highlightObservable = ({ computedData$, fullChartParams$, event$ }: {
|
262
272
|
// computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
263
273
|
// fullChartParams$: Observable<ChartParams>
|
264
274
|
// event$: Subject<any>
|
@@ -269,7 +279,7 @@ export const multiValueComputedLayoutDataObservable = ({ computedData$, minMaxXY
|
|
269
279
|
// return highlightObservable ({ datumList$, fullChartParams$, event$ })
|
270
280
|
// }
|
271
281
|
|
272
|
-
export const
|
282
|
+
export const categoryLabelsObservable = ({ computedData$, fullDataFormatter$ }: {
|
273
283
|
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
274
284
|
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
275
285
|
}) => {
|
@@ -285,7 +295,7 @@ export const multiValueCategoryLabelsObservable = ({ computedData$, fullDataForm
|
|
285
295
|
)
|
286
296
|
}
|
287
297
|
|
288
|
-
export const
|
298
|
+
export const visibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'multiValue'>> }) => {
|
289
299
|
return computedData$.pipe(
|
290
300
|
map(data => {
|
291
301
|
return data
|
@@ -299,8 +309,100 @@ export const multiValueVisibleComputedDataObservable = ({ computedData$ }: { com
|
|
299
309
|
)
|
300
310
|
}
|
301
311
|
|
302
|
-
export const
|
303
|
-
return
|
312
|
+
export const visibleComputedSumDataObservable = ({ visibleComputedData$ }: { visibleComputedData$: Observable<ComputedDataMultiValue> }) => {
|
313
|
+
return visibleComputedData$.pipe(
|
314
|
+
map(data => {
|
315
|
+
return data.map(categoryData => {
|
316
|
+
return categoryData
|
317
|
+
.map(d => {
|
318
|
+
let newDatum = d as ComputedDatumWithSumMultiValue
|
319
|
+
// 新增總計資料欄位
|
320
|
+
newDatum.sum = newDatum.value.reduce((acc, curr) => acc + curr, 0)
|
321
|
+
return newDatum
|
322
|
+
})
|
323
|
+
})
|
324
|
+
})
|
325
|
+
)
|
326
|
+
}
|
327
|
+
|
328
|
+
// Ranking資料 - 用 value[index] 排序
|
329
|
+
export const visibleComputedRankingByIndexDataObservable = ({ xyValueIndex$, isCategorySeprate$, visibleComputedData$ }: {
|
330
|
+
xyValueIndex$: Observable<[number, number]>
|
331
|
+
isCategorySeprate$: Observable<boolean>
|
332
|
+
visibleComputedData$: Observable<ComputedDatumMultiValue[][]>
|
333
|
+
}) => {
|
334
|
+
|
335
|
+
return combineLatest({
|
336
|
+
isCategorySeprate: isCategorySeprate$,
|
337
|
+
xyValueIndex: xyValueIndex$,
|
338
|
+
visibleComputedData: visibleComputedData$
|
339
|
+
}).pipe(
|
340
|
+
switchMap(async d => d),
|
341
|
+
map(data => {
|
342
|
+
const xValueIndex = data.xyValueIndex[0]
|
343
|
+
// -- category 分開 --
|
344
|
+
if (data.isCategorySeprate) {
|
345
|
+
return data.visibleComputedData
|
346
|
+
.map(categoryData => {
|
347
|
+
return categoryData
|
348
|
+
.sort((a, b) => {
|
349
|
+
const bValue = b.value[xValueIndex] ?? - Infinity // - Infinity 為最小值
|
350
|
+
const aValue = a.value[xValueIndex] ?? - Infinity
|
351
|
+
|
352
|
+
return bValue - aValue
|
353
|
+
})
|
354
|
+
})
|
355
|
+
// -- 用 value[index] 排序 --
|
356
|
+
} else {
|
357
|
+
return [
|
358
|
+
data.visibleComputedData
|
359
|
+
.flat()
|
360
|
+
.sort((a, b) => {
|
361
|
+
const bValue = b.value[xValueIndex] ?? - Infinity // - Infinity 為最小值
|
362
|
+
const aValue = a.value[xValueIndex] ?? - Infinity
|
363
|
+
|
364
|
+
return bValue - aValue
|
365
|
+
})
|
366
|
+
]
|
367
|
+
}
|
368
|
+
})
|
369
|
+
)
|
370
|
+
}
|
371
|
+
|
372
|
+
// Ranking資料 - 用所有 valueIndex 加總資料排序
|
373
|
+
export const visibleComputedRankingBySumDataObservable = ({ isCategorySeprate$, visibleComputedSumData$ }: {
|
374
|
+
isCategorySeprate$: Observable<boolean>
|
375
|
+
// visibleComputedData$: Observable<ComputedDatumMultiValue[][]>
|
376
|
+
visibleComputedSumData$: Observable<ComputedDatumWithSumMultiValue[][]>
|
377
|
+
}) => {
|
378
|
+
|
379
|
+
return combineLatest({
|
380
|
+
isCategorySeprate: isCategorySeprate$,
|
381
|
+
visibleComputedSumData: visibleComputedSumData$
|
382
|
+
}).pipe(
|
383
|
+
switchMap(async d => d),
|
384
|
+
map(data => {
|
385
|
+
// -- category 分開 --
|
386
|
+
if (data.isCategorySeprate) {
|
387
|
+
return data.visibleComputedSumData
|
388
|
+
.map(categoryData => {
|
389
|
+
return categoryData
|
390
|
+
.sort((a, b) => b.sum - a.sum)
|
391
|
+
})
|
392
|
+
// -- 用 value[index] 排序 --
|
393
|
+
} else {
|
394
|
+
return [
|
395
|
+
data.visibleComputedSumData
|
396
|
+
.flat()
|
397
|
+
.sort((a, b) => b.sum - a.sum)
|
398
|
+
]
|
399
|
+
}
|
400
|
+
})
|
401
|
+
)
|
402
|
+
}
|
403
|
+
|
404
|
+
export const visibleComputedXYDataObservable = ({ computedXYData$ }: { computedXYData$: Observable<ComputedXYDataMultiValue> }) => {
|
405
|
+
return computedXYData$.pipe(
|
304
406
|
map(data => {
|
305
407
|
return data
|
306
408
|
.map(categoryData => {
|
@@ -313,14 +415,14 @@ export const multiValueVisibleComputedLayoutDataObservable = ({ computedLayoutDa
|
|
313
415
|
)
|
314
416
|
}
|
315
417
|
|
316
|
-
// 所有container位置(對應
|
317
|
-
export const
|
418
|
+
// 所有container位置(對應category)
|
419
|
+
export const containerPositionObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
|
318
420
|
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
319
421
|
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
320
422
|
layout$: Observable<Layout>
|
321
423
|
}): Observable<ContainerPositionScaled[]> => {
|
322
424
|
|
323
|
-
const
|
425
|
+
const containerPosition$ = combineLatest({
|
324
426
|
computedData: computedData$,
|
325
427
|
fullDataFormatter: fullDataFormatter$,
|
326
428
|
layout: layout$,
|
@@ -330,7 +432,7 @@ export const multiValueContainerPositionObservable = ({ computedData$, fullDataF
|
|
330
432
|
|
331
433
|
if (data.fullDataFormatter.separateCategory) {
|
332
434
|
// -- 依slotIndexes計算 --
|
333
|
-
return
|
435
|
+
return calcContainerPositionScaled(data.layout, data.fullDataFormatter.container, data.computedData.length)
|
334
436
|
// return data.computedData.map((seriesData, seriesIndex) => {
|
335
437
|
// const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
|
336
438
|
// const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
|
@@ -345,8 +447,8 @@ export const multiValueContainerPositionObservable = ({ computedData$, fullDataF
|
|
345
447
|
// })
|
346
448
|
} else {
|
347
449
|
// -- 無拆分 --
|
348
|
-
const
|
349
|
-
return data.computedData.map((d, i) =>
|
450
|
+
const containerPositionArr = calcContainerPositionScaled(data.layout, data.fullDataFormatter.container, 1)
|
451
|
+
return data.computedData.map((d, i) => containerPositionArr[0]) // 每個series相同位置
|
350
452
|
// const columnIndex = 0
|
351
453
|
// const rowIndex = 0
|
352
454
|
// return data.computedData.map((seriesData, seriesIndex) => {
|
@@ -363,25 +465,69 @@ export const multiValueContainerPositionObservable = ({ computedData$, fullDataF
|
|
363
465
|
})
|
364
466
|
)
|
365
467
|
|
366
|
-
return
|
468
|
+
return containerPosition$
|
367
469
|
}
|
368
470
|
|
471
|
+
// export const containerSizeObservable = ({ layout$, containerPosition$ }: {
|
472
|
+
// layout$: Observable<Layout>
|
473
|
+
// containerPosition$: Observable<ContainerPositionScaled[]>
|
474
|
+
// }) => {
|
475
|
+
// const rowAmount$ = containerPosition$.pipe(
|
476
|
+
// map(containerPosition => {
|
477
|
+
// const maxRowIndex = containerPosition.reduce((acc, current) => {
|
478
|
+
// return current.rowIndex > acc ? current.rowIndex : acc
|
479
|
+
// }, 0)
|
480
|
+
// return maxRowIndex + 1
|
481
|
+
// }),
|
482
|
+
// distinctUntilChanged(),
|
483
|
+
// )
|
484
|
+
|
485
|
+
// const columnAmount$ = containerPosition$.pipe(
|
486
|
+
// map(containerPosition => {
|
487
|
+
// const maxColumnIndex = containerPosition.reduce((acc, current) => {
|
488
|
+
// return current.columnIndex > acc ? current.columnIndex : acc
|
489
|
+
// }, 0)
|
490
|
+
// return maxColumnIndex + 1
|
491
|
+
// }),
|
492
|
+
// distinctUntilChanged()
|
493
|
+
// )
|
369
494
|
|
370
|
-
|
371
|
-
|
372
|
-
|
495
|
+
// return combineLatest({
|
496
|
+
// layout: layout$,
|
497
|
+
// rowAmount: rowAmount$,
|
498
|
+
// columnAmount: columnAmount$
|
499
|
+
// }).pipe(
|
500
|
+
// switchMap(async (d) => d),
|
501
|
+
// map(data => {
|
502
|
+
// const width = (data.layout.rootWidth / data.columnAmount) - (data.layout.left + data.layout.right)
|
503
|
+
// const height = (data.layout.rootHeight / data.rowAmount) - (data.layout.top + data.layout.bottom)
|
504
|
+
// return {
|
505
|
+
// width,
|
506
|
+
// height
|
507
|
+
// }
|
508
|
+
// }),
|
509
|
+
// distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height),
|
510
|
+
// shareReplay(1)
|
511
|
+
// )
|
512
|
+
// }
|
513
|
+
|
514
|
+
export const filteredXYMinMaxDataObservable = ({ visibleComputedXYData$, xyMinMax$, xyValueIndex$, fullDataFormatter$ }: {
|
515
|
+
visibleComputedXYData$: Observable<ComputedXYDataMultiValue>
|
516
|
+
xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
|
517
|
+
xyValueIndex$: Observable<[number, number]>
|
373
518
|
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
374
519
|
}) => {
|
375
520
|
return combineLatest({
|
376
|
-
|
377
|
-
|
521
|
+
visibleComputedXYData: visibleComputedXYData$,
|
522
|
+
xyMinMax: xyMinMax$,
|
523
|
+
xyValueIndex: xyValueIndex$,
|
378
524
|
fullDataFormatter: fullDataFormatter$,
|
379
525
|
}).pipe(
|
380
526
|
map(data => {
|
381
527
|
// 所有可見資料依 dataFormatter 的 scale 設定篩選出最大小值
|
382
528
|
const { minX, maxX, minY, maxY } = (() => {
|
383
529
|
|
384
|
-
let { minX, maxX, minY, maxY } = data.
|
530
|
+
let { minX, maxX, minY, maxY } = data.xyMinMax
|
385
531
|
|
386
532
|
if (data.fullDataFormatter.xAxis.scaleDomain[0] === 'auto' && minX > 0) {
|
387
533
|
minX = 0
|
@@ -407,29 +553,31 @@ export const filteredMinMaxXYDataObservable = ({ visibleComputedLayoutData$, min
|
|
407
553
|
return { minX, maxX, minY, maxY }
|
408
554
|
})()
|
409
555
|
// console.log({ minX, maxX, minY, maxY })
|
410
|
-
let datumList:
|
411
|
-
let minXDatum:
|
412
|
-
let maxXDatum:
|
413
|
-
let minYDatum:
|
414
|
-
let maxYDatum:
|
415
|
-
// console.log('data.
|
556
|
+
let datumList: ComputedXYDatumMultiValue[] = []
|
557
|
+
let minXDatum: ComputedXYDatumMultiValue | null = null
|
558
|
+
let maxXDatum: ComputedXYDatumMultiValue | null = null
|
559
|
+
let minYDatum: ComputedXYDatumMultiValue | null = null
|
560
|
+
let maxYDatum: ComputedXYDatumMultiValue | null = null
|
561
|
+
// console.log('data.visibleComputedXYData', data.visibleComputedXYData)
|
416
562
|
// minX, maxX, minY, maxY 範圍內的最大最小值資料
|
417
563
|
// console.log({ minX, maxX, minY, maxY })
|
418
|
-
for (let categoryData of data.
|
564
|
+
for (let categoryData of data.visibleComputedXYData) {
|
419
565
|
for (let datum of categoryData) {
|
566
|
+
const xValue = datum.value[data.xyValueIndex[0]]
|
567
|
+
const yValue = datum.value[data.xyValueIndex[1]]
|
420
568
|
// 比較矩形範圍(所以 minX, maxX, minY, maxY 要同時比較)
|
421
|
-
if (
|
569
|
+
if (xValue >= minX && xValue <= maxX && yValue >= minY && yValue <= maxY) {
|
422
570
|
datumList.push(datum)
|
423
|
-
if (minXDatum == null ||
|
571
|
+
if (minXDatum == null || xValue < minXDatum.value[data.xyValueIndex[0]]) {
|
424
572
|
minXDatum = datum
|
425
573
|
}
|
426
|
-
if (maxXDatum == null ||
|
574
|
+
if (maxXDatum == null || xValue > maxXDatum.value[data.xyValueIndex[0]]) {
|
427
575
|
maxXDatum = datum
|
428
576
|
}
|
429
|
-
if (minYDatum == null ||
|
577
|
+
if (minYDatum == null || yValue < minYDatum.value[data.xyValueIndex[1]]) {
|
430
578
|
minYDatum = datum
|
431
579
|
}
|
432
|
-
if (maxYDatum == null ||
|
580
|
+
if (maxYDatum == null || yValue > maxYDatum.value[data.xyValueIndex[1]]) {
|
433
581
|
maxYDatum = datum
|
434
582
|
}
|
435
583
|
}
|
@@ -447,29 +595,123 @@ export const filteredMinMaxXYDataObservable = ({ visibleComputedLayoutData$, min
|
|
447
595
|
)
|
448
596
|
}
|
449
597
|
|
450
|
-
export const
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
598
|
+
// export const visibleComputedRankingDataObservable = ({ visibleComputedData$ }: {
|
599
|
+
// visibleComputedData$: Observable<ComputedDatumMultiValue[][]>
|
600
|
+
// }) => {
|
601
|
+
// return visibleComputedData$.pipe(
|
602
|
+
// map(visibleComputedData => visibleComputedData
|
603
|
+
// .flat()
|
604
|
+
// .map(d => {
|
605
|
+
// // 新增總計資料欄位
|
606
|
+
// ;(d as any)._sum = d.value.reduce((acc, curr) => acc + curr, 0)
|
607
|
+
// return d
|
608
|
+
// })
|
609
|
+
// .sort((a: any, b: any) => b._sum - a._sum)
|
610
|
+
// )
|
611
|
+
// )
|
612
|
+
|
613
|
+
// // const labelAmountLimit$ = combineLatest({
|
614
|
+
// // layout: layout$,
|
615
|
+
// // textSizePx: textSizePx$,
|
616
|
+
// // sortedLabels: sortedLabels$
|
617
|
+
// // }).pipe(
|
618
|
+
// // switchMap(async (d) => d),
|
619
|
+
// // map(data => {
|
620
|
+
// // const lineHeight = data.textSizePx * 2 // 2倍行高
|
621
|
+
// // const labelAmountLimit = Math.floor(data.layout.height / lineHeight)
|
622
|
+
// // return labelAmountLimit
|
623
|
+
// // }),
|
624
|
+
// // distinctUntilChanged()
|
625
|
+
// // )
|
626
|
+
|
627
|
+
// // return combineLatest({
|
628
|
+
// // sortedLabels: sortedLabels$,
|
629
|
+
// // labelAmountLimit: labelAmountLimit$
|
630
|
+
// // }).pipe(
|
631
|
+
// // map(data => {
|
632
|
+
// // return data.sortedLabels.slice(0, data.labelAmountLimit)
|
633
|
+
// // })
|
634
|
+
// // )
|
635
|
+
|
636
|
+
// }
|
637
|
+
|
638
|
+
// export const rankingAmountLimitObservable = ({ layout$, textSizePx$ }: {
|
639
|
+
// layout$: Observable<Layout>
|
640
|
+
// textSizePx$: Observable<number>
|
641
|
+
// }) => {
|
642
|
+
// return combineLatest({
|
643
|
+
// layout: layout$,
|
644
|
+
// textSizePx: textSizePx$
|
645
|
+
// }).pipe(
|
646
|
+
// switchMap(async (d) => d),
|
647
|
+
// map(data => {
|
648
|
+
// const lineHeight = data.textSizePx * 2 // 2倍行高
|
649
|
+
// const labelAmountLimit = Math.floor(data.layout.height / lineHeight)
|
650
|
+
// return labelAmountLimit
|
651
|
+
// }),
|
652
|
+
// distinctUntilChanged()
|
653
|
+
// )
|
654
|
+
// }
|
655
|
+
|
656
|
+
// export const rankingScaleObservable = ({ layout$, visibleComputedRankingData$, rankingAmountLimit$ }: {
|
657
|
+
// layout$: Observable<Layout>
|
658
|
+
// visibleComputedRankingData$: Observable<ComputedDatumMultiValue[]>
|
659
|
+
// rankingAmountLimit$: Observable<number>
|
660
|
+
// }) => {
|
661
|
+
// return combineLatest({
|
662
|
+
// layout: layout$,
|
663
|
+
// rankingAmountLimit: rankingAmountLimit$,
|
664
|
+
// visibleComputedRankingData: visibleComputedRankingData$,
|
665
|
+
// }).pipe(
|
666
|
+
// switchMap(async (d) => d),
|
667
|
+
// map(data => {
|
668
|
+
// let labelAmount = 0
|
669
|
+
// let lineHeight = 0
|
670
|
+
// let totalHeight = 0
|
671
|
+
// if (data.visibleComputedRankingData.length > data.rankingAmountLimit) {
|
672
|
+
// labelAmount = data.rankingAmountLimit
|
673
|
+
// lineHeight = data.layout.height / labelAmount
|
674
|
+
// totalHeight = lineHeight * labelAmount // 用全部的數量來算而不是要顯示的數量(要超出圖軸高度)
|
675
|
+
// } else {
|
676
|
+
// labelAmount = data.visibleComputedRankingData.length
|
677
|
+
// lineHeight = data.layout.height / labelAmount
|
678
|
+
// totalHeight = data.layout.height
|
679
|
+
// }
|
680
|
+
|
681
|
+
// return createLabelToAxisScale({
|
682
|
+
// axisLabels: data.visibleComputedRankingData.map(d => d.label),
|
683
|
+
// axisWidth: totalHeight,
|
684
|
+
// padding: 0.5
|
685
|
+
// })
|
686
|
+
// })
|
687
|
+
// )
|
688
|
+
// }
|
689
|
+
|
690
|
+
export const graphicTransformObservable = ({ xyMinMax$, xyValueIndex$, filteredXYMinMaxData$, fullDataFormatter$, layout$ }: {
|
691
|
+
xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
|
692
|
+
xyValueIndex$: Observable<[number, number]>
|
693
|
+
filteredXYMinMaxData$: Observable<{
|
694
|
+
minXDatum: ComputedXYDatumMultiValue
|
695
|
+
maxXDatum: ComputedXYDatumMultiValue
|
696
|
+
minYDatum: ComputedXYDatumMultiValue
|
697
|
+
maxYDatum: ComputedXYDatumMultiValue
|
457
698
|
}>
|
458
699
|
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
459
700
|
layout$: Observable<Layout>
|
460
701
|
}): Observable<TransformData> => {
|
461
702
|
const destroy$ = new Subject()
|
462
703
|
|
463
|
-
function calcDataAreaTransform ({
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
704
|
+
function calcDataAreaTransform ({ xyMinMax, xyValueIndex, filteredXYMinMaxData, xAxis, yAxis, width, height }: {
|
705
|
+
xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }
|
706
|
+
xyValueIndex: [number, number]
|
707
|
+
filteredXYMinMaxData: {
|
708
|
+
minXDatum: ComputedXYDatumMultiValue
|
709
|
+
maxXDatum: ComputedXYDatumMultiValue
|
710
|
+
minYDatum: ComputedXYDatumMultiValue
|
711
|
+
maxYDatum: ComputedXYDatumMultiValue
|
470
712
|
}
|
471
|
-
xAxis:
|
472
|
-
yAxis:
|
713
|
+
xAxis: DataFormatterXYAxis
|
714
|
+
yAxis: DataFormatterXYAxis
|
473
715
|
width: number
|
474
716
|
height: number
|
475
717
|
}): TransformData {
|
@@ -509,13 +751,13 @@ export const multiValueGraphicTransformObservable = ({ minMaxXY$, filteredMinMax
|
|
509
751
|
// let filteredMinY = 0
|
510
752
|
// let filteredMaxY = 0
|
511
753
|
// let [minY, maxY] = getMinMax(flatData.map(d => d.value[1]))
|
512
|
-
// console.log('
|
513
|
-
let { minX, maxX, minY, maxY } =
|
754
|
+
// console.log('filteredXYMinMaxData', filteredXYMinMaxData)
|
755
|
+
let { minX, maxX, minY, maxY } = xyMinMax
|
514
756
|
// console.log({ minX, maxX, minY, maxY })
|
515
|
-
let filteredMinX =
|
516
|
-
let filteredMaxX =
|
517
|
-
let filteredMinY =
|
518
|
-
let filteredMaxY =
|
757
|
+
let filteredMinX = filteredXYMinMaxData.minXDatum.value[xyValueIndex[0]] ?? 0
|
758
|
+
let filteredMaxX = filteredXYMinMaxData.maxXDatum.value[xyValueIndex[0]] ?? 0
|
759
|
+
let filteredMinY = filteredXYMinMaxData.minYDatum.value[xyValueIndex[1]] ?? 0
|
760
|
+
let filteredMaxY = filteredXYMinMaxData.maxYDatum.value[xyValueIndex[1]] ?? 0
|
519
761
|
|
520
762
|
// if (yAxis.scaleDomain[0] === 'auto' && filteredMinY > 0) {
|
521
763
|
// filteredMinY = 0
|
@@ -594,24 +836,26 @@ export const multiValueGraphicTransformObservable = ({ minMaxXY$, filteredMinMax
|
|
594
836
|
|
595
837
|
return new Observable(subscriber => {
|
596
838
|
combineLatest({
|
597
|
-
|
598
|
-
|
839
|
+
xyMinMax: xyMinMax$,
|
840
|
+
xyValueIndex: xyValueIndex$,
|
841
|
+
filteredXYMinMaxData: filteredXYMinMaxData$,
|
599
842
|
fullDataFormatter: fullDataFormatter$,
|
600
843
|
layout: layout$
|
601
844
|
}).pipe(
|
602
845
|
takeUntil(destroy$),
|
603
846
|
switchMap(async (d) => d),
|
604
847
|
).subscribe(data => {
|
605
|
-
if (!data.
|
606
|
-
|| data.
|
607
|
-
|| !data.
|
608
|
-
|| data.
|
848
|
+
if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
|
849
|
+
|| data.filteredXYMinMaxData.minXDatum.value[data.xyValueIndex[0]] == null || data.filteredXYMinMaxData.maxXDatum.value[data.xyValueIndex[0]] == null
|
850
|
+
|| !data.filteredXYMinMaxData.minYDatum || !data.filteredXYMinMaxData.maxYDatum
|
851
|
+
|| data.filteredXYMinMaxData.minYDatum.value[data.xyValueIndex[1]] == null || data.filteredXYMinMaxData.maxYDatum.value[data.xyValueIndex[1]] == null
|
609
852
|
) {
|
610
853
|
return
|
611
854
|
}
|
612
855
|
const dataAreaTransformData = calcDataAreaTransform({
|
613
|
-
|
614
|
-
|
856
|
+
xyMinMax: data.xyMinMax,
|
857
|
+
xyValueIndex: data.xyValueIndex,
|
858
|
+
filteredXYMinMaxData: data.filteredXYMinMaxData,
|
615
859
|
xAxis: data.fullDataFormatter.xAxis,
|
616
860
|
yAxis: data.fullDataFormatter.yAxis,
|
617
861
|
width: data.layout.width,
|
@@ -629,34 +873,172 @@ export const multiValueGraphicTransformObservable = ({ minMaxXY$, filteredMinMax
|
|
629
873
|
})
|
630
874
|
}
|
631
875
|
|
632
|
-
export const
|
633
|
-
|
876
|
+
export const graphicReverseScaleObservable = ({ containerPosition$, graphicTransform$ }: {
|
877
|
+
containerPosition$: Observable<ContainerPositionScaled[]>
|
634
878
|
// multiValueAxesTransform$: Observable<TransformData>
|
635
|
-
|
879
|
+
graphicTransform$: Observable<TransformData>
|
636
880
|
}): Observable<[number, number][]> => {
|
637
881
|
return combineLatest({
|
638
|
-
|
882
|
+
containerPosition: containerPosition$,
|
639
883
|
// multiValueAxesTransform: multiValueAxesTransform$,
|
640
|
-
|
884
|
+
graphicTransform: graphicTransform$,
|
641
885
|
}).pipe(
|
642
886
|
switchMap(async (d) => d),
|
643
887
|
map(data => {
|
644
888
|
// if (data.multiValueAxesTransform.rotate == 0 || data.multiValueAxesTransform.rotate == 180) {
|
645
|
-
return data.
|
889
|
+
return data.containerPosition.map((series, seriesIndex) => {
|
646
890
|
return [
|
647
|
-
1 / data.
|
648
|
-
1 / data.
|
891
|
+
1 / data.graphicTransform.scale[0] / data.containerPosition[seriesIndex].scale[0],
|
892
|
+
1 / data.graphicTransform.scale[1] / data.containerPosition[seriesIndex].scale[1],
|
649
893
|
]
|
650
894
|
})
|
651
895
|
// } else {
|
652
|
-
// return data.
|
896
|
+
// return data.containerPosition.map((series, seriesIndex) => {
|
653
897
|
// // 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
|
654
898
|
// return [
|
655
|
-
// 1 / data.
|
656
|
-
// 1 / data.
|
899
|
+
// 1 / data.graphicTransform.scale[0] / data.containerPosition[seriesIndex].scale[1],
|
900
|
+
// 1 / data.graphicTransform.scale[1] / data.containerPosition[seriesIndex].scale[0],
|
657
901
|
// ]
|
658
902
|
// })
|
659
903
|
// }
|
660
904
|
}),
|
661
905
|
)
|
662
|
-
}
|
906
|
+
}
|
907
|
+
|
908
|
+
// X 軸圖軸 - 用 value[index]
|
909
|
+
export const xScaleObservable = ({ visibleComputedSumData$, fullDataFormatter$, filteredXYMinMaxData$, containerSize$ }: {
|
910
|
+
visibleComputedSumData$: Observable<ComputedDatumMultiValue[][]>
|
911
|
+
fullDataFormatter$: Observable<DataFormatterMultiValue>
|
912
|
+
filteredXYMinMaxData$: Observable<{
|
913
|
+
minXDatum: ComputedXYDatumMultiValue
|
914
|
+
maxXDatum: ComputedXYDatumMultiValue
|
915
|
+
minYDatum: ComputedXYDatumMultiValue
|
916
|
+
maxYDatum: ComputedXYDatumMultiValue
|
917
|
+
}>
|
918
|
+
// layout$: Observable<Layout>
|
919
|
+
containerSize$: Observable<ContainerSize>
|
920
|
+
}) => {
|
921
|
+
return combineLatest({
|
922
|
+
visibleComputedSumData: visibleComputedSumData$,
|
923
|
+
fullDataFormatter: fullDataFormatter$,
|
924
|
+
containerSize: containerSize$,
|
925
|
+
// xyMinMax: xyMinMax$
|
926
|
+
filteredXYMinMaxData: filteredXYMinMaxData$
|
927
|
+
}).pipe(
|
928
|
+
switchMap(async (d) => d),
|
929
|
+
map(data => {
|
930
|
+
const valueIndex = data.fullDataFormatter.xAxis.valueIndex
|
931
|
+
if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
|
932
|
+
// || data.filteredXYMinMaxData.minXDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxXDatum.value[valueIndex] == null
|
933
|
+
) {
|
934
|
+
return
|
935
|
+
}
|
936
|
+
let maxValue: number | null = data.filteredXYMinMaxData.maxXDatum.value[valueIndex]
|
937
|
+
let minValue: number | null = data.filteredXYMinMaxData.minXDatum.value[valueIndex]
|
938
|
+
if (maxValue === minValue && maxValue === 0) {
|
939
|
+
// 避免最大及最小值同等於 0 造成無法計算scale
|
940
|
+
maxValue = 1
|
941
|
+
}
|
942
|
+
|
943
|
+
const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
944
|
+
maxValue,
|
945
|
+
minValue,
|
946
|
+
axisWidth: data.containerSize.width,
|
947
|
+
scaleDomain: data.fullDataFormatter.xAxis.scaleDomain,
|
948
|
+
scaleRange: data.fullDataFormatter.xAxis.scaleRange,
|
949
|
+
})
|
950
|
+
return xScale
|
951
|
+
})
|
952
|
+
)
|
953
|
+
}
|
954
|
+
|
955
|
+
// X 軸圖軸 - 用所有 valueIndex 加總資料
|
956
|
+
export const xSumScaleObservable = ({ fullDataFormatter$, filteredXYMinMaxData$, containerSize$ }: {
|
957
|
+
// valueIndex$: Observable<number>
|
958
|
+
fullDataFormatter$: Observable<DataFormatterMultiValue>
|
959
|
+
filteredXYMinMaxData$: Observable<{
|
960
|
+
minXDatum: ComputedXYDatumMultiValue
|
961
|
+
maxXDatum: ComputedXYDatumMultiValue
|
962
|
+
minYDatum: ComputedXYDatumMultiValue
|
963
|
+
maxYDatum: ComputedXYDatumMultiValue
|
964
|
+
}>
|
965
|
+
// layout$: Observable<Layout>
|
966
|
+
containerSize$: Observable<ContainerSize>
|
967
|
+
}) => {
|
968
|
+
return combineLatest({
|
969
|
+
// valueIndex: valueIndex$,
|
970
|
+
fullDataFormatter: fullDataFormatter$,
|
971
|
+
containerSize: containerSize$,
|
972
|
+
// xyMinMax: xyMinMax$
|
973
|
+
filteredXYMinMaxData: filteredXYMinMaxData$
|
974
|
+
}).pipe(
|
975
|
+
switchMap(async (d) => d),
|
976
|
+
map(data => {
|
977
|
+
const valueIndex = data.fullDataFormatter.xAxis.valueIndex
|
978
|
+
if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
|
979
|
+
// || data.filteredXYMinMaxData.minXDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxXDatum.value[valueIndex] == null
|
980
|
+
) {
|
981
|
+
return
|
982
|
+
}
|
983
|
+
let maxValue: number | null = data.filteredXYMinMaxData.maxXDatum.value[valueIndex]
|
984
|
+
let minValue: number | null = data.filteredXYMinMaxData.minXDatum.value[valueIndex]
|
985
|
+
if (maxValue === minValue && maxValue === 0) {
|
986
|
+
// 避免最大及最小值同等於 0 造成無法計算scale
|
987
|
+
maxValue = 1
|
988
|
+
}
|
989
|
+
|
990
|
+
const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
991
|
+
maxValue,
|
992
|
+
minValue,
|
993
|
+
axisWidth: data.containerSize.width,
|
994
|
+
scaleDomain: data.fullDataFormatter.xAxis.scaleDomain,
|
995
|
+
scaleRange: data.fullDataFormatter.xAxis.scaleRange,
|
996
|
+
})
|
997
|
+
return xScale
|
998
|
+
})
|
999
|
+
)
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
export const yScaleObservable = ({ fullDataFormatter$, filteredXYMinMaxData$, containerSize$ }: {
|
1003
|
+
fullDataFormatter$: Observable<DataFormatterMultiValue>
|
1004
|
+
filteredXYMinMaxData$: Observable<{
|
1005
|
+
minXDatum: ComputedXYDatumMultiValue
|
1006
|
+
maxXDatum: ComputedXYDatumMultiValue
|
1007
|
+
minYDatum: ComputedXYDatumMultiValue
|
1008
|
+
maxYDatum: ComputedXYDatumMultiValue
|
1009
|
+
}>
|
1010
|
+
containerSize$: Observable<ContainerSize>
|
1011
|
+
}) => {
|
1012
|
+
return combineLatest({
|
1013
|
+
fullDataFormatter: fullDataFormatter$,
|
1014
|
+
containerSize: containerSize$,
|
1015
|
+
// xyMinMax: observer.xyMinMax$
|
1016
|
+
filteredXYMinMaxData: filteredXYMinMaxData$
|
1017
|
+
}).pipe(
|
1018
|
+
switchMap(async (d) => d),
|
1019
|
+
map(data => {
|
1020
|
+
const valueIndex = data.fullDataFormatter.yAxis.valueIndex
|
1021
|
+
if (!data.filteredXYMinMaxData.minYDatum || !data.filteredXYMinMaxData.maxYDatum
|
1022
|
+
|| data.filteredXYMinMaxData.minYDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxYDatum.value[valueIndex] == null
|
1023
|
+
) {
|
1024
|
+
return
|
1025
|
+
}
|
1026
|
+
let maxValue = data.filteredXYMinMaxData.maxYDatum.value[valueIndex]
|
1027
|
+
let minValue = data.filteredXYMinMaxData.minYDatum.value[valueIndex]
|
1028
|
+
if (maxValue === minValue && maxValue === 0) {
|
1029
|
+
// 避免最大及最小值同等於 0 造成無法計算scale
|
1030
|
+
maxValue = 1
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
const yScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
1034
|
+
maxValue,
|
1035
|
+
minValue,
|
1036
|
+
axisWidth: data.containerSize.height,
|
1037
|
+
scaleDomain: data.fullDataFormatter.yAxis.scaleDomain,
|
1038
|
+
scaleRange: data.fullDataFormatter.yAxis.scaleRange,
|
1039
|
+
reverse: true
|
1040
|
+
})
|
1041
|
+
return yScale
|
1042
|
+
})
|
1043
|
+
)
|
1044
|
+
}
|