@orbcharts/core 3.0.0-beta.3 → 3.0.0-beta.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.
@@ -1,7 +1,6 @@
1
1
  import type { DataMultiValueDatum, ComputedDataFn, ComputedDatumMultiValue } from '../../lib/core-types'
2
- import { formatValueToLabel, createDefaultDatumId } from '../utils/orbchartsUtils'
3
- import { createAxisLinearScale, createAxisPointScale } from '../utils/d3Utils'
4
- import { getMinAndMaxValue } from '../utils/orbchartsUtils'
2
+ import { createDefaultCategoryLabel, createDefaultDatumId, seriesColorPredicate } from '../utils/orbchartsUtils'
3
+ import { isPlainObject } from '../utils'
5
4
 
6
5
  export const computedDataFn: ComputedDataFn<'multiValue'> = (context) => {
7
6
  const { data, dataFormatter, chartParams } = context
@@ -9,163 +8,98 @@ export const computedDataFn: ComputedDataFn<'multiValue'> = (context) => {
9
8
  return []
10
9
  }
11
10
 
12
- // @Q@ 假資料待改寫
13
- const layout = {
14
- width: 1000,
15
- height: 1000
16
- }
11
+ const defaultCategoryLabel = createDefaultCategoryLabel()
17
12
 
18
13
  let computedDataMultiValue: ComputedDatumMultiValue[][] = []
19
14
 
20
15
  try {
21
- const dataMultiValue: DataMultiValueDatum[][] = data.map((d, i) => {
22
- return d.map((_d, _i) => {
23
- const datum: DataMultiValueDatum = typeof _d === 'number'
24
- ? {
25
- id: '',
26
- label: '',
27
- description: '',
28
- // tooltipContent: '',
29
- data: {},
30
- categoryLabel: '',
31
- value: _d
32
- }
33
- : {
34
- id: _d.id ?? '',
35
- label: _d.label ?? '',
36
- description: _d.description ?? '',
37
- // tooltipContent: _d.tooltipContent ?? '',
38
- data: _d.data ?? {},
39
- categoryLabel: _d.categoryLabel ??'',
40
- value: _d.value
41
- }
42
-
43
- return datum
44
- })
45
- })
46
-
47
- // x軸資料最小及最大值(第二維陣列中的第1筆為x軸資料)
48
- const [xMinValue, xMaxValue] = getMinAndMaxValue(dataMultiValue.map(d => d[0]))
49
- // y軸資料最小及最大值(第二維陣列中的第2筆為y軸資料)
50
- const [yMinValue, yMaxValue] = getMinAndMaxValue(dataMultiValue.map(d => d[1]))
51
-
52
- // const axisWidth = layout.width - dataFormatter.padding.left - dataFormatter.padding.right
53
- // const axisHeight = layout.height - dataFormatter.padding.top - dataFormatter.padding.bottom
54
- // const axisWidth = layout.width
55
- // const axisHeight = layout.height
56
- const xAxisWidth = (dataFormatter.xAxis.position === 'top' || dataFormatter.xAxis.position === 'bottom')
57
- ? layout.width
58
- : layout.height
59
- const yAxisWidth = (dataFormatter.yAxis.position === 'left' || dataFormatter.yAxis.position === 'right')
60
- ? layout.height
61
- : layout.width
62
-
63
- const xScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
64
- maxValue: xMaxValue,
65
- minValue: xMinValue,
66
- axisWidth: xAxisWidth,
67
- // scaleDomain: dataFormatter.xAxis.scaleDomain,
68
- // scaleRange: dataFormatter.xAxis.scaleRange
69
- scaleDomain: [xMinValue, xMaxValue],
70
- scaleRange: [0, 1]
71
- })
72
- const yScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
73
- maxValue: yMaxValue,
74
- minValue: yMinValue,
75
- axisWidth: yAxisWidth,
76
- // scaleDomain: dataFormatter.yAxis.scaleDomain,
77
- // scaleRange: dataFormatter.yAxis.scaleRange
78
- scaleDomain: [yMinValue, yMaxValue],
79
- scaleRange: [0, 1]
80
- })
81
-
82
- const _xScaleDoamin: [number, number] = [
83
- // dataFormatter.xAxis.scaleDomain[0] === 'auto' ? xMinValue : dataFormatter.xAxis.scaleDomain[0],
84
- (() => {
85
- if (dataFormatter.xAxis.scaleDomain[0] === 'auto') {
86
- return xMinValue < 0 ? xMinValue : 0
87
- } else if (dataFormatter.xAxis.scaleDomain[0] === 'min') {
88
- return xMinValue
89
- } else {
90
- return dataFormatter.xAxis.scaleDomain[0]
16
+ const dataMultiValue: DataMultiValueDatum[] = data.map((d, i) => {
17
+ if (Array.isArray(d)) {
18
+ return {
19
+ id: '',
20
+ label: '',
21
+ description: '',
22
+ // tooltipContent: '',
23
+ data: {},
24
+ categoryLabel: defaultCategoryLabel,
25
+ value: d
91
26
  }
92
- })(),
93
- // dataFormatter.xAxis.scaleDomain[1] === 'auto' ? xMaxValue : dataFormatter.xAxis.scaleDomain[1]
94
- (() => {
95
- if (dataFormatter.xAxis.scaleDomain[1] === 'auto') {
96
- return xMaxValue >= 0 ? xMaxValue : 0
97
- } else if (dataFormatter.xAxis.scaleDomain[1] === 'max') {
98
- return xMaxValue
99
- } else {
100
- return dataFormatter.xAxis.scaleDomain[1]
27
+ } else if (isPlainObject(d)) {
28
+ return {
29
+ id: d.id ?? '',
30
+ label: d.label ?? '',
31
+ description: d.description ?? '',
32
+ // tooltipContent: _d.tooltipContent ?? '',
33
+ data: d.data ?? {},
34
+ categoryLabel: d.categoryLabel ?? defaultCategoryLabel,
35
+ value: d.value
101
36
  }
102
- })()
103
- ]
104
- const _yScaleDoamin: [number, number] = [
105
- // dataFormatter.yAxis.scaleDomain[0] === 'auto' ? yMinValue : dataFormatter.yAxis.scaleDomain[0],
106
- (() => {
107
- if (dataFormatter.yAxis.scaleDomain[0] === 'auto') {
108
- return xMinValue < 0 ? xMinValue : 0
109
- } else if (dataFormatter.yAxis.scaleDomain[0] === 'min') {
110
- return xMinValue
111
- } else {
112
- return dataFormatter.yAxis.scaleDomain[0]
37
+ } else {
38
+ return {
39
+ id: '',
40
+ label: '',
41
+ description: '',
42
+ // tooltipContent: '',
43
+ data: {},
44
+ categoryLabel: defaultCategoryLabel,
45
+ value: []
113
46
  }
114
- })(),
115
- // dataFormatter.yAxis.scaleDomain[1] === 'auto' ? yMaxValue : dataFormatter.yAxis.scaleDomain[1]
116
- (() => {
117
- if (dataFormatter.yAxis.scaleDomain[1] === 'auto') {
118
- return xMaxValue >= 0 ? xMaxValue : 0
119
- } else if (dataFormatter.yAxis.scaleDomain[1] === 'max') {
120
- return xMaxValue
121
- } else {
122
- return dataFormatter.yAxis.scaleDomain[1]
123
- }
124
- })()
125
- ]
47
+ }
48
+ })
49
+
50
+ const categoryLabels = (() => {
51
+ // 先使用 dataFormatter.categoryLabels
52
+ const CategoryLabelsSet = new Set(dataFormatter.categoryLabels)
53
+ // 再加入 datum 中的 categoryLabel
54
+ for (let datum of dataMultiValue) {
55
+ const categoryLabel = datum.categoryLabel ?? defaultCategoryLabel
56
+ CategoryLabelsSet.add(categoryLabel) // 不重覆
57
+ }
58
+ return Array.from(CategoryLabelsSet)
59
+ })()
126
60
 
127
- // // 篩選顯示狀態
128
- // const visibleFilter = (datum: DataMultiValueDatum, rowIndex: number, columnIndex: number, context: DataFormatterContext<"multiValue">) => {
129
- // // 如果不在scale的範圍內則為false,不再做visibleFilter的判斷
130
- // if (columnIndex === 0 && datum.value != null && ((datum.value as number) < _xScaleDoamin[0] || datum.value > _xScaleDoamin[1])) {
131
- // return false
132
- // }
133
- // if (columnIndex === 1 && datum.value != null && (datum.value < _yScaleDoamin[0] || datum.value > _yScaleDoamin[1])) {
134
- // return false
135
- // }
136
-
137
- // return dataFormatter.visibleFilter(datum, rowIndex, columnIndex, context)
138
- // }
61
+ // <categoryLabel, categoryIndex>
62
+ const CategoryIndexMap = new Map<string, number>(
63
+ categoryLabels.map((label, index) => [label, index])
64
+ )
65
+
139
66
 
140
67
  let index = 0
141
68
 
142
- computedDataMultiValue = dataMultiValue.map((d, i) => {
143
- return d.map((_d, _i) => {
144
- const currentIndex = index
145
- index++
146
-
147
- const defaultId = createDefaultDatumId(dataFormatter.type, i, _i)
148
-
149
- const computedDatum: ComputedDatumMultiValue = {
150
- id: _d.id ? _d.id : defaultId,
151
- index: currentIndex,
152
- label: _d.label ? _d.label : defaultId,
153
- description: _d.description ?? '',
154
- // tooltipContent: _d.tooltipContent ? _d.tooltipContent : dataFormatter.tooltipContentFormat(_d, i, _i, context),
155
- data: _d.data,
156
- value: _d.value,
157
- categoryIndex: 0, // @Q@ 未完成
158
- categoryLabel: '', // @Q@ 未完成
159
- // valueLabel: formatValueToLabel(_d.value, dataFormatter.multiValue[_i].valueFormat),
160
- axis: _i == 0 ? xScale(_d.value) : yScale(_d.value),
161
- visible: true, // 先給預設值
162
- color: '' // @Q@ 未完成
163
- }
69
+ dataMultiValue.forEach((d, i) => {
70
+ const currentIndex = index
71
+ index++
72
+
73
+ const defaultId = createDefaultDatumId(dataFormatter.type, i)
74
+
75
+ const categoryIndex = CategoryIndexMap.get(d.categoryLabel) ?? 0
76
+
77
+ const color = seriesColorPredicate(categoryIndex, chartParams)
78
+
79
+ const computedDatum: ComputedDatumMultiValue = {
80
+ id: d.id ? d.id : defaultId,
81
+ index: currentIndex,
82
+ label: d.label ? d.label : defaultId,
83
+ description: d.description ?? '',
84
+ // tooltipContent: _d.tooltipContent ? _d.tooltipContent : dataFormatter.tooltipContentFormat(_d, i, _i, context),
85
+ data: d.data,
86
+ datumIndex: i,
87
+ value: d.value,
88
+ categoryIndex,
89
+ categoryLabel: d.categoryLabel,
90
+ // valueLabel: formatValueToLabel(_d.value, dataFormatter.multiValue[_i].valueFormat),
91
+ // axis: _i == 0 ? xScale(_d.value) : yScale(_d.value),
92
+ visible: true, // 先給預設值
93
+ color
94
+ }
164
95
 
165
- computedDatum.visible = dataFormatter.visibleFilter(computedDatum, context)
96
+ computedDatum.visible = dataFormatter.visibleFilter(computedDatum, context)
166
97
 
167
- return computedDatum
168
- })
98
+ // 依 categoryIndex 分組
99
+ if (!computedDataMultiValue[categoryIndex]) {
100
+ computedDataMultiValue[categoryIndex] = []
101
+ }
102
+ computedDataMultiValue[categoryIndex].push(computedDatum)
169
103
  })
170
104
  } catch (e) {
171
105
  // console.error(e)
@@ -1,12 +1,160 @@
1
- import type { ContextObserverCallback } from '../../lib/core-types'
1
+ import { map, shareReplay, distinctUntilChanged } from 'rxjs'
2
+ import type { ContextObserverCallback, ContextObserverTypeMap } from '../../lib/core-types'
3
+ import {
4
+ highlightObservable,
5
+ categoryDataMapObservable,
6
+ textSizePxObservable
7
+ } from '../utils/observables'
8
+ import {
9
+ multiValueComputedLayoutDataObservable,
10
+ // multiValueAxesTransformObservable,
11
+ // multiValueAxesReverseTransformObservable,
12
+ multiValueGraphicTransformObservable,
13
+ multiValueGraphicReverseScaleObservable,
14
+ multiValueCategoryLabelsObservable,
15
+ multiValueVisibleComputedDataObservable,
16
+ multiValueVisibleComputedLayoutDataObservable,
17
+ multiValueContainerPositionObservable,
18
+ minMaxXYObservable,
19
+ filteredMinMaxXYDataObservable
20
+ } from '../utils/multiValueObservables'
2
21
 
3
22
  export const contextObserverCallback: ContextObserverCallback<'multiValue'> = ({ subject, observer }) => {
4
23
 
5
- return {
24
+ const textSizePx$ = textSizePxObservable(observer.fullChartParams$).pipe(
25
+ shareReplay(1)
26
+ )
27
+
28
+ const isCategorySeprate$ = observer.fullDataFormatter$.pipe(
29
+ map(d => d.separateCategory),
30
+ distinctUntilChanged(),
31
+ shareReplay(1)
32
+ )
33
+
34
+ const multiValueContainerPosition$ = multiValueContainerPositionObservable({
35
+ computedData$: observer.computedData$,
36
+ fullDataFormatter$: observer.fullDataFormatter$,
37
+ layout$: observer.layout$,
38
+ })
39
+
40
+ // const multiValueAxesSize$ = multiValueAxesSizeObservable({
41
+ // fullDataFormatter$: observer.fullDataFormatter$,
42
+ // layout$: observer.layout$
43
+ // }).pipe(
44
+ // shareReplay(1)
45
+ // )
46
+
47
+ const datumList$ = observer.computedData$.pipe(
48
+ map(d => d.flat().flat())
49
+ ).pipe(
50
+ shareReplay(1)
51
+ )
52
+
53
+ const multiValueHighlight$ = highlightObservable({
54
+ datumList$,
55
+ fullChartParams$: observer.fullChartParams$,
56
+ event$: subject.event$
57
+ }).pipe(
58
+ shareReplay(1)
59
+ )
60
+
61
+ const categoryLabels$ = multiValueCategoryLabelsObservable({
62
+ computedData$: observer.computedData$,
63
+ fullDataFormatter$: observer.fullDataFormatter$,
64
+ })
65
+
66
+ const CategoryDataMap$ = categoryDataMapObservable({
67
+ datumList$: datumList$
68
+ }).pipe(
69
+ shareReplay(1)
70
+ )
71
+
72
+ const minMaxXY$ = minMaxXYObservable({
73
+ computedData$: observer.computedData$
74
+ }).pipe(
75
+ shareReplay(1)
76
+ )
77
+
78
+
79
+ const computedLayoutData$ = multiValueComputedLayoutDataObservable({
80
+ computedData$: observer.computedData$,
81
+ minMaxXY$,
82
+ fullDataFormatter$: observer.fullDataFormatter$,
83
+ layout$: observer.layout$,
84
+ }).pipe(
85
+ shareReplay(1)
86
+ )
87
+
88
+ const visibleComputedData$ = multiValueVisibleComputedDataObservable({
89
+ computedData$: observer.computedData$,
90
+ }).pipe(
91
+ shareReplay(1)
92
+ )
93
+
94
+ const visibleComputedLayoutData$ = multiValueVisibleComputedLayoutDataObservable({
95
+ computedLayoutData$: computedLayoutData$,
96
+ }).pipe(
97
+ shareReplay(1)
98
+ )
99
+
100
+ const filteredMinMaxXYData$ = filteredMinMaxXYDataObservable({
101
+ visibleComputedLayoutData$: visibleComputedLayoutData$,
102
+ minMaxXY$,
103
+ fullDataFormatter$: observer.fullDataFormatter$,
104
+ }).pipe(
105
+ shareReplay(1)
106
+ )
107
+
108
+ // const multiValueAxesTransform$ = multiValueAxesTransformObservable({
109
+ // fullDataFormatter$: observer.fullDataFormatter$,
110
+ // layout$: observer.layout$
111
+ // }).pipe(
112
+ // shareReplay(1)
113
+ // )
114
+
115
+ // const multiValueAxesReverseTransform$ = multiValueAxesReverseTransformObservable({
116
+ // multiValueAxesTransform$
117
+ // }).pipe(
118
+ // shareReplay(1)
119
+ // )
120
+
121
+ const multiValueGraphicTransform$ = multiValueGraphicTransformObservable({
122
+ minMaxXY$,
123
+ filteredMinMaxXYData$,
124
+ fullDataFormatter$: observer.fullDataFormatter$,
125
+ layout$: observer.layout$
126
+ }).pipe(
127
+ shareReplay(1)
128
+ )
129
+
130
+ const multiValueGraphicReverseScale$ = multiValueGraphicReverseScaleObservable({
131
+ multiValueContainerPosition$: multiValueContainerPosition$,
132
+ // multiValueAxesTransform$: multiValueAxesTransform$,
133
+ multiValueGraphicTransform$: multiValueGraphicTransform$,
134
+ })
135
+
136
+
137
+ return <ContextObserverTypeMap<'multiValue', any>>{
6
138
  fullParams$: observer.fullParams$,
7
139
  fullChartParams$: observer.fullChartParams$,
8
140
  fullDataFormatter$: observer.fullDataFormatter$,
9
141
  computedData$: observer.computedData$,
10
142
  layout$: observer.layout$,
143
+ textSizePx$,
144
+ isCategorySeprate$,
145
+ multiValueContainerPosition$,
146
+ // multiValueAxesSize$,
147
+ multiValueHighlight$,
148
+ categoryLabels$,
149
+ CategoryDataMap$,
150
+ minMaxXY$,
151
+ computedLayoutData$,
152
+ visibleComputedData$,
153
+ visibleComputedLayoutData$,
154
+ filteredMinMaxXYData$,
155
+ // multiValueAxesTransform$,
156
+ // multiValueAxesReverseTransform$,
157
+ multiValueGraphicTransform$,
158
+ multiValueGraphicReverseScale$,
11
159
  }
12
160
  }
@@ -66,7 +66,7 @@ export const computedDataFn: ComputedDataFn<'relationship'> = (context) => {
66
66
  description: edge.description ?? '',
67
67
  // tooltipContent: edge.tooltipContent ? edge.tooltipContent : dataFormatter.tooltipContentFormat(edge, 1, i, context), // 1代表edge
68
68
  data: edge.data ?? {},
69
- value: edge.value ?? 0,
69
+ // value: edge.value ?? 0,
70
70
  startNode: NodesMap.get(edge.start),
71
71
  startNodeId: edge.start,
72
72
  endNode: NodesMap.get(edge.end),
@@ -1,10 +1,12 @@
1
1
  import type { DataTree, DataTreeObj, DataTreeDatum, ComputedDataFn, ComputedDataTree } from '../../lib/core-types'
2
2
  import { isPlainObject } from '../utils/commonUtils'
3
- import { seriesColorPredicate } from '../utils/orbchartsUtils'
3
+ import { seriesColorPredicate, createDefaultCategoryLabel } from '../utils/orbchartsUtils'
4
4
 
5
5
  export const computedDataFn: ComputedDataFn<'tree'> = (context) => {
6
6
  const { data = [], dataFormatter, chartParams } = context
7
7
 
8
+ const defaultCategoryLabel = createDefaultCategoryLabel()
9
+
8
10
  // <categoryLabel, categoryIndex>
9
11
  const CategoryIndexMap = new Map<string, number>(
10
12
  dataFormatter.categoryLabels.map((label, index) => [label, index])
@@ -15,7 +17,7 @@ export const computedDataFn: ComputedDataFn<'tree'> = (context) => {
15
17
  index: 0,
16
18
  label: '',
17
19
  description: '',
18
- categoryIndex: 0,
20
+ categoryIndex: -1,
19
21
  categoryLabel: '',
20
22
  color: '',
21
23
  visible: true,
@@ -64,7 +66,7 @@ export const computedDataFn: ComputedDataFn<'tree'> = (context) => {
64
66
  data: root.data,
65
67
  // tooltipContent: root.tooltipContent,
66
68
  value: root.value,
67
- categoryLabel: root.categoryLabel,
69
+ categoryLabel: root.categoryLabel ?? defaultCategoryLabel,
68
70
  children: (ChildrenMap.get(root.id) ?? []).map(d => {
69
71
  // 遞迴
70
72
  return createBranchData(d)
@@ -84,14 +86,11 @@ export const computedDataFn: ComputedDataFn<'tree'> = (context) => {
84
86
 
85
87
  const formatBranchData = (branch: DataTreeObj, level: number, seq: number): ComputedDataTree => {
86
88
  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
89
+ const categoryLabel: string = branch.categoryLabel ?? defaultCategoryLabel
90
+ if (!CategoryIndexMap.has(categoryLabel)) {
91
+ CategoryIndexMap.set(categoryLabel, CategoryIndexMap.size)
94
92
  }
93
+ const categoryIndex = CategoryIndexMap.get(categoryLabel) ?? 0
95
94
 
96
95
  const currentIndex = index
97
96
  index++
@@ -3,7 +3,7 @@ import type { ContextObserverCallback } from '../../lib/core-types'
3
3
  import { highlightObservable, categoryDataMapObservable, textSizePxObservable } from '../utils/observables'
4
4
  import {
5
5
  nodeListObservable,
6
- existCategoryLabelsObservable,
6
+ categoryLabelsObservable,
7
7
  treeVisibleComputedDataObservable
8
8
  } from '../utils/treeObservables'
9
9
 
@@ -27,18 +27,15 @@ export const contextObserverCallback: ContextObserverCallback<'tree'> = ({ subje
27
27
  shareReplay(1)
28
28
  )
29
29
 
30
- const existCategoryLabels$ = existCategoryLabelsObservable({
31
- nodeList$,
32
- fullDataFormatter$: observer.fullDataFormatter$
33
- }).pipe(
34
- shareReplay(1)
35
- )
36
-
37
30
  const CategoryDataMap$ = categoryDataMapObservable({
38
31
  datumList$: nodeList$
39
32
  }).pipe(
40
33
  shareReplay(1)
41
34
  )
35
+
36
+ const categoryLabels$ = categoryLabelsObservable(CategoryDataMap$).pipe(
37
+ shareReplay(1)
38
+ )
42
39
 
43
40
  const visibleComputedData$ = treeVisibleComputedDataObservable({
44
41
  computedData$: observer.computedData$
@@ -54,7 +51,7 @@ export const contextObserverCallback: ContextObserverCallback<'tree'> = ({ subje
54
51
  layout$: observer.layout$,
55
52
  textSizePx$,
56
53
  treeHighlight$,
57
- existCategoryLabels$,
54
+ categoryLabels$,
58
55
  CategoryDataMap$,
59
56
  visibleComputedData$
60
57
  }