@orbcharts/core 4.0.0-alpha.0 → 4.0.0-beta.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.
Files changed (47) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +876 -865
  3. package/dist/orbcharts-core.umd.js +3 -3
  4. package/dist/src/types/Plugin.d.ts +1 -1
  5. package/package.json +1 -1
  6. package/src/OrbCharts.ts +34 -34
  7. package/src/chart/createChart.ts +1013 -996
  8. package/src/chart/createGraphData.ts +391 -391
  9. package/src/chart/createGridData.ts +247 -247
  10. package/src/chart/createMultivariateData.ts +181 -181
  11. package/src/chart/createSeriesData.ts +297 -297
  12. package/src/chart/createTreeData.ts +344 -344
  13. package/src/chart/defaults.ts +119 -119
  14. package/src/defineCanvasLayer.ts +23 -23
  15. package/src/defineCanvasPlugin.ts +38 -38
  16. package/src/defineSVGLayer.ts +23 -23
  17. package/src/defineSVGPlugin.ts +38 -38
  18. package/src/index.ts +8 -8
  19. package/src/layer/createLayer.ts +137 -137
  20. package/src/plugin/createPlugin.ts +487 -469
  21. package/src/test/createGraphData.test.ts +103 -103
  22. package/src/test/createTreeData.test.ts +97 -97
  23. package/src/test/simple-graph-test.js +51 -51
  24. package/src/test/simple-tree-test.js +58 -58
  25. package/src/types/Chart.ts +62 -62
  26. package/src/types/ChartContext.ts +41 -41
  27. package/src/types/Common.ts +4 -4
  28. package/src/types/Encoding.ts +42 -42
  29. package/src/types/Event.ts +25 -25
  30. package/src/types/Layers.ts +92 -92
  31. package/src/types/ModelData.ts +94 -94
  32. package/src/types/Plugin.ts +101 -98
  33. package/src/types/RawData.ts +67 -67
  34. package/src/types/RenderData.ts +15 -15
  35. package/src/types/Theme.ts +20 -20
  36. package/src/types/Validator.ts +35 -35
  37. package/src/types/index.ts +12 -12
  38. package/src/utils/aggregateUtils.ts +99 -99
  39. package/src/utils/colorUtils.ts +63 -63
  40. package/src/utils/commonUtils.ts +56 -56
  41. package/src/utils/dom-lifecycle.ts +164 -164
  42. package/src/utils/dom.ts +54 -54
  43. package/src/utils/errorMessage.ts +40 -40
  44. package/src/utils/index.ts +7 -7
  45. package/src/utils/observables.ts +16 -16
  46. package/src/utils/orbchartsUtils.ts +8 -8
  47. package/src/utils/validator.ts +127 -127
