@orbcharts/core 3.0.7 → 4.0.0-alpha.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 (196) hide show
  1. package/dist/orbcharts-core.es.js +2826 -6582
  2. package/dist/orbcharts-core.umd.js +6 -6
  3. package/dist/src/OrbCharts.d.ts +18 -0
  4. package/dist/src/chart/createChart.d.ts +3 -0
  5. package/dist/src/chart/createGraphData.d.ts +3 -0
  6. package/dist/src/chart/createGridData.d.ts +3 -0
  7. package/dist/src/chart/createMultivariateData.d.ts +3 -0
  8. package/dist/src/chart/createSeriesData.d.ts +3 -0
  9. package/dist/src/chart/createTreeData.d.ts +3 -0
  10. package/dist/src/chart/defaults.d.ts +5 -0
  11. package/dist/src/defineCanvasLayer.d.ts +16 -0
  12. package/dist/src/defineCanvasPlugin.d.ts +22 -0
  13. package/dist/src/defineSVGLayer.d.ts +16 -0
  14. package/dist/src/defineSVGPlugin.d.ts +22 -0
  15. package/dist/src/index.d.ts +6 -14
  16. package/dist/src/layer/createLayer.d.ts +3 -0
  17. package/dist/src/plugin/createPlugin.d.ts +3 -0
  18. package/dist/src/test/createGraphData.test.d.ts +1 -0
  19. package/dist/src/test/createTreeData.test.d.ts +1 -0
  20. package/dist/src/test/simple-graph-test.d.ts +74 -0
  21. package/dist/src/test/simple-tree-test.d.ts +13 -0
  22. package/dist/src/types/Chart.d.ts +39 -0
  23. package/dist/src/types/ChartContext.d.ts +27 -0
  24. package/dist/src/types/Common.d.ts +3 -0
  25. package/dist/src/types/Encoding.d.ts +33 -0
  26. package/dist/src/types/Event.d.ts +12 -0
  27. package/dist/src/types/Layers.d.ts +55 -0
  28. package/dist/src/types/ModelData.d.ts +70 -0
  29. package/dist/src/types/Plugin.d.ts +39 -0
  30. package/dist/src/types/RawData.d.ts +18 -0
  31. package/dist/src/types/RenderData.d.ts +4 -0
  32. package/dist/src/types/Theme.d.ts +17 -0
  33. package/dist/src/types/Validator.d.ts +20 -0
  34. package/dist/src/types/index.d.ts +12 -0
  35. package/dist/src/utils/aggregateUtils.d.ts +37 -0
  36. package/dist/src/utils/colorUtils.d.ts +22 -0
  37. package/dist/src/utils/commonUtils.d.ts +3 -5
  38. package/dist/src/utils/dom-lifecycle.d.ts +37 -0
  39. package/dist/src/utils/dom.d.ts +6 -0
  40. package/dist/src/utils/index.d.ts +5 -1
  41. package/dist/src/utils/observables.d.ts +1 -25
  42. package/dist/src/utils/orbchartsUtils.d.ts +2 -53
  43. package/dist/src/utils/validator.d.ts +2 -2
  44. package/dist/test/aggregateTest.d.ts +1 -0
  45. package/package.json +24 -13
  46. package/src/OrbCharts.ts +35 -0
  47. package/src/chart/createChart.ts +997 -0
  48. package/src/chart/createGraphData.ts +391 -0
  49. package/src/chart/createGridData.ts +247 -0
  50. package/src/chart/createMultivariateData.ts +181 -0
  51. package/src/chart/createSeriesData.ts +297 -0
  52. package/src/chart/createTreeData.ts +344 -0
  53. package/src/chart/defaults.ts +120 -0
  54. package/src/defineCanvasLayer.ts +24 -0
  55. package/src/defineCanvasPlugin.ts +39 -0
  56. package/src/defineSVGLayer.ts +24 -0
  57. package/src/defineSVGPlugin.ts +39 -0
  58. package/src/index.ts +6 -18
  59. package/src/layer/createLayer.ts +138 -0
  60. package/src/plugin/createPlugin.ts +470 -0
  61. package/src/test/createGraphData.test.ts +103 -0
  62. package/src/test/createTreeData.test.ts +97 -0
  63. package/src/test/simple-graph-test.js +51 -0
  64. package/src/test/simple-tree-test.js +58 -0
  65. package/src/types/Chart.ts +62 -0
  66. package/src/types/ChartContext.ts +42 -0
  67. package/src/types/Common.ts +5 -0
  68. package/src/types/Encoding.ts +43 -0
  69. package/src/types/Event.ts +26 -0
  70. package/src/types/Layers.ts +93 -0
  71. package/src/types/ModelData.ts +95 -0
  72. package/src/types/Plugin.ts +98 -0
  73. package/src/types/RawData.ts +67 -0
  74. package/src/types/RenderData.ts +16 -0
  75. package/src/types/Theme.ts +21 -0
  76. package/src/types/Validator.ts +36 -0
  77. package/src/types/index.ts +12 -0
  78. package/src/utils/aggregateUtils.ts +99 -0
  79. package/src/utils/colorUtils.ts +63 -0
  80. package/src/utils/commonUtils.ts +12 -11
  81. package/src/utils/dom-lifecycle.ts +164 -0
  82. package/src/utils/dom.ts +55 -0
  83. package/src/utils/index.ts +6 -2
  84. package/src/utils/observables.ts +1 -292
  85. package/src/utils/orbchartsUtils.ts +6 -393
  86. package/src/utils/validator.ts +15 -14
  87. package/dist/lib/core-types.d.ts +0 -1
  88. package/dist/src/AbstractChart.d.ts +0 -19
  89. package/dist/src/GridChart.d.ts +0 -6
  90. package/dist/src/MultiGridChart.d.ts +0 -6
  91. package/dist/src/MultiValueChart.d.ts +0 -6
  92. package/dist/src/RelationshipChart.d.ts +0 -6
  93. package/dist/src/SeriesChart.d.ts +0 -6
  94. package/dist/src/TreeChart.d.ts +0 -6
  95. package/dist/src/base/createBaseChart.d.ts +0 -3
  96. package/dist/src/base/createBasePlugin.d.ts +0 -3
  97. package/dist/src/base/validators/chartOptionsValidator.d.ts +0 -3
  98. package/dist/src/base/validators/chartParamsValidator.d.ts +0 -3
  99. package/dist/src/base/validators/elementValidator.d.ts +0 -3
  100. package/dist/src/base/validators/pluginsValidator.d.ts +0 -3
  101. package/dist/src/defaults.d.ts +0 -25
  102. package/dist/src/defineGridPlugin.d.ts +0 -1
  103. package/dist/src/defineMultiGridPlugin.d.ts +0 -1
  104. package/dist/src/defineMultiValuePlugin.d.ts +0 -1
  105. package/dist/src/defineNoneDataPlugin.d.ts +0 -1
  106. package/dist/src/defineRelationshipPlugin.d.ts +0 -1
  107. package/dist/src/defineSeriesPlugin.d.ts +0 -1
  108. package/dist/src/defineTreePlugin.d.ts +0 -1
  109. package/dist/src/grid/computedDataFn.d.ts +0 -4
  110. package/dist/src/grid/contextObserverCallback.d.ts +0 -3
  111. package/dist/src/grid/dataFormatterValidator.d.ts +0 -3
  112. package/dist/src/grid/dataValidator.d.ts +0 -3
  113. package/dist/src/grid/gridObservables.d.ts +0 -64
  114. package/dist/src/multiGrid/computedDataFn.d.ts +0 -3
  115. package/dist/src/multiGrid/contextObserverCallback.d.ts +0 -3
  116. package/dist/src/multiGrid/dataFormatterValidator.d.ts +0 -3
  117. package/dist/src/multiGrid/dataValidator.d.ts +0 -3
  118. package/dist/src/multiGrid/multiGridObservables.d.ts +0 -16
  119. package/dist/src/multiValue/computedDataFn.d.ts +0 -3
  120. package/dist/src/multiValue/contextObserverCallback.d.ts +0 -3
  121. package/dist/src/multiValue/dataFormatterValidator.d.ts +0 -3
  122. package/dist/src/multiValue/dataValidator.d.ts +0 -3
  123. package/dist/src/multiValue/multiValueObservables.d.ts +0 -130
  124. package/dist/src/relationship/computedDataFn.d.ts +0 -3
  125. package/dist/src/relationship/contextObserverCallback.d.ts +0 -3
  126. package/dist/src/relationship/dataFormatterValidator.d.ts +0 -3
  127. package/dist/src/relationship/dataValidator.d.ts +0 -3
  128. package/dist/src/relationship/relationshipObservables.d.ts +0 -13
  129. package/dist/src/series/computedDataFn.d.ts +0 -3
  130. package/dist/src/series/contextObserverCallback.d.ts +0 -3
  131. package/dist/src/series/dataFormatterValidator.d.ts +0 -3
  132. package/dist/src/series/dataValidator.d.ts +0 -3
  133. package/dist/src/series/seriesObservables.d.ts +0 -37
  134. package/dist/src/tree/computedDataFn.d.ts +0 -3
  135. package/dist/src/tree/contextObserverCallback.d.ts +0 -3
  136. package/dist/src/tree/dataFormatterValidator.d.ts +0 -3
  137. package/dist/src/tree/dataValidator.d.ts +0 -3
  138. package/dist/src/tree/treeObservables.d.ts +0 -10
  139. package/dist/src/utils/d3Scale.d.ts +0 -28
  140. package/lib/core-types.ts +0 -7
  141. package/src/AbstractChart.ts +0 -57
  142. package/src/GridChart.ts +0 -25
  143. package/src/MultiGridChart.ts +0 -25
  144. package/src/MultiValueChart.ts +0 -25
  145. package/src/RelationshipChart.ts +0 -25
  146. package/src/SeriesChart.ts +0 -25
  147. package/src/TreeChart.ts +0 -25
  148. package/src/base/createBaseChart.ts +0 -524
  149. package/src/base/createBasePlugin.ts +0 -154
  150. package/src/base/validators/chartOptionsValidator.ts +0 -24
  151. package/src/base/validators/chartParamsValidator.ts +0 -134
  152. package/src/base/validators/elementValidator.ts +0 -14
  153. package/src/base/validators/pluginsValidator.ts +0 -15
  154. package/src/defaults.ts +0 -284
  155. package/src/defineGridPlugin.ts +0 -3
  156. package/src/defineMultiGridPlugin.ts +0 -3
  157. package/src/defineMultiValuePlugin.ts +0 -3
  158. package/src/defineNoneDataPlugin.ts +0 -4
  159. package/src/defineRelationshipPlugin.ts +0 -3
  160. package/src/defineSeriesPlugin.ts +0 -3
  161. package/src/defineTreePlugin.ts +0 -3
  162. package/src/grid/computedDataFn.ts +0 -129
  163. package/src/grid/contextObserverCallback.ts +0 -209
  164. package/src/grid/dataFormatterValidator.ts +0 -126
  165. package/src/grid/dataValidator.ts +0 -13
  166. package/src/grid/gridObservables.ts +0 -699
  167. package/src/multiGrid/computedDataFn.ts +0 -123
  168. package/src/multiGrid/contextObserverCallback.ts +0 -109
  169. package/src/multiGrid/dataFormatterValidator.ts +0 -121
  170. package/src/multiGrid/dataValidator.ts +0 -13
  171. package/src/multiGrid/multiGridObservables.ts +0 -367
  172. package/src/multiValue/computedDataFn.ts +0 -113
  173. package/src/multiValue/contextObserverCallback.ts +0 -328
  174. package/src/multiValue/dataFormatterValidator.ts +0 -95
  175. package/src/multiValue/dataValidator.ts +0 -13
  176. package/src/multiValue/multiValueObservables.ts +0 -865
  177. package/src/relationship/computedDataFn.ts +0 -159
  178. package/src/relationship/contextObserverCallback.ts +0 -80
  179. package/src/relationship/dataFormatterValidator.ts +0 -14
  180. package/src/relationship/dataValidator.ts +0 -14
  181. package/src/relationship/relationshipObservables.ts +0 -85
  182. package/src/series/computedDataFn.ts +0 -88
  183. package/src/series/contextObserverCallback.ts +0 -132
  184. package/src/series/dataFormatterValidator.ts +0 -47
  185. package/src/series/dataValidator.ts +0 -13
  186. package/src/series/seriesObservables.ts +0 -210
  187. package/src/tree/computedDataFn.ts +0 -129
  188. package/src/tree/contextObserverCallback.ts +0 -58
  189. package/src/tree/dataFormatterValidator.ts +0 -14
  190. package/src/tree/dataValidator.ts +0 -14
  191. package/src/tree/treeObservables.ts +0 -106
  192. package/src/utils/d3Scale.ts +0 -198
  193. package/tsconfig.base.json +0 -14
  194. package/tsconfig.json +0 -3
  195. package/vite-env.d.ts +0 -7
  196. package/vite.config.js +0 -23
