@orbcharts/core 3.0.0-beta.8 → 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.
Files changed (76) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +2734 -2353
  3. package/dist/orbcharts-core.umd.js +4 -4
  4. package/dist/src/defaults.d.ts +2 -1
  5. package/dist/src/utils/gridObservables.d.ts +8 -4
  6. package/dist/src/utils/index.d.ts +0 -3
  7. package/dist/src/utils/multiGridObservables.d.ts +3 -2
  8. package/dist/src/utils/multiValueObservables.d.ts +76 -29
  9. package/dist/src/utils/observables.d.ts +8 -1
  10. package/dist/src/utils/orbchartsUtils.d.ts +9 -9
  11. package/dist/src/utils/seriesObservables.d.ts +1 -1
  12. package/lib/core-types.ts +7 -7
  13. package/package.json +42 -42
  14. package/src/AbstractChart.ts +57 -57
  15. package/src/GridChart.ts +24 -24
  16. package/src/MultiGridChart.ts +24 -24
  17. package/src/MultiValueChart.ts +24 -24
  18. package/src/RelationshipChart.ts +24 -24
  19. package/src/SeriesChart.ts +24 -24
  20. package/src/TreeChart.ts +24 -24
  21. package/src/base/createBaseChart.ts +506 -505
  22. package/src/base/createBasePlugin.ts +154 -153
  23. package/src/base/validators/chartOptionsValidator.ts +23 -23
  24. package/src/base/validators/chartParamsValidator.ts +133 -133
  25. package/src/base/validators/elementValidator.ts +13 -13
  26. package/src/base/validators/pluginsValidator.ts +14 -14
  27. package/src/defaults.ts +282 -238
  28. package/src/defineGridPlugin.ts +3 -3
  29. package/src/defineMultiGridPlugin.ts +3 -3
  30. package/src/defineMultiValuePlugin.ts +3 -3
  31. package/src/defineNoneDataPlugin.ts +4 -4
  32. package/src/defineRelationshipPlugin.ts +3 -3
  33. package/src/defineSeriesPlugin.ts +3 -3
  34. package/src/defineTreePlugin.ts +3 -3
  35. package/src/grid/computedDataFn.ts +129 -129
  36. package/src/grid/contextObserverCallback.ts +198 -176
  37. package/src/grid/dataFormatterValidator.ts +120 -101
  38. package/src/grid/dataValidator.ts +12 -12
  39. package/src/index.ts +20 -20
  40. package/src/multiGrid/computedDataFn.ts +123 -123
  41. package/src/multiGrid/contextObserverCallback.ts +72 -41
  42. package/src/multiGrid/dataFormatterValidator.ts +115 -115
  43. package/src/multiGrid/dataValidator.ts +12 -12
  44. package/src/multiValue/computedDataFn.ts +113 -110
  45. package/src/multiValue/contextObserverCallback.ts +276 -160
  46. package/src/multiValue/dataFormatterValidator.ts +89 -9
  47. package/src/multiValue/dataValidator.ts +12 -9
  48. package/src/relationship/computedDataFn.ts +159 -144
  49. package/src/relationship/contextObserverCallback.ts +80 -80
  50. package/src/relationship/dataFormatterValidator.ts +13 -9
  51. package/src/relationship/dataValidator.ts +13 -9
  52. package/src/series/computedDataFn.ts +88 -88
  53. package/src/series/contextObserverCallback.ts +107 -100
  54. package/src/series/dataFormatterValidator.ts +41 -41
  55. package/src/series/dataValidator.ts +12 -12
  56. package/src/tree/computedDataFn.ts +129 -129
  57. package/src/tree/contextObserverCallback.ts +58 -58
  58. package/src/tree/dataFormatterValidator.ts +13 -13
  59. package/src/tree/dataValidator.ts +13 -13
  60. package/src/utils/commonUtils.ts +55 -55
  61. package/src/utils/d3Scale.ts +198 -198
  62. package/src/utils/errorMessage.ts +42 -42
  63. package/src/utils/gridObservables.ts +705 -683
  64. package/src/utils/index.ts +10 -10
  65. package/src/utils/multiGridObservables.ts +401 -392
  66. package/src/utils/multiValueObservables.ts +1044 -662
  67. package/src/utils/observables.ts +281 -219
  68. package/src/utils/orbchartsUtils.ts +377 -377
  69. package/src/utils/relationshipObservables.ts +84 -84
  70. package/src/utils/seriesObservables.ts +175 -175
  71. package/src/utils/treeObservables.ts +105 -105
  72. package/src/utils/validator.ts +126 -126
  73. package/tsconfig.base.json +13 -13
  74. package/tsconfig.json +2 -2
  75. package/vite-env.d.ts +6 -6
  76. package/vite.config.js +22 -22