@@ -1,181 +1,181 @@
1
- import type { RawData, RawDataColumn, Encoding, ModelDataMultivariate, ModelDatumMultivariate, Theme } from '../types'
2
- import { getColorByFrom } from '../utils/colorUtils'
3
-
4
- export const createMultivariateData = (rawData: RawData, encoding: Encoding, theme: Theme): ModelDataMultivariate[] => {
5
- // 依據 dataset 欄位將資料分組
6
- const datasetMap = new Map<string, RawDataColumn[]>()
7
-
8
- // 判斷是一維陣列還是二維陣列
9
- const is2DArray = Array.isArray(rawData[0])
10
-
11
- if (is2DArray) {
12
- // 二維陣列:每個子陣列代表一個 dataset
13
- (rawData as RawDataColumn[][]).forEach((datasetArray, datasetIndex) => {
14
- datasetArray.forEach((d) => {
15
- const datasetKey = (d as any)[encoding.dataset.from] || `dataset-${datasetIndex}`
16
- if (!datasetMap.has(datasetKey)) {
17
- datasetMap.set(datasetKey, [])
18
- }
19
- datasetMap.get(datasetKey)!.push(d)
20
- })
21
- })
22
- } else {
23
- // 一維陣列:依據 dataset 欄位分組
24
- (rawData as RawDataColumn[]).forEach((d) => {
25
- const datasetKey = (d as any)[encoding.dataset.from] || 'default'
26
- if (!datasetMap.has(datasetKey)) {
27
- datasetMap.set(datasetKey, [])
28
- }
29
- datasetMap.get(datasetKey)!.push(d)
30
- })
31
- }
32
-
33
- // 建立排序後的 dataset 名稱陣列
34
- let sortedDatasetNames: string[] = Array.from(datasetMap.keys())
35
- if (Array.isArray(encoding.dataset.sort)) {
36
- sortedDatasetNames = encoding.dataset.sort.filter(name => datasetMap.has(name))
37
- .concat(sortedDatasetNames.filter(name => !encoding.dataset.sort.includes(name)))
38
- } else if (encoding.dataset.sort === 'original') {
39
- // original 排序:依照原始資料中 dataset 名稱出現的順序
40
- const datasetOrder: string[] = []
41
- if (is2DArray) {
42
- (rawData as RawDataColumn[][]).forEach((datasetArray, datasetIndex) => {
43
- datasetArray.forEach((d) => {
44
- const datasetKey = (d as any)[encoding.dataset.from] || `dataset-${datasetIndex}`
45
- if (!datasetOrder.includes(datasetKey)) {
46
- datasetOrder.push(datasetKey)
47
- }
48
- })
49
- })
50
- } else {
51
- (rawData as RawDataColumn[]).forEach((d) => {
52
- const datasetKey = (d as any)[encoding.dataset.from] || 'default'
53
- if (!datasetOrder.includes(datasetKey)) {
54
- datasetOrder.push(datasetKey)
55
- }
56
- })
57
- }
58
- sortedDatasetNames = datasetOrder
59
- } else if (encoding.dataset.sort === 'alphabetical') {
60
- // alphabetical 排序:依照字母順序
61
- sortedDatasetNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
62
- }
63
-
64
- // 對每個 dataset 進行 multivariate 資料的處理
65
- const result: ModelDataMultivariate[] = []
66
- sortedDatasetNames.forEach((datasetName, datasetIndex) => {
67
- const data = datasetMap.get(datasetName)!
68
-
69
- // 依據 series 欄位將資料分組
70
- const seriesMap = new Map<string, RawDataColumn[]>()
71
- data.forEach((d) => {
72
- const seriesKey = (d as any)[encoding.series.from] || 'default'
73
- if (!seriesMap.has(seriesKey)) {
74
- seriesMap.set(seriesKey, [])
75
- }
76
- seriesMap.get(seriesKey)!.push(d)
77
- })
78
-
79
- // 建立排序後的系列名稱陣列
80
- let sortedSeriesNames: string[] = Array.from(seriesMap.keys())
81
- if (Array.isArray(encoding.series.sort)) {
82
- sortedSeriesNames = encoding.series.sort.filter(name => seriesMap.has(name))
83
- .concat(sortedSeriesNames.filter(name => !encoding.series.sort.includes(name)))
84
- } else if (encoding.series.sort === 'original') {
85
- // original 排序:依照原始資料中 series 名稱出現的順序
86
- const seriesOrder: string[] = []
87
- data.forEach((d) => {
88
- const seriesKey = (d as any)[encoding.series.from] || 'default'
89
- if (!seriesOrder.includes(seriesKey)) {
90
- seriesOrder.push(seriesKey)
91
- }
92
- })
93
- sortedSeriesNames = seriesOrder
94
- } else if (encoding.series.sort === 'alphabetical') {
95
- // alphabetical 排序:依照字母順序
96
- sortedSeriesNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
97
- }
98
-
99
- // 依據排序後的系列名稱來建立最終的資料結構
100
- const multivariateData: ModelDatumMultivariate[][] = []
101
- sortedSeriesNames.forEach((seriesName, seriesIndex) => {
102
- const seriesItems = seriesMap.get(seriesName)!
103
-
104
- // 依據 category 欄位將 series 內的資料分組
105
- const categoryMap = new Map<string, RawDataColumn[]>()
106
- seriesItems.forEach((d) => {
107
- const categoryKey = (d as any)[encoding.category.from] || 'default'
108
- if (!categoryMap.has(categoryKey)) {
109
- categoryMap.set(categoryKey, [])
110
- }
111
- categoryMap.get(categoryKey)!.push(d)
112
- })
113
-
114
- // 建立排序後的類別名稱陣列
115
- let sortedCategoryNames: string[] = Array.from(categoryMap.keys())
116
- if (Array.isArray(encoding.category.sort)) {
117
- sortedCategoryNames = encoding.category.sort.filter(name => categoryMap.has(name))
118
- .concat(sortedCategoryNames.filter(name => !encoding.category.sort.includes(name)))
119
- } else if (encoding.category.sort === 'original') {
120
- // original 排序:依照原始資料中 category 名稱出現的順序
121
- const categoryOrder: string[] = []
122
- seriesItems.forEach((d) => {
123
- const categoryKey = (d as any)[encoding.category.from] || 'default'
124
- if (!categoryOrder.includes(categoryKey)) {
125
- categoryOrder.push(categoryKey)
126
- }
127
- })
128
- sortedCategoryNames = categoryOrder
129
- } else if (encoding.category.sort === 'alphabetical') {
130
- // alphabetical 排序:依照字母順序
131
- sortedCategoryNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
132
- }
133
-
134
- // 處理每個 category
135
- const seriesData: ModelDatumMultivariate[] = []
136
- sortedCategoryNames.forEach((categoryName, categoryIndex) => {
137
- const categoryItems = categoryMap.get(categoryName)!
138
-
139
- // MultivariateData 不進行聚合,直接處理每筆資料
140
- categoryItems.forEach((d, index) => {
141
- // 處理 multivariate 欄位,將多個維度的值收集起來
142
- const multivariate = encoding.multivariate.map((multiVariateDef, multiVariateIndex) => ({
143
- index: multiVariateIndex,
144
- name: multiVariateDef.name,
145
- value: (() => {
146
- const rawValue = (d as any)[multiVariateDef.from]
147
- return typeof rawValue === 'number' ? rawValue : null
148
- })()
149
- }))
150
-
151
- const modelData: ModelDatumMultivariate = {
152
- id: d.id || `${datasetName}-${seriesName}-${categoryName}-${index}`,
153
- index,
154
- modelType: 'multivariate',
155
- name: d.name || '',
156
- data: d.data,
157
- value: null, // MultivariateData 的主要值在 values 陣列中,這裡設為 null
158
- color: getColorByFrom(encoding.color.from, {
159
- index,
160
- seriesIndex,
161
- categoryIndex,
162
- datasetIndex
163
- }, theme),
164
- multivariate,
165
- series: seriesName,
166
- seriesIndex: seriesIndex,
167
- category: categoryName,
168
- categoryIndex: categoryIndex
169
- }
170
- seriesData.push(modelData)
171
- })
172
- })
173
-
174
- multivariateData.push(seriesData)
175
- })
176
-
177
- result.push(multivariateData)
178
- })
179
-
180
- return result
181
- }
1
+ import type { RawData, RawDataColumn, Encoding, ModelDataMultivariate, ModelDatumMultivariate, Theme } from '../types'
2
+ import { getColorByFrom } from '../utils/colorUtils'
3
+
4
+ export const createMultivariateData = (rawData: RawData, encoding: Encoding, theme: Theme): ModelDataMultivariate[] => {
5
+ // 依據 dataset 欄位將資料分組
6
+ const datasetMap = new Map<string, RawDataColumn[]>()
7
+
8
+ // 判斷是一維陣列還是二維陣列
9
+ const is2DArray = Array.isArray(rawData[0])
10
+
11
+ if (is2DArray) {
12
+ // 二維陣列:每個子陣列代表一個 dataset
13
+ (rawData as RawDataColumn[][]).forEach((datasetArray, datasetIndex) => {
14
+ datasetArray.forEach((d) => {
15
+ const datasetKey = (d as any)[encoding.dataset.from] || `dataset-${datasetIndex}`
16
+ if (!datasetMap.has(datasetKey)) {
17
+ datasetMap.set(datasetKey, [])
18
+ }
19
+ datasetMap.get(datasetKey)!.push(d)
20
+ })
21
+ })
22
+ } else {
23
+ // 一維陣列:依據 dataset 欄位分組
24
+ (rawData as RawDataColumn[]).forEach((d) => {
25
+ const datasetKey = (d as any)[encoding.dataset.from] || 'default'
26
+ if (!datasetMap.has(datasetKey)) {
27
+ datasetMap.set(datasetKey, [])
28
+ }
29
+ datasetMap.get(datasetKey)!.push(d)
30
+ })
31
+ }
32
+
33
+ // 建立排序後的 dataset 名稱陣列
34
+ let sortedDatasetNames: string[] = Array.from(datasetMap.keys())
35
+ if (Array.isArray(encoding.dataset.sort)) {
36
+ sortedDatasetNames = encoding.dataset.sort.filter(name => datasetMap.has(name))
37
+ .concat(sortedDatasetNames.filter(name => !encoding.dataset.sort.includes(name)))
38
+ } else if (encoding.dataset.sort === 'original') {
39
+ // original 排序:依照原始資料中 dataset 名稱出現的順序
40
+ const datasetOrder: string[] = []
41
+ if (is2DArray) {
42
+ (rawData as RawDataColumn[][]).forEach((datasetArray, datasetIndex) => {
43
+ datasetArray.forEach((d) => {
44
+ const datasetKey = (d as any)[encoding.dataset.from] || `dataset-${datasetIndex}`
45
+ if (!datasetOrder.includes(datasetKey)) {
46
+ datasetOrder.push(datasetKey)
47
+ }
48
+ })
49
+ })
50
+ } else {
51
+ (rawData as RawDataColumn[]).forEach((d) => {
52
+ const datasetKey = (d as any)[encoding.dataset.from] || 'default'
53
+ if (!datasetOrder.includes(datasetKey)) {
54
+ datasetOrder.push(datasetKey)
55
+ }
56
+ })
57
+ }
58
+ sortedDatasetNames = datasetOrder
59
+ } else if (encoding.dataset.sort === 'alphabetical') {
60
+ // alphabetical 排序:依照字母順序
61
+ sortedDatasetNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
62
+ }
63
+
64
+ // 對每個 dataset 進行 multivariate 資料的處理
65
+ const result: ModelDataMultivariate[] = []
66
+ sortedDatasetNames.forEach((datasetName, datasetIndex) => {
67
+ const data = datasetMap.get(datasetName)!
68
+
69
+ // 依據 series 欄位將資料分組
70
+ const seriesMap = new Map<string, RawDataColumn[]>()
71
+ data.forEach((d) => {
72
+ const seriesKey = (d as any)[encoding.series.from] || 'default'
73
+ if (!seriesMap.has(seriesKey)) {
74
+ seriesMap.set(seriesKey, [])
75
+ }
76
+ seriesMap.get(seriesKey)!.push(d)
77
+ })
78
+
79
+ // 建立排序後的系列名稱陣列
80
+ let sortedSeriesNames: string[] = Array.from(seriesMap.keys())
81
+ if (Array.isArray(encoding.series.sort)) {
82
+ sortedSeriesNames = encoding.series.sort.filter(name => seriesMap.has(name))
83
+ .concat(sortedSeriesNames.filter(name => !encoding.series.sort.includes(name)))
84
+ } else if (encoding.series.sort === 'original') {
85
+ // original 排序:依照原始資料中 series 名稱出現的順序
86
+ const seriesOrder: string[] = []
87
+ data.forEach((d) => {
88
+ const seriesKey = (d as any)[encoding.series.from] || 'default'
89
+ if (!seriesOrder.includes(seriesKey)) {
90
+ seriesOrder.push(seriesKey)
91
+ }
92
+ })
93
+ sortedSeriesNames = seriesOrder
94
+ } else if (encoding.series.sort === 'alphabetical') {
95
+ // alphabetical 排序:依照字母順序
96
+ sortedSeriesNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
97
+ }
98
+
99
+ // 依據排序後的系列名稱來建立最終的資料結構
100
+ const multivariateData: ModelDatumMultivariate[][] = []
101
+ sortedSeriesNames.forEach((seriesName, seriesIndex) => {
102
+ const seriesItems = seriesMap.get(seriesName)!
103
+
104
+ // 依據 category 欄位將 series 內的資料分組
105
+ const categoryMap = new Map<string, RawDataColumn[]>()
106
+ seriesItems.forEach((d) => {
107
+ const categoryKey = (d as any)[encoding.category.from] || 'default'
108
+ if (!categoryMap.has(categoryKey)) {
109
+ categoryMap.set(categoryKey, [])
110
+ }
111
+ categoryMap.get(categoryKey)!.push(d)
112
+ })
113
+
114
+ // 建立排序後的類別名稱陣列
115
+ let sortedCategoryNames: string[] = Array.from(categoryMap.keys())
116
+ if (Array.isArray(encoding.category.sort)) {
117
+ sortedCategoryNames = encoding.category.sort.filter(name => categoryMap.has(name))
118
+ .concat(sortedCategoryNames.filter(name => !encoding.category.sort.includes(name)))
119
+ } else if (encoding.category.sort === 'original') {
120
+ // original 排序:依照原始資料中 category 名稱出現的順序
121
+ const categoryOrder: string[] = []
122
+ seriesItems.forEach((d) => {
123
+ const categoryKey = (d as any)[encoding.category.from] || 'default'
124
+ if (!categoryOrder.includes(categoryKey)) {
125
+ categoryOrder.push(categoryKey)
126
+ }
127
+ })
128
+ sortedCategoryNames = categoryOrder
129
+ } else if (encoding.category.sort === 'alphabetical') {
130
+ // alphabetical 排序:依照字母順序
131
+ sortedCategoryNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
132
+ }
133
+
134
+ // 處理每個 category
135
+ const seriesData: ModelDatumMultivariate[] = []
136
+ sortedCategoryNames.forEach((categoryName, categoryIndex) => {
137
+ const categoryItems = categoryMap.get(categoryName)!
138
+
139
+ // MultivariateData 不進行聚合,直接處理每筆資料
140
+ categoryItems.forEach((d, index) => {
141
+ // 處理 multivariate 欄位,將多個維度的值收集起來
142
+ const multivariate = encoding.multivariate.map((multiVariateDef, multiVariateIndex) => ({
143
+ index: multiVariateIndex,
144
+ name: multiVariateDef.name,
145
+ value: (() => {
146
+ const rawValue = (d as any)[multiVariateDef.from]
147
+ return typeof rawValue === 'number' ? rawValue : null
148
+ })()
149
+ }))
150
+
151
+ const modelData: ModelDatumMultivariate = {
152
+ id: d.id || `${datasetName}-${seriesName}-${categoryName}-${index}`,
153
+ index,
154
+ modelType: 'multivariate',
155
+ name: d.name || '',
156
+ data: d.data,
157
+ value: null, // MultivariateData 的主要值在 values 陣列中,這裡設為 null
158
+ color: getColorByFrom(encoding.color.from, {
159
+ index,
160
+ seriesIndex,
161
+ categoryIndex,
162
+ datasetIndex
163
+ }, theme),
164
+ multivariate,
165
+ series: seriesName,
166
+ seriesIndex: seriesIndex,
167
+ category: categoryName,
168
+ categoryIndex: categoryIndex
169
+ }
170
+ seriesData.push(modelData)
171
+ })
172
+ })
173
+
174
+ multivariateData.push(seriesData)
175
+ })
176
+
177
+ result.push(multivariateData)
178
+ })
179
+
180
+ return result
181
+ }