@@ -0,0 +1,344 @@
1
+ import type { RawData, RawDataColumn, Encoding, ModelDataTree, ModelDatumTree, Theme } from '../types'
2
+ import { aggregate } from '../utils/aggregateUtils'
3
+ import { getColorByFrom } from '../utils/colorUtils'
4
+
5
+ export const createTreeData = (rawData: RawData, encoding: Encoding, theme: Theme): ModelDataTree[] => {
6
+ // 依據 dataset 欄位將資料分組
7
+ const datasetMap = new Map<string, RawDataColumn[]>()
8
+
9
+ // 判斷是一維陣列還是二維陣列
10
+ const is2DArray = Array.isArray(rawData[0])
11
+
12
+ if (is2DArray) {
13
+ // 二維陣列:每個子陣列代表一個 dataset
14
+ (rawData as RawDataColumn[][]).forEach((datasetArray, datasetIndex) => {
15
+ datasetArray.forEach((d) => {
16
+ const datasetKey = (d as any)[encoding.dataset.from] || `dataset-${datasetIndex}`
17
+ if (!datasetMap.has(datasetKey)) {
18
+ datasetMap.set(datasetKey, [])
19
+ }
20
+ datasetMap.get(datasetKey)!.push(d)
21
+ })
22
+ })
23
+ } else {
24
+ // 一維陣列:依據 dataset 欄位分組
25
+ (rawData as RawDataColumn[]).forEach((d) => {
26
+ const datasetKey = (d as any)[encoding.dataset.from] || 'default'
27
+ if (!datasetMap.has(datasetKey)) {
28
+ datasetMap.set(datasetKey, [])
29
+ }
30
+ datasetMap.get(datasetKey)!.push(d)
31
+ })
32
+ }
33
+
34
+ // 建立排序後的 dataset 名稱陣列
35
+ let sortedDatasetNames: string[] = Array.from(datasetMap.keys())
36
+ if (Array.isArray(encoding.dataset.sort)) {
37
+ sortedDatasetNames = encoding.dataset.sort.filter(name => datasetMap.has(name))
38
+ .concat(sortedDatasetNames.filter(name => !encoding.dataset.sort.includes(name)))
39
+ } else if (encoding.dataset.sort === 'original') {
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
+ sortedDatasetNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
61
+ }
62
+
63
+ // 對每個 dataset 進行 tree 資料的處理
64
+ const result: ModelDataTree[] = []
65
+ sortedDatasetNames.forEach((datasetName, datasetIndex) => {
66
+ const data = datasetMap.get(datasetName)!
67
+
68
+ // 建立 dataset 內排序後的 series 名稱陣列(僅作為屬性與色彩來源,不做拆樹)
69
+ const seriesMap = new Map<string, RawDataColumn[]>()
70
+ data.forEach((d) => {
71
+ const seriesKey = (d as any)[encoding.series.from] || 'default'
72
+ if (!seriesMap.has(seriesKey)) {
73
+ seriesMap.set(seriesKey, [])
74
+ }
75
+ seriesMap.get(seriesKey)!.push(d)
76
+ })
77
+ let sortedSeriesNames: string[] = Array.from(seriesMap.keys())
78
+ if (Array.isArray(encoding.series.sort)) {
79
+ sortedSeriesNames = encoding.series.sort.filter(name => seriesMap.has(name))
80
+ .concat(sortedSeriesNames.filter(name => !encoding.series.sort.includes(name)))
81
+ } else if (encoding.series.sort === 'original') {
82
+ const seriesOrder: string[] = []
83
+ data.forEach((d) => {
84
+ const seriesKey = (d as any)[encoding.series.from] || 'default'
85
+ if (!seriesOrder.includes(seriesKey)) {
86
+ seriesOrder.push(seriesKey)
87
+ }
88
+ })
89
+ sortedSeriesNames = seriesOrder
90
+ } else if (encoding.series.sort === 'alphabetical') {
91
+ sortedSeriesNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
92
+ }
93
+
94
+ // 建立 dataset 內排序後的 category 名稱陣列(僅作為屬性與色彩來源,不做拆樹)
95
+ const categoryMap = new Map<string, RawDataColumn[]>()
96
+ data.forEach((d) => {
97
+ const categoryKey = (d as any)[encoding.category.from] || 'default'
98
+ if (!categoryMap.has(categoryKey)) {
99
+ categoryMap.set(categoryKey, [])
100
+ }
101
+ categoryMap.get(categoryKey)!.push(d)
102
+ })
103
+ let sortedCategoryNames: string[] = Array.from(categoryMap.keys())
104
+ if (Array.isArray(encoding.category.sort)) {
105
+ sortedCategoryNames = encoding.category.sort.filter(name => categoryMap.has(name))
106
+ .concat(sortedCategoryNames.filter(name => !encoding.category.sort.includes(name)))
107
+ } else if (encoding.category.sort === 'original') {
108
+ const categoryOrder: string[] = []
109
+ data.forEach((d) => {
110
+ const categoryKey = (d as any)[encoding.category.from] || 'default'
111
+ if (!categoryOrder.includes(categoryKey)) {
112
+ categoryOrder.push(categoryKey)
113
+ }
114
+ })
115
+ sortedCategoryNames = categoryOrder
116
+ } else if (encoding.category.sort === 'alphabetical') {
117
+ sortedCategoryNames.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
118
+ }
119
+
120
+ // 收集所有節點並依據 id 進行聚合(同一 dataset 內)
121
+ const nodeMap = new Map<string, RawDataColumn[]>()
122
+ data.forEach((d) => {
123
+ const nodeId = d.id || 'unknown'
124
+ if (!nodeMap.has(nodeId)) {
125
+ nodeMap.set(nodeId, [])
126
+ }
127
+ nodeMap.get(nodeId)!.push(d)
128
+ })
129
+
130
+ let globalNodeIndex = 0
131
+ const defaultSeriesName = sortedSeriesNames[0] || 'default'
132
+ const defaultSeriesIndex = sortedSeriesNames.indexOf(defaultSeriesName)
133
+
134
+ // 為每個 id 建立 ModelDatumTree,並進行聚合
135
+ const treeNodeMap = new Map<string, ModelDatumTree>()
136
+
137
+ Array.from(nodeMap.entries()).forEach(([nodeId, nodeItems]) => {
138
+ const firstItem = nodeItems[0]
139
+ const seriesName = (firstItem as any)[encoding.series.from] || 'default'
140
+ const seriesIndex = sortedSeriesNames.indexOf(seriesName)
141
+ const categoryName = (firstItem as any)[encoding.category.from] || 'default'
142
+ const categoryIndex = sortedCategoryNames.indexOf(categoryName)
143
+
144
+ if (encoding.value.aggregate === 'none') {
145
+ // 不聚合,使用第一筆資料
146
+ const value = (firstItem as any)[encoding.value.from]
147
+ const treeNode: ModelDatumTree = {
148
+ id: nodeId,
149
+ index: globalNodeIndex++,
150
+ modelType: 'tree',
151
+ name: firstItem.name || nodeId,
152
+ data: firstItem.data,
153
+ value: typeof value === 'number' ? value : null,
154
+ color: getColorByFrom(encoding.color.from, {
155
+ index: globalNodeIndex - 1,
156
+ seriesIndex,
157
+ categoryIndex,
158
+ datasetIndex
159
+ }, theme),
160
+ parent: firstItem.parent || null,
161
+ parentIndex: null, // 稍後設定
162
+ depth: 0, // 稍後計算
163
+ seq: 0, // 稍後計算
164
+ children: [],
165
+ series: seriesName,
166
+ seriesIndex,
167
+ category: categoryName,
168
+ categoryIndex,
169
+ }
170
+ treeNodeMap.set(nodeId, treeNode)
171
+ } else {
172
+ // 進行聚合,將相同 dataset, id 的資料合併
173
+ const values: (number | null)[] = nodeItems.map(d => {
174
+ if (encoding.value.aggregate === 'count') {
175
+ return 1 // count 聚合時每筆資料計為 1
176
+ }
177
+ const value = (d as any)[encoding.value.from]
178
+ return typeof value === 'number' ? value : null
179
+ })
180
+
181
+ const aggregatedValue = aggregate(values, encoding.value.aggregate)
182
+
183
+ const treeNode: ModelDatumTree = {
184
+ id: nodeId,
185
+ index: globalNodeIndex++,
186
+ modelType: 'tree',
187
+ name: firstItem.name || nodeId,
188
+ data: firstItem.data,
189
+ value: aggregatedValue,
190
+ color: getColorByFrom(encoding.color.from, {
191
+ index: globalNodeIndex - 1,
192
+ seriesIndex,
193
+ categoryIndex,
194
+ datasetIndex
195
+ }, theme),
196
+ parent: firstItem.parent || null,
197
+ parentIndex: null, // 稍後設定
198
+ depth: 0, // 稍後計算
199
+ seq: 0, // 稍後計算
200
+ children: [],
201
+ series: seriesName,
202
+ seriesIndex,
203
+ category: categoryName,
204
+ categoryIndex,
205
+ }
206
+ treeNodeMap.set(nodeId, treeNode)
207
+ }
208
+ })
209
+
210
+ // 建立樹狀結構
211
+ const allNodes = Array.from(treeNodeMap.values())
212
+ const nodeIndexMap = new Map<string, number>()
213
+ allNodes.forEach(node => {
214
+ nodeIndexMap.set(node.id, node.index)
215
+ })
216
+
217
+ // 設定 parentIndex
218
+ allNodes.forEach(node => {
219
+ if (node.parent && nodeIndexMap.has(node.parent)) {
220
+ node.parentIndex = nodeIndexMap.get(node.parent)!
221
+ }
222
+ })
223
+
224
+ // 建立父子關係
225
+ const rootNodes: ModelDatumTree[] = []
226
+ const childrenMap = new Map<string, ModelDatumTree[]>()
227
+
228
+ allNodes.forEach(node => {
229
+ if (node.parent === null) {
230
+ rootNodes.push(node)
231
+ } else {
232
+ if (!childrenMap.has(node.parent)) {
233
+ childrenMap.set(node.parent, [])
234
+ }
235
+ childrenMap.get(node.parent)!.push(node)
236
+ }
237
+ })
238
+
239
+ // 遞迴建立完整樹狀結構並計算 depth 和 seq
240
+ function buildTree(node: ModelDatumTree, depth: number): ModelDatumTree {
241
+ node.depth = depth
242
+ const children = childrenMap.get(node.id) || []
243
+
244
+ // 根據 value.sort 對子節點進行排序
245
+ if (encoding.value.sort === 'asc') {
246
+ children.sort((a, b) => {
247
+ if (a.value === null && b.value === null) return 0
248
+ if (a.value === null) return 1
249
+ if (b.value === null) return -1
250
+ return a.value - b.value
251
+ })
252
+ } else if (encoding.value.sort === 'desc') {
253
+ children.sort((a, b) => {
254
+ if (a.value === null && b.value === null) return 0
255
+ if (a.value === null) return 1
256
+ if (b.value === null) return -1
257
+ return b.value - a.value
258
+ })
259
+ }
260
+ // 'original' 不需要額外排序,保持原始順序
261
+
262
+ // 設定 seq
263
+ children.forEach((child, index) => {
264
+ child.seq = index
265
+ })
266
+
267
+ // 遞迴處理子節點
268
+ node.children = children.map(child => buildTree(child, depth + 1))
269
+
270
+ return node
271
+ }
272
+
273
+ // 建立完整的樹
274
+ const trees = rootNodes.map(root => buildTree(root, 0))
275
+
276
+ // 如果有多個根節點,建立一個虛擬根節點
277
+ if (trees.length === 0) {
278
+ // 沒有資料,建立空樹
279
+ result.push({
280
+ id: `empty-${datasetName}`,
281
+ index: globalNodeIndex++,
282
+ modelType: 'tree',
283
+ name: 'Empty Tree',
284
+ data: {},
285
+ value: null,
286
+ color: getColorByFrom(encoding.color.from, {
287
+ index: globalNodeIndex - 1,
288
+ seriesIndex: defaultSeriesIndex < 0 ? 0 : defaultSeriesIndex,
289
+ categoryIndex: 0,
290
+ datasetIndex
291
+ }, theme),
292
+ parent: null,
293
+ parentIndex: null,
294
+ depth: 0,
295
+ seq: 0,
296
+ children: [],
297
+ series: defaultSeriesName,
298
+ seriesIndex: defaultSeriesIndex < 0 ? 0 : defaultSeriesIndex,
299
+ category: 'default',
300
+ categoryIndex: 0,
301
+ })
302
+ } else if (trees.length === 1) {
303
+ // 單一根節點
304
+ result.push(trees[0])
305
+ } else {
306
+ const virtualRoot: ModelDatumTree = {
307
+ id: `virtual-root-${datasetName}`,
308
+ index: globalNodeIndex++,
309
+ modelType: 'tree',
310
+ name: `Virtual Root (${datasetName})`,
311
+ data: {},
312
+ value: null,
313
+ color: getColorByFrom(encoding.color.from, {
314
+ index: globalNodeIndex - 1,
315
+ seriesIndex: defaultSeriesIndex < 0 ? 0 : defaultSeriesIndex,
316
+ categoryIndex: 0,
317
+ datasetIndex
318
+ }, theme),
319
+ parent: null,
320
+ parentIndex: null,
321
+ depth: 0,
322
+ seq: 0,
323
+ children: trees.map((tree, index) => {
324
+ const updateDepth = (node: ModelDatumTree, newDepth: number): ModelDatumTree => {
325
+ node.depth = newDepth
326
+ if (newDepth === 1) {
327
+ node.seq = index
328
+ }
329
+ node.children = node.children.map(child => updateDepth(child, newDepth + 1))
330
+ return node
331
+ }
332
+ return updateDepth(tree, 1)
333
+ }),
334
+ series: defaultSeriesName,
335
+ seriesIndex: defaultSeriesIndex < 0 ? 0 : defaultSeriesIndex,
336
+ category: 'default',
337
+ categoryIndex: 0,
338
+ }
339
+ result.push(virtualRoot)
340
+ }
341
+ })
342
+
343
+ return result
344
+ }
@@ -0,0 +1,120 @@
1
+ import type { Encoding, Theme, SizeConfig } from '../types'
2
+
3
+ // export const DEFAULT_CHART_WIDTH = 800
4
+
5
+ // export const DEFAULT_CHART_HEIGHT = 500
6
+
7
+ export const DEFAULT_SIZE_CONFIG: SizeConfig = {
8
+ width: 'auto',
9
+ height: 'auto',
10
+ resizeDebounce: 50
11
+ }
12
+
13
+ export const DEFAULT_DATA_ENCODING: Encoding = {
14
+ dataset: {
15
+ from: 'dataset',
16
+ sort: 'original'
17
+ },
18
+ series: {
19
+ from: 'series',
20
+ sort: 'original'
21
+ },
22
+ category: {
23
+ from: 'category',
24
+ sort: 'original'
25
+ },
26
+ value: {
27
+ from: 'value',
28
+ sort: 'original',
29
+ aggregate: 'none'
30
+ },
31
+ multivariate: [
32
+ { from: 'x', name: 'x' },
33
+ { from: 'y', name: 'y' },
34
+ { from: 'z', name: 'z' },
35
+ ],
36
+ color: {
37
+ from: 'series',
38
+ }
39
+ }
40
+
41
+ export const DEFAULT_THEME: Theme = {
42
+ // colorScheme: 'light',
43
+ // colors: {
44
+ // light: {
45
+ // data: ['#5B8FF9', '#61DDAA', '#65789B', '#F6BD16', '#7262FD', '#78D3F8', '#9661BC', '#F6903D', '#008685', '#F08BB4'],
46
+ // primary: '#000000',
47
+ // secondary: '#595959',
48
+ // dataContrast: ['#FF4D4F', '#FAAD14', '#52C41A', '#1890FF', '#722ED1', '#EB2F96', '#13C2C2', '#FA541C', '#2F54EB', '#A0D911'],
49
+ // background: '#FFFFFF'
50
+ // },
51
+ // dark: {
52
+ // data: ['#5B8FF9', '#61DDAA', '#65789B', '#F6BD16', '#7262FD', '#78D3F8', '#9661BC', '#F6903D', '#008685', '#F08BB4'],
53
+ // primary: '#FFFFFF',
54
+ // secondary: '#BFBFBF',
55
+ // dataContrast: ['#FF4D4F', '#FAAD14', '#52C41A', '#1890FF', '#722ED1', '#EB2F96', '#13C2C2', '#FA541C', '#2F54EB', '#A0D911'],
56
+ // background: '#1F1F1F'
57
+ // }
58
+ // },
59
+ // fontSize: '12px'
60
+ colorScheme: 'light',
61
+ colors: {
62
+ light: {
63
+ data: [
64
+ // "#0088FF",
65
+ // "#FF3232",
66
+ // "#38BEA8",
67
+ // "#6F3BD5",
68
+ // "#314285",
69
+ // "#42C724",
70
+ // "#D52580",
71
+ // "#F4721B",
72
+ // "#D117EA",
73
+ // "#7E7D7D"
74
+ '#4E79A7', // blue
75
+ '#F28E2B', // orange
76
+ '#E15759', // red
77
+ '#76B7B2', // teal
78
+ '#59A14F', // green
79
+ '#EDC948', // yellow (已調過不刺眼)
80
+ '#B07AA1', // purple
81
+ '#FF9DA7', // pink
82
+ '#9C755F', // brown
83
+ '#BAB0AC', // gray
84
+ ],
85
+ primary: '#000000',
86
+ secondary: '#e0e0e0',
87
+ dataContrast: ['#ffffff', '#000000'],
88
+ background: '#FFFFFF'
89
+ },
90
+ dark: {
91
+ data: [
92
+ // "#4BABFF",
93
+ // "#FF6C6C",
94
+ // "#7DD3C4",
95
+ // "#8E6BC9",
96
+ // "#5366AC",
97
+ // "#86DC72",
98
+ // "#FF72BB",
99
+ // "#F9B052",
100
+ // "#EF76FF",
101
+ // "#C4C4C4"
102
+ '#7EA6E0', // blue (亮化)
103
+ '#FFB86B', // orange
104
+ '#FF7A7A', // red
105
+ '#6ED0CC', // teal
106
+ '#7ED97A', // green
107
+ '#FFE06E', // yellow
108
+ '#D4A5D8', // purple
109
+ '#FFB3BA', // pink
110
+ '#C89F7A', // brown
111
+ '#D3D3D3', // gray
112
+ ],
113
+ primary: '#FFFFFF',
114
+ secondary: '#e0e0e0',
115
+ dataContrast: ['#ffffff', '#000000'],
116
+ background: '#000000'
117
+ }
118
+ },
119
+ fontSize: '0.875rem'
120
+ }
@@ -0,0 +1,24 @@
1
+ import type { ChartContext, DefineLayerConfig, LayerEntity, ExtendableContext, LayerEnableProps } from "./types"
2
+ import { createLayer } from "./layer/createLayer"
3
+
4
+ export const defineCanvasLayer = <
5
+ ExtendContext extends ExtendableContext,
6
+ PluginParams extends Record<string, any>,
7
+ LayerParams extends Record<string, any>,
8
+ >(config: DefineLayerConfig<'canvas', ExtendContext, PluginParams, LayerParams>) => {
9
+ return class Layer implements LayerEntity<ExtendContext, PluginParams, LayerParams> {
10
+ _name: string
11
+ _defaultParams: LayerParams
12
+ _layerIndex: number
13
+ _initShow: boolean
14
+ _enable: (enableProps: LayerEnableProps<'canvas', ExtendContext, PluginParams, LayerParams>) => void
15
+ _disable: () => void
16
+ _updateParams: (params: Partial<LayerParams>) => void
17
+ _forceReplaceParams: (params: LayerParams) => void
18
+ _getParams: () => Readonly<LayerParams>
19
+ _destroy: () => void
20
+ constructor () {
21
+ return createLayer<ExtendContext, PluginParams, LayerParams>('canvas', config)
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,39 @@
1
+ import type { DeepPartial, DefinePluginConfig, PluginEntity, ChartContext, ExtendableContext } from './types'
2
+ import { createPlugin } from './plugin/createPlugin'
3
+
4
+ export const defineCanvasPlugin = <
5
+ ExtendContext extends ExtendableContext,
6
+ PluginParams extends Record<string, any>,
7
+ AllLayerParams extends Record<string, any>,
8
+ >(config: DefinePluginConfig<ExtendContext, PluginParams, AllLayerParams>) => {
9
+ return class Plugin implements PluginEntity<'canvas', PluginParams, AllLayerParams> {
10
+ _name: string
11
+ _elementType: 'canvas'
12
+ _getId: () => string
13
+ _setId: (id: string) => void
14
+ _injectContext: (context: ChartContext<{}>) => void
15
+ show: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
16
+ showOnly: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
17
+ showAll: () => void
18
+ hide: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
19
+ hideAll: () => void
20
+ toggle: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
21
+ // setLayers: (partial: DeepPartial<PluginParams>) => void
22
+ getShownLayerNames: () => (keyof AllLayerParams)[]
23
+ updateParams: (patch: DeepPartial<PluginParams | AllLayerParams>) => void
24
+ forceReplaceParams: (full: PluginParams | AllLayerParams) => void
25
+ getParams: () => Readonly<PluginParams | AllLayerParams>
26
+ // layer: <LayerName extends keyof PluginParams>(name: LayerName) => {
27
+ // // set: (partial: DeepPartial<PluginParams[LayerName]>) => void
28
+ // update: (patch: DeepPartial<PluginParams[LayerName]>) => void
29
+ // replace: (full: PluginParams[LayerName]) => void
30
+ // show: () => void
31
+ // hide: () => void
32
+ // toggle: () => void
33
+ // }
34
+ destroy: () => void
35
+ constructor (params?: DeepPartial<PluginParams | AllLayerParams>) {
36
+ return createPlugin('canvas', config, params)
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,24 @@
1
+ import type { ChartContext, DefineLayerConfig, LayerEntity, ExtendableContext, LayerEnableProps } from "./types"
2
+ import { createLayer } from "./layer/createLayer"
3
+
4
+ export const defineSVGLayer = <
5
+ ExtendContext extends ExtendableContext,
6
+ PluginParams extends Record<string, any>,
7
+ LayerParams extends Record<string, any>,
8
+ >(config: DefineLayerConfig<'svg', ExtendContext, PluginParams, LayerParams>) => {
9
+ return class Layer implements LayerEntity<ExtendContext, PluginParams, LayerParams> {
10
+ _name: string
11
+ _defaultParams: LayerParams
12
+ _layerIndex: number
13
+ _initShow: boolean
14
+ _enable: (enableProps: LayerEnableProps<'svg', ExtendContext, PluginParams, LayerParams>) => void
15
+ _disable: () => void
16
+ _updateParams: (params: Partial<LayerParams>) => void
17
+ _forceReplaceParams: (params: LayerParams) => void
18
+ _getParams: () => Readonly<LayerParams>
19
+ _destroy: () => void
20
+ constructor () {
21
+ return createLayer<ExtendContext, PluginParams, LayerParams>('svg', config)
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,39 @@
1
+ import type { DeepPartial, DefinePluginConfig, PluginEntity, ChartContext, ExtendableContext } from './types'
2
+ import { createPlugin } from './plugin/createPlugin'
3
+
4
+ export const defineSVGPlugin = <
5
+ ExtendContext extends ExtendableContext,
6
+ PluginParams extends Record<string, any>,
7
+ AllLayerParams extends Record<string, any>,
8
+ >(config: DefinePluginConfig<ExtendContext, PluginParams, AllLayerParams>) => {
9
+ return class Plugin implements PluginEntity<'svg', PluginParams, AllLayerParams> {
10
+ _name: string
11
+ _elementType: 'svg'
12
+ _getId: () => string
13
+ _setId: (id: string) => void
14
+ _injectContext: (context: ChartContext<{}>) => void
15
+ show: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
16
+ showOnly: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
17
+ showAll: () => void
18
+ hide: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
19
+ hideAll: () => void
20
+ toggle: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => void
21
+ // setLayers: (partial: DeepPartial<PluginParams>) => void
22
+ getShownLayerNames: () => (keyof AllLayerParams)[]
23
+ updateParams: (patch: DeepPartial<PluginParams | AllLayerParams>) => void
24
+ forceReplaceParams: (full: PluginParams | AllLayerParams) => void
25
+ getParams: () => Readonly<PluginParams | AllLayerParams>
26
+ // layer: <LayerName extends keyof PluginParams>(name: LayerName) => {
27
+ // // set: (partial: DeepPartial<PluginParams[LayerName]>) => void
28
+ // update: (patch: DeepPartial<PluginParams[LayerName]>) => void
29
+ // replace: (full: PluginParams[LayerName]) => void
30
+ // show: () => void
31
+ // hide: () => void
32
+ // toggle: () => void
33
+ // }
34
+ destroy: () => void
35
+ constructor (params?: DeepPartial<PluginParams | AllLayerParams>) {
36
+ return createPlugin('svg', config, params)
37
+ }
38
+ }
39
+ }
package/src/index.ts CHANGED
@@ -1,20 +1,8 @@
1
1
 
2
- export { SeriesChart } from './SeriesChart'
3
- export { GridChart } from './GridChart'
4
- export { MultiGridChart } from './MultiGridChart'
5
- export { MultiValueChart } from './MultiValueChart'
6
- export { RelationshipChart } from './RelationshipChart'
7
- export { TreeChart } from './TreeChart'
8
-
9
- export { defineSeriesPlugin } from './defineSeriesPlugin'
10
- export { defineGridPlugin } from './defineGridPlugin'
11
- export { defineMultiGridPlugin } from './defineMultiGridPlugin'
12
- export { defineMultiValuePlugin } from './defineMultiValuePlugin'
13
- export { defineNoneDataPlugin } from './defineNoneDataPlugin'
14
- export { defineRelationshipPlugin } from './defineRelationshipPlugin'
15
- export { defineTreePlugin } from './defineTreePlugin'
16
-
2
+ export { OrbCharts } from './OrbCharts'
3
+ export { defineSVGPlugin } from './defineSVGPlugin'
4
+ export { defineSVGLayer } from './defineSVGLayer'
5
+ export { defineCanvasPlugin } from './defineCanvasPlugin'
6
+ export { defineCanvasLayer } from './defineCanvasLayer'
7
+ export * from './types'
17
8
  export * from './utils'
18
- export * from './defaults'
19
-
20
-