@@ -1,377 +1,377 @@
1
- import * as d3 from 'd3'
2
- import type {
3
- ChartType,
4
- ChartParams,
5
- DatumValue,
6
- DataSeries,
7
- DataSeriesDatum,
8
- DataSeriesValue,
9
- DataGrid,
10
- DataGridDatum,
11
- DataGridValue,
12
- DataMultiGrid,
13
- DataMultiValue,
14
- DataMultiValueDatum,
15
- DataMultiValueValue,
16
- ComputedLayoutDatumMultiValue,
17
- DataFormatterContainer,
18
- SeriesDirection,
19
- DataFormatterGridGrid,
20
- ContainerPosition,
21
- ContainerPositionScaled,
22
- Layout
23
- } from '../../lib/core-types'
24
- import { isPlainObject } from './commonUtils'
25
-
26
- export function formatValueToLabel (value: any, valueFormatter: string | ((text: d3.NumberValue) => string)) {
27
- if (valueFormatter! instanceof Function == true) {
28
- return (valueFormatter as ((text: d3.NumberValue) => string))(value)
29
- }
30
- return d3.format(valueFormatter as string)!(value)
31
- }
32
-
33
- export function createDefaultDatumId (chartTypeOrPrefix: string, levelOneIndex: number, levelTwoIndex?: number, levelThreeIndex?: number) {
34
- let text = `${chartTypeOrPrefix}_${levelOneIndex}`
35
- if (levelTwoIndex != null) {
36
- text += `_${levelTwoIndex}`
37
- }
38
- if (levelThreeIndex != null) {
39
- text += `_${levelThreeIndex}`
40
- }
41
- return text
42
- }
43
-
44
- export function createDefaultSeriesLabel (chartTypeOrPrefix: string, seriesIndex: number) {
45
- return `${chartTypeOrPrefix}_series${seriesIndex}`
46
- }
47
-
48
- export function createDefaultGroupLabel (chartTypeOrPrefix: string, groupIndex: number) {
49
- return `${chartTypeOrPrefix}_group${groupIndex}`
50
- }
51
-
52
- export function createDefaultCategoryLabel () {
53
- // return `${chartTypeOrPrefix}_category`
54
- return '' // 空值
55
- }
56
-
57
- export function createGridSeriesLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'grid' }: {
58
- transposedDataGrid: DataGridDatum[][],
59
- dataFormatterGrid: DataFormatterGridGrid
60
- chartType?: ChartType
61
- }) {
62
- const labels = dataFormatterGrid.seriesDirection === 'row'
63
- ? dataFormatterGrid.rowLabels
64
- : dataFormatterGrid.columnLabels
65
- return transposedDataGrid.map((_, rowIndex) => {
66
- return labels[rowIndex] != null
67
- ? labels[rowIndex]
68
- : createDefaultSeriesLabel(chartType, rowIndex)
69
- })
70
- }
71
-
72
- export function createMultiGridSeriesLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'multiGrid', gridIndex = 0 }: {
73
- transposedDataGrid: DataGridDatum[][],
74
- dataFormatterGrid: DataFormatterGridGrid
75
- chartType?: ChartType
76
- gridIndex?: number
77
- }) {
78
- const labels = dataFormatterGrid.seriesDirection === 'row'
79
- ? dataFormatterGrid.rowLabels
80
- : dataFormatterGrid.columnLabels
81
- return transposedDataGrid.map((_, rowIndex) => {
82
- return labels[rowIndex] != null
83
- ? labels[rowIndex]
84
- : createDefaultSeriesLabel(`${chartType}_grid${gridIndex}`, rowIndex)
85
- })
86
- }
87
-
88
- export function createGridGroupLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'grid' }: {
89
- transposedDataGrid: DataGridDatum[][],
90
- dataFormatterGrid: DataFormatterGridGrid
91
- chartType?: ChartType
92
- }) {
93
- if (transposedDataGrid[0] == null) {
94
- return []
95
- }
96
- const labels = dataFormatterGrid.seriesDirection === 'row'
97
- ? dataFormatterGrid.columnLabels
98
- : dataFormatterGrid.rowLabels
99
- return transposedDataGrid[0].map((_, columnLabels) => {
100
- return labels[columnLabels] != null
101
- ? labels[columnLabels]
102
- : createDefaultGroupLabel(chartType, columnLabels)
103
- })
104
- }
105
-
106
- export function createMultiGridGroupLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'multiGrid', gridIndex = 0 }: {
107
- transposedDataGrid: DataGridDatum[][],
108
- dataFormatterGrid: DataFormatterGridGrid
109
- chartType?: ChartType
110
- gridIndex?: number
111
- }) {
112
- if (transposedDataGrid[0] == null) {
113
- return []
114
- }
115
- const labels = dataFormatterGrid.seriesDirection === 'row'
116
- ? dataFormatterGrid.columnLabels
117
- : dataFormatterGrid.rowLabels
118
- return transposedDataGrid[0].map((_, columnLabels) => {
119
- return labels[columnLabels] != null
120
- ? labels[columnLabels]
121
- : createDefaultGroupLabel(`${chartType}_grid${gridIndex}`, columnLabels)
122
- })
123
- }
124
-
125
- // 取得最小及最大值 - 數字陣列
126
- export function getMinMax (data: number[]): [number, number] {
127
- const defaultMinMax: [number, number] = [0, 0] // default
128
- if (!data.length) {
129
- return defaultMinMax
130
- }
131
- const minMax: [number, number] = data.reduce((prev, current) => {
132
- // [min, max]
133
- return [
134
- current < prev[0] ? current : prev[0],
135
- current > prev[1] ? current : prev[1]
136
- ]
137
- }, [data[0], data[0]])
138
- return minMax
139
- }
140
-
141
- // 取得最小及最大值 - datum格式陣列資料
142
- export function getMinMaxValue (data: DatumValue[]): [number, number] {
143
- const arr = data
144
- .filter(d => d != null && d.value != null)
145
- .map(d => d.value )
146
- return getMinMax(arr)
147
- }
148
-
149
- // 取得最小及最大值 - Series Data
150
- export function getMinMaxSeries (data: DataSeries): [number, number] {
151
- const flatData: (DataSeriesValue | DataSeriesDatum)[] = data[0] && Array.isArray((data as (DataSeriesValue | DataSeriesDatum)[][])[0])
152
- ? data.flat()
153
- : data as (DataSeriesValue | DataSeriesDatum)[]
154
- const arr = flatData
155
- .filter(d => (d == null || (isPlainObject(d) && (d as DataSeriesDatum).value == null)) === false) // 過濾掉null &
156
- .map(d => typeof d === 'number' ? d : d.value )
157
- return getMinMax(arr)
158
- }
159
-
160
- // 取得最小及最大值 - Grid Data
161
- export function getMinMaxGrid (data: DataGrid): [number, number] {
162
- const flatData: (DataGridValue | DataGridDatum)[] = data.flat()
163
- const arr = flatData
164
- .filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
165
- .map(d => typeof d === 'number' ? d : d.value )
166
- return getMinMax(arr)
167
- }
168
-
169
- // 取得最小及最大值 - MultiGrid Data
170
- export function getMinMaxMultiGrid (data: DataMultiGrid): [number, number] {
171
- const flatData: (DataGridValue | DataGridDatum)[] = data.flat().flat()
172
- const arr = flatData
173
- .filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
174
- .map(d => typeof d === 'number' ? d : d.value )
175
- return getMinMax(arr)
176
- }
177
-
178
- // 取得最小及最大值 - MultiValue Data
179
- export function getMinMaxMultiValue (data: DataMultiValue, valueIndex: number): [number, number] {
180
- const arr: number[] = data
181
- .map(d => {
182
- if (Array.isArray(d)) {
183
- return d[valueIndex] ?? null
184
- } else if (isPlainObject(d)) {
185
- return (d as DataMultiValueDatum).value[valueIndex] ?? null
186
- } else {
187
- return null
188
- }
189
- })
190
- .filter(d => d != null)
191
- return getMinMax(arr)
192
- }
193
-
194
- export function getMinMaxMultiValueXY ({ data, minX, maxX, minY, maxY }: {
195
- data: ComputedLayoutDatumMultiValue[][]
196
- minX: number
197
- maxX: number
198
- minY: number
199
- maxY: number
200
- }) {
201
- let filteredData: ComputedLayoutDatumMultiValue[][] = []
202
- let minXDatum: ComputedLayoutDatumMultiValue | null = null
203
- let maxXDatum: ComputedLayoutDatumMultiValue | null = null
204
- let minYDatum: ComputedLayoutDatumMultiValue | null = null
205
- let maxYDatum: ComputedLayoutDatumMultiValue | null = null
206
-
207
- for (let categoryData of data) {
208
- for (let datum of categoryData) {
209
- if (datum.axisX >= minX && datum.axisX <= maxX && datum.axisY >= minY && datum.axisY <= maxY) {
210
- filteredData.push(categoryData)
211
- if (minXDatum == null || datum.axisX < minXDatum.axisX) {
212
- minXDatum = datum
213
- }
214
- if (maxXDatum == null || datum.axisX > maxXDatum.axisX) {
215
- maxXDatum = datum
216
- }
217
- if (minYDatum == null || datum.axisY < minYDatum.axisY) {
218
- minYDatum = datum
219
- }
220
- if (maxYDatum == null || datum.axisY > maxYDatum.axisY) {
221
- maxYDatum = datum
222
- }
223
- }
224
- }
225
- }
226
-
227
- return {
228
- minXDatum,
229
- maxXDatum,
230
- minYDatum,
231
- maxYDatum,
232
- filteredData
233
- }
234
- }
235
-
236
- // @Q@ 待處理
237
- // // 取得最小及最大值 - Relationship Data
238
- // export function getMinMaxRelationship (data: DataRelationship, target: 'nodes' | 'edges' = 'nodes'): [number, number] {
239
-
240
- // }
241
-
242
- // @Q@ 待處理
243
- // // 取得最小及最大值 - Tree Data
244
- // export function getMinMaxTree (data: DataTree): [number, number] {
245
-
246
- // }
247
-
248
- // 轉置成seriesDirection為main的陣列格式
249
- export function transposeData<T> (seriesDirection: SeriesDirection, data: T[][]): T[][] {
250
- if (seriesDirection === 'row') {
251
- return Object.assign([], data)
252
- }
253
- // 取得原始陣列的維度
254
- const rows = data.length;
255
- const cols = data.reduce((prev, current) => {
256
- return Math.max(prev, current.length)
257
- }, 0)
258
-
259
- // 初始化轉換後的陣列
260
- const transposedArray = new Array(cols).fill(null).map(() => new Array(rows).fill(null))
261
-
262
- // 遍歷原始陣列,進行轉換
263
- for (let i = 0; i < rows; i++) {
264
- for (let j = 0; j < cols; j++) {
265
- transposedArray[j][i] = data[i][j]
266
- }
267
- }
268
-
269
- return transposedArray
270
- }
271
-
272
-
273
- export function seriesColorPredicate (seriesIndex: number, chartParams: ChartParams) {
274
- return seriesIndex < chartParams.colors[chartParams.colorScheme].label.length
275
- ? chartParams.colors[chartParams.colorScheme].label[seriesIndex]
276
- : chartParams.colors[chartParams.colorScheme].label[
277
- seriesIndex % chartParams.colors[chartParams.colorScheme].label.length
278
- ]
279
- }
280
-
281
-
282
- // 計算預設欄列數量
283
- // 規則1.rowAmount*columnAmount要大於或等於amount,並且數字要盡可能小
284
- // 規則2.columnAmount要大於或等於rowAmount,並且數字要盡可能小
285
- function calcGridDimensions (amount: number): { rowAmount: number; columnAmount: number } {
286
- let rowAmount = Math.floor(Math.sqrt(amount))
287
- let columnAmount = Math.ceil(amount / rowAmount)
288
- while (rowAmount * columnAmount < amount) {
289
- columnAmount++
290
- }
291
- return { rowAmount, columnAmount }
292
- }
293
-
294
- export function calcSeriesContainerLayout (layout: Layout, container: DataFormatterContainer, amount: number): ContainerPosition[] {
295
- const { gap } = container
296
- const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
297
- // 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
298
- ? container
299
- // 否則計算一個合適的預設值
300
- : calcGridDimensions(amount)
301
-
302
- return new Array(amount).fill(null).map((_, index) => {
303
- const columnIndex = index % columnAmount
304
- const rowIndex = Math.floor(index / columnAmount)
305
-
306
- const width = (layout.width - (gap * (columnAmount - 1))) / columnAmount
307
- const height = (layout.height - (gap * (rowAmount - 1))) / rowAmount
308
- const x = columnIndex * width + (columnIndex * gap)
309
- const y = rowIndex * height + (rowIndex * gap)
310
- // const translate: [number, number] = [x, y]
311
-
312
- return {
313
- slotIndex: index,
314
- rowIndex,
315
- columnIndex,
316
- // translate,
317
- startX: x,
318
- startY: y,
319
- centerX: x + width / 2,
320
- centerY: y + height / 2,
321
- width,
322
- height
323
- }
324
- })
325
- }
326
-
327
- export function calcGridContainerLayout (layout: Layout, container: DataFormatterContainer, amount: number): ContainerPositionScaled[] {
328
- const { gap } = container
329
- const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
330
- // 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
331
- ? container
332
- // 否則計算一個合適的預設值
333
- : calcGridDimensions(amount)
334
-
335
- return new Array(amount).fill(null).map((_, index) => {
336
- const columnIndex = index % columnAmount
337
- const rowIndex = Math.floor(index / columnAmount)
338
-
339
- const width = (layout.width - (gap * (columnAmount - 1))) / columnAmount
340
- const height = (layout.height - (gap * (rowAmount - 1))) / rowAmount
341
- const x = columnIndex * width + (columnIndex * gap)
342
- const y = rowIndex * height + (rowIndex * gap)
343
- const translate: [number, number] = [x, y]
344
- const scale: [number, number] = [width / layout.width, height / layout.height]
345
-
346
- return {
347
- slotIndex: index,
348
- rowIndex,
349
- columnIndex,
350
- translate,
351
- scale
352
- }
353
- })
354
- }
355
-
356
- // // multiGrid datum color
357
- // export function multiGridColorPredicate ({ seriesIndex, groupIndex, data, chartParams }: {
358
- // seriesIndex: number
359
- // groupIndex: number
360
- // data: ComputedDataMultiGrid
361
- // chartParams: ChartParams
362
- // }) {
363
- // // 累加前面的grid的seriesIndex
364
- // const accSeriesIndex = data.reduce((prev, current) => {
365
- // if (current[0] && current[0][0] && groupIndex > current[0][0].gridIndex) {
366
- // return prev + current[0].length
367
- // } else if (current[0] && current[0][0] && groupIndex == current[0][0].gridIndex) {
368
- // return prev + seriesIndex
369
- // } else {
370
- // return prev
371
- // }
372
- // }, 0)
373
-
374
- // return seriesColorPredicate(accSeriesIndex, chartParams)
375
- // }
376
-
377
-
1
+ import * as d3 from 'd3'
2
+ import type {
3
+ ChartType,
4
+ ChartParams,
5
+ DatumValue,
6
+ DataSeries,
7
+ DataSeriesDatum,
8
+ DataSeriesValue,
9
+ DataGrid,
10
+ DataGridDatum,
11
+ DataGridValue,
12
+ DataMultiGrid,
13
+ DataMultiValue,
14
+ DataMultiValueDatum,
15
+ DataMultiValueValue,
16
+ ComputedXYDatumMultiValue,
17
+ DataFormatterContainer,
18
+ SeriesDirection,
19
+ DataFormatterGridGrid,
20
+ ContainerPosition,
21
+ ContainerPositionScaled,
22
+ Layout
23
+ } from '../../lib/core-types'
24
+ import { isPlainObject } from './commonUtils'
25
+
26
+ export function formatValueToLabel (value: any, valueFormatter: string | ((text: d3.NumberValue) => string)) {
27
+ if (valueFormatter! instanceof Function == true) {
28
+ return (valueFormatter as ((text: d3.NumberValue) => string))(value)
29
+ }
30
+ return d3.format(valueFormatter as string)!(value)
31
+ }
32
+
33
+ export function createDefaultDatumId (chartTypeOrPrefix: string, levelOneIndex: number, levelTwoIndex?: number, levelThreeIndex?: number) {
34
+ let text = `${chartTypeOrPrefix}_${levelOneIndex}`
35
+ if (levelTwoIndex != null) {
36
+ text += `_${levelTwoIndex}`
37
+ }
38
+ if (levelThreeIndex != null) {
39
+ text += `_${levelThreeIndex}`
40
+ }
41
+ return text
42
+ }
43
+
44
+ export function createDefaultSeriesLabel (chartTypeOrPrefix: string, seriesIndex: number) {
45
+ return `${chartTypeOrPrefix}_series${seriesIndex}`
46
+ }
47
+
48
+ export function createDefaultGroupLabel (chartTypeOrPrefix: string, groupIndex: number) {
49
+ return `${chartTypeOrPrefix}_group${groupIndex}`
50
+ }
51
+
52
+ export function createDefaultCategoryLabel () {
53
+ // return `${chartTypeOrPrefix}_category`
54
+ return '' // 空值
55
+ }
56
+
57
+ export function createGridSeriesLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'grid' }: {
58
+ transposedDataGrid: DataGridDatum[][],
59
+ dataFormatterGrid: DataFormatterGridGrid
60
+ chartType?: ChartType
61
+ }) {
62
+ const labels = dataFormatterGrid.seriesDirection === 'row'
63
+ ? dataFormatterGrid.rowLabels
64
+ : dataFormatterGrid.columnLabels
65
+ return transposedDataGrid.map((_, rowIndex) => {
66
+ return labels[rowIndex] != null
67
+ ? labels[rowIndex]
68
+ : createDefaultSeriesLabel(chartType, rowIndex)
69
+ })
70
+ }
71
+
72
+ export function createMultiGridSeriesLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'multiGrid', gridIndex = 0 }: {
73
+ transposedDataGrid: DataGridDatum[][],
74
+ dataFormatterGrid: DataFormatterGridGrid
75
+ chartType?: ChartType
76
+ gridIndex?: number
77
+ }) {
78
+ const labels = dataFormatterGrid.seriesDirection === 'row'
79
+ ? dataFormatterGrid.rowLabels
80
+ : dataFormatterGrid.columnLabels
81
+ return transposedDataGrid.map((_, rowIndex) => {
82
+ return labels[rowIndex] != null
83
+ ? labels[rowIndex]
84
+ : createDefaultSeriesLabel(`${chartType}_grid${gridIndex}`, rowIndex)
85
+ })
86
+ }
87
+
88
+ export function createGridGroupLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'grid' }: {
89
+ transposedDataGrid: DataGridDatum[][],
90
+ dataFormatterGrid: DataFormatterGridGrid
91
+ chartType?: ChartType
92
+ }) {
93
+ if (transposedDataGrid[0] == null) {
94
+ return []
95
+ }
96
+ const labels = dataFormatterGrid.seriesDirection === 'row'
97
+ ? dataFormatterGrid.columnLabels
98
+ : dataFormatterGrid.rowLabels
99
+ return transposedDataGrid[0].map((_, columnLabels) => {
100
+ return labels[columnLabels] != null
101
+ ? labels[columnLabels]
102
+ : createDefaultGroupLabel(chartType, columnLabels)
103
+ })
104
+ }
105
+
106
+ export function createMultiGridGroupLabels ({ transposedDataGrid, dataFormatterGrid, chartType = 'multiGrid', gridIndex = 0 }: {
107
+ transposedDataGrid: DataGridDatum[][],
108
+ dataFormatterGrid: DataFormatterGridGrid
109
+ chartType?: ChartType
110
+ gridIndex?: number
111
+ }) {
112
+ if (transposedDataGrid[0] == null) {
113
+ return []
114
+ }
115
+ const labels = dataFormatterGrid.seriesDirection === 'row'
116
+ ? dataFormatterGrid.columnLabels
117
+ : dataFormatterGrid.rowLabels
118
+ return transposedDataGrid[0].map((_, columnLabels) => {
119
+ return labels[columnLabels] != null
120
+ ? labels[columnLabels]
121
+ : createDefaultGroupLabel(`${chartType}_grid${gridIndex}`, columnLabels)
122
+ })
123
+ }
124
+
125
+ // 取得最小及最大值 - 數字陣列
126
+ export function getMinMax (data: number[]): [number, number] {
127
+ const defaultMinMax: [number, number] = [0, 0] // default
128
+ if (!data.length) {
129
+ return defaultMinMax
130
+ }
131
+ const minMax: [number, number] = data.reduce((prev, current) => {
132
+ // [min, max]
133
+ return [
134
+ current < prev[0] ? current : prev[0],
135
+ current > prev[1] ? current : prev[1]
136
+ ]
137
+ }, [data[0], data[0]])
138
+ return minMax
139
+ }
140
+
141
+ // 取得最小及最大值 - datum格式陣列資料
142
+ export function getMinMaxValue (data: DatumValue[]): [number, number] {
143
+ const arr = data
144
+ .filter(d => d != null && d.value != null)
145
+ .map(d => d.value )
146
+ return getMinMax(arr)
147
+ }
148
+
149
+ // 取得最小及最大值 - Series Data
150
+ export function getMinMaxSeries (data: DataSeries): [number, number] {
151
+ const flatData: (DataSeriesValue | DataSeriesDatum)[] = data[0] && Array.isArray((data as (DataSeriesValue | DataSeriesDatum)[][])[0])
152
+ ? data.flat()
153
+ : data as (DataSeriesValue | DataSeriesDatum)[]
154
+ const arr = flatData
155
+ .filter(d => (d == null || (isPlainObject(d) && (d as DataSeriesDatum).value == null)) === false) // 過濾掉null &
156
+ .map(d => typeof d === 'number' ? d : d.value )
157
+ return getMinMax(arr)
158
+ }
159
+
160
+ // 取得最小及最大值 - Grid Data
161
+ export function getMinMaxGrid (data: DataGrid): [number, number] {
162
+ const flatData: (DataGridValue | DataGridDatum)[] = data.flat()
163
+ const arr = flatData
164
+ .filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
165
+ .map(d => typeof d === 'number' ? d : d.value )
166
+ return getMinMax(arr)
167
+ }
168
+
169
+ // 取得最小及最大值 - MultiGrid Data
170
+ export function getMinMaxMultiGrid (data: DataMultiGrid): [number, number] {
171
+ const flatData: (DataGridValue | DataGridDatum)[] = data.flat().flat()
172
+ const arr = flatData
173
+ .filter(d => (d == null || (isPlainObject(d) && (d as DataGridDatum).value == null)) === false) // 過濾掉null
174
+ .map(d => typeof d === 'number' ? d : d.value )
175
+ return getMinMax(arr)
176
+ }
177
+
178
+ // 取得最小及最大值 - MultiValue Data
179
+ export function getMinMaxMultiValue (data: DataMultiValue, valueIndex: number): [number, number] {
180
+ const arr: number[] = data
181
+ .map(d => {
182
+ if (Array.isArray(d)) {
183
+ return d[valueIndex] ?? null
184
+ } else if (isPlainObject(d)) {
185
+ return (d as DataMultiValueDatum).value[valueIndex] ?? null
186
+ } else {
187
+ return null
188
+ }
189
+ })
190
+ .filter(d => d != null)
191
+ return getMinMax(arr)
192
+ }
193
+
194
+ export function getMinMaxMultiValueXY ({ data, minX, maxX, minY, maxY }: {
195
+ data: ComputedXYDatumMultiValue[][]
196
+ minX: number
197
+ maxX: number
198
+ minY: number
199
+ maxY: number
200
+ }) {
201
+ let filteredData: ComputedXYDatumMultiValue[][] = []
202
+ let minXDatum: ComputedXYDatumMultiValue | null = null
203
+ let maxXDatum: ComputedXYDatumMultiValue | null = null
204
+ let minYDatum: ComputedXYDatumMultiValue | null = null
205
+ let maxYDatum: ComputedXYDatumMultiValue | null = null
206
+
207
+ for (let categoryData of data) {
208
+ for (let datum of categoryData) {
209
+ if (datum.axisX >= minX && datum.axisX <= maxX && datum.axisY >= minY && datum.axisY <= maxY) {
210
+ filteredData.push(categoryData)
211
+ if (minXDatum == null || datum.axisX < minXDatum.axisX) {
212
+ minXDatum = datum
213
+ }
214
+ if (maxXDatum == null || datum.axisX > maxXDatum.axisX) {
215
+ maxXDatum = datum
216
+ }
217
+ if (minYDatum == null || datum.axisY < minYDatum.axisY) {
218
+ minYDatum = datum
219
+ }
220
+ if (maxYDatum == null || datum.axisY > maxYDatum.axisY) {
221
+ maxYDatum = datum
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ return {
228
+ minXDatum,
229
+ maxXDatum,
230
+ minYDatum,
231
+ maxYDatum,
232
+ filteredData
233
+ }
234
+ }
235
+
236
+ // @Q@ 待處理
237
+ // // 取得最小及最大值 - Relationship Data
238
+ // export function getMinMaxRelationship (data: DataRelationship, target: 'nodes' | 'edges' = 'nodes'): [number, number] {
239
+
240
+ // }
241
+
242
+ // @Q@ 待處理
243
+ // // 取得最小及最大值 - Tree Data
244
+ // export function getMinMaxTree (data: DataTree): [number, number] {
245
+
246
+ // }
247
+
248
+ // 轉置成seriesDirection為main的陣列格式
249
+ export function transposeData<T> (seriesDirection: SeriesDirection, data: T[][]): T[][] {
250
+ if (seriesDirection === 'row') {
251
+ return Object.assign([], data)
252
+ }
253
+ // 取得原始陣列的維度
254
+ const rows = data.length;
255
+ const cols = data.reduce((prev, current) => {
256
+ return Math.max(prev, current.length)
257
+ }, 0)
258
+
259
+ // 初始化轉換後的陣列
260
+ const transposedArray = new Array(cols).fill(null).map(() => new Array(rows).fill(null))
261
+
262
+ // 遍歷原始陣列,進行轉換
263
+ for (let i = 0; i < rows; i++) {
264
+ for (let j = 0; j < cols; j++) {
265
+ transposedArray[j][i] = data[i][j]
266
+ }
267
+ }
268
+
269
+ return transposedArray
270
+ }
271
+
272
+
273
+ export function seriesColorPredicate (seriesIndex: number, chartParams: ChartParams) {
274
+ return seriesIndex < chartParams.colors[chartParams.colorScheme].label.length
275
+ ? chartParams.colors[chartParams.colorScheme].label[seriesIndex]
276
+ : chartParams.colors[chartParams.colorScheme].label[
277
+ seriesIndex % chartParams.colors[chartParams.colorScheme].label.length
278
+ ]
279
+ }
280
+
281
+
282
+ // 計算預設欄列數量
283
+ // 規則1.rowAmount*columnAmount要大於或等於amount,並且數字要盡可能小
284
+ // 規則2.columnAmount要大於或等於rowAmount,並且數字要盡可能小
285
+ function calcGridDimensions (amount: number): { rowAmount: number; columnAmount: number } {
286
+ let rowAmount = Math.floor(Math.sqrt(amount))
287
+ let columnAmount = Math.ceil(amount / rowAmount)
288
+ while (rowAmount * columnAmount < amount) {
289
+ columnAmount++
290
+ }
291
+ return { rowAmount, columnAmount }
292
+ }
293
+
294
+ export function calcContainerPosition (layout: Layout, container: DataFormatterContainer, amount: number): ContainerPosition[] {
295
+ const { gap } = container
296
+ const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
297
+ // 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
298
+ ? container
299
+ // 否則計算一個合適的預設值
300
+ : calcGridDimensions(amount)
301
+
302
+ return new Array(amount).fill(null).map((_, index) => {
303
+ const columnIndex = index % columnAmount
304
+ const rowIndex = Math.floor(index / columnAmount)
305
+
306
+ const width = (layout.width - (gap * (columnAmount - 1))) / columnAmount
307
+ const height = (layout.height - (gap * (rowAmount - 1))) / rowAmount
308
+ const x = columnIndex * width + (columnIndex * gap)
309
+ const y = rowIndex * height + (rowIndex * gap)
310
+ // const translate: [number, number] = [x, y]
311
+
312
+ return {
313
+ slotIndex: index,
314
+ rowIndex,
315
+ columnIndex,
316
+ // translate,
317
+ startX: x,
318
+ startY: y,
319
+ centerX: x + width / 2,
320
+ centerY: y + height / 2,
321
+ width,
322
+ height
323
+ }
324
+ })
325
+ }
326
+
327
+ export function calcContainerPositionScaled (layout: Layout, container: DataFormatterContainer, amount: number): ContainerPositionScaled[] {
328
+ const { gap } = container
329
+ const { rowAmount, columnAmount } = (container.rowAmount * container.columnAmount) >= amount
330
+ // 如果container設定的rowAmount和columnAmount的乘積大於或等於amount,則使用目前設定
331
+ ? container
332
+ // 否則計算一個合適的預設值
333
+ : calcGridDimensions(amount)
334
+
335
+ return new Array(amount).fill(null).map((_, index) => {
336
+ const columnIndex = index % columnAmount
337
+ const rowIndex = Math.floor(index / columnAmount)
338
+
339
+ const width = (layout.width - (gap * (columnAmount - 1))) / columnAmount
340
+ const height = (layout.height - (gap * (rowAmount - 1))) / rowAmount
341
+ const x = columnIndex * width + (columnIndex * gap)
342
+ const y = rowIndex * height + (rowIndex * gap)
343
+ const translate: [number, number] = [x, y]
344
+ const scale: [number, number] = [width / layout.width, height / layout.height]
345
+
346
+ return {
347
+ slotIndex: index,
348
+ rowIndex,
349
+ columnIndex,
350
+ translate,
351
+ scale
352
+ }
353
+ })
354
+ }
355
+
356
+ // // multiGrid datum color
357
+ // export function multiGridColorPredicate ({ seriesIndex, groupIndex, data, chartParams }: {
358
+ // seriesIndex: number
359
+ // groupIndex: number
360
+ // data: ComputedDataMultiGrid
361
+ // chartParams: ChartParams
362
+ // }) {
363
+ // // 累加前面的grid的seriesIndex
364
+ // const accSeriesIndex = data.reduce((prev, current) => {
365
+ // if (current[0] && current[0][0] && groupIndex > current[0][0].gridIndex) {
366
+ // return prev + current[0].length
367
+ // } else if (current[0] && current[0][0] && groupIndex == current[0][0].gridIndex) {
368
+ // return prev + seriesIndex
369
+ // } else {
370
+ // return prev
371
+ // }
372
+ // }, 0)
373
+
374
+ // return seriesColorPredicate(accSeriesIndex, chartParams)
375
+ // }
376
+
377
+