@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,36 +1,36 @@
1
- export type ToBeTypes = 'string' | 'number' | 'boolean' | 'object' | 'object[]' | 'string[]' | 'number[]' | 'Function' | 'null' | 'undefined'
2
-
3
- export type ToBeOption = 'ColorType'
4
-
5
- // 有使用定義好的型別則不需寫 validate
6
- export interface ValidatorRuleToBeTypes {
7
- toBeTypes: ToBeTypes[]
8
- }
9
-
10
- // 自訂規則
11
- export interface ValidatorRuleToBe {
12
- toBe: string
13
- test: (value: any) => boolean
14
- }
15
-
16
- // 選項資料型別
17
- export interface ValidatorRuleToBeOption {
18
- toBeOption: ToBeOption
19
- }
20
-
21
- export type ValidatorRule<T> = {[key in keyof T]: ValidatorRuleToBeTypes | ValidatorRuleToBe | ValidatorRuleToBeOption}
22
-
23
-
24
- // export type ValidateObject<T> = (data: T, rules: ValidatorRule<T>) => ValidatorResult
25
-
26
- // export interface ValidatorUtils {
27
- // validateObject: typeof validateObject // 我發現要這樣寫才能夠透過 data 型別自動推斷出 T,不曉得有沒有更好的寫法
28
- // }
29
-
30
-
31
- export interface ValidatorResult {
32
- status: 'success' | 'warning' | 'error'
33
- // message: string // warning or error message
34
- columnName: string,
35
- expectToBe: string,
1
+ export type ToBeTypes = 'string' | 'number' | 'boolean' | 'object' | 'object[]' | 'string[]' | 'number[]' | 'Function' | 'null' | 'undefined'
2
+
3
+ export type ToBeOption = 'ColorType'
4
+
5
+ // 有使用定義好的型別則不需寫 validate
6
+ export interface ValidatorRuleToBeTypes {
7
+ toBeTypes: ToBeTypes[]
8
+ }
9
+
10
+ // 自訂規則
11
+ export interface ValidatorRuleToBe {
12
+ toBe: string
13
+ test: (value: any) => boolean
14
+ }
15
+
16
+ // 選項資料型別
17
+ export interface ValidatorRuleToBeOption {
18
+ toBeOption: ToBeOption
19
+ }
20
+
21
+ export type ValidatorRule<T> = {[key in keyof T]: ValidatorRuleToBeTypes | ValidatorRuleToBe | ValidatorRuleToBeOption}
22
+
23
+
24
+ // export type ValidateObject<T> = (data: T, rules: ValidatorRule<T>) => ValidatorResult
25
+
26
+ // export interface ValidatorUtils {
27
+ // validateObject: typeof validateObject // 我發現要這樣寫才能夠透過 data 型別自動推斷出 T,不曉得有沒有更好的寫法
28
+ // }
29
+
30
+
31
+ export interface ValidatorResult {
32
+ status: 'success' | 'warning' | 'error'
33
+ // message: string // warning or error message
34
+ columnName: string,
35
+ expectToBe: string,
36
36
  }
@@ -1,12 +1,12 @@
1
- export * from './Chart'
2
- export * from './ChartContext'
3
- export * from './Encoding'
4
- export * from './Event'
5
- export * from './Layers'
6
- export * from './ModelData'
7
- export * from './Plugin'
8
- export * from './RawData'
9
- export * from './RenderData'
10
- export * from './Theme'
11
- export * from './Validator'
12
- export * from './Common'
1
+ export * from './Chart'
2
+ export * from './ChartContext'
3
+ export * from './Encoding'
4
+ export * from './Event'
5
+ export * from './Layers'
6
+ export * from './ModelData'
7
+ export * from './Plugin'
8
+ export * from './RawData'
9
+ export * from './RenderData'
10
+ export * from './Theme'
11
+ export * from './Validator'
12
+ export * from './Common'
@@ -1,99 +1,99 @@
1
- /**
2
- * 聚合函數工具集
3
- * 用於處理數值陣列的各種聚合運算
4
- */
5
-
6
- export type AggregateType = 'sum' | 'mean' | 'median' | 'min' | 'max' | 'count' | 'none'
7
-
8
- /**
9
- * 計算數值陣列的總和
10
- */
11
- export function sum(values: (number | null)[]): number | null {
12
- const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
13
- if (validValues.length === 0) return null
14
- return validValues.reduce((acc, val) => acc + val, 0)
15
- }
16
-
17
- /**
18
- * 計算數值陣列的平均值
19
- */
20
- export function mean(values: (number | null)[]): number | null {
21
- const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
22
- if (validValues.length === 0) return null
23
- const total = validValues.reduce((acc, val) => acc + val, 0)
24
- return total / validValues.length
25
- }
26
-
27
- /**
28
- * 計算數值陣列的中位數
29
- */
30
- export function median(values: (number | null)[]): number | null {
31
- const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
32
- if (validValues.length === 0) return null
33
-
34
- const sorted = [...validValues].sort((a, b) => a - b)
35
- const mid = Math.floor(sorted.length / 2)
36
-
37
- if (sorted.length % 2 === 0) {
38
- return (sorted[mid - 1] + sorted[mid]) / 2
39
- } else {
40
- return sorted[mid]
41
- }
42
- }
43
-
44
- /**
45
- * 計算數值陣列的最小值
46
- */
47
- export function min(values: (number | null)[]): number | null {
48
- const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
49
- if (validValues.length === 0) return null
50
- return Math.min(...validValues)
51
- }
52
-
53
- /**
54
- * 計算數值陣列的最大值
55
- */
56
- export function max(values: (number | null)[]): number | null {
57
- const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
58
- if (validValues.length === 0) return null
59
- return Math.max(...validValues)
60
- }
61
-
62
- /**
63
- * 計算數值陣列的有效數量
64
- */
65
- export function count(values: (number | null)[]): number {
66
- return values.filter((v): v is number => v !== null && !isNaN(v)).length
67
- }
68
-
69
- /**
70
- * 不進行聚合,返回第一個有效值
71
- */
72
- export function none(values: (number | null)[]): number | null {
73
- const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
74
- return validValues.length > 0 ? validValues[0] : null
75
- }
76
-
77
- /**
78
- * 根據聚合類型執行對應的聚合函數
79
- */
80
- export function aggregate(values: (number | null)[], type: AggregateType): number | null {
81
- switch (type) {
82
- case 'sum':
83
- return sum(values)
84
- case 'mean':
85
- return mean(values)
86
- case 'median':
87
- return median(values)
88
- case 'min':
89
- return min(values)
90
- case 'max':
91
- return max(values)
92
- case 'count':
93
- return count(values)
94
- case 'none':
95
- return none(values)
96
- default:
97
- throw new Error(`Unknown aggregate type: ${type}`)
98
- }
99
- }
1
+ /**
2
+ * 聚合函數工具集
3
+ * 用於處理數值陣列的各種聚合運算
4
+ */
5
+
6
+ export type AggregateType = 'sum' | 'mean' | 'median' | 'min' | 'max' | 'count' | 'none'
7
+
8
+ /**
9
+ * 計算數值陣列的總和
10
+ */
11
+ export function sum(values: (number | null)[]): number | null {
12
+ const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
13
+ if (validValues.length === 0) return null
14
+ return validValues.reduce((acc, val) => acc + val, 0)
15
+ }
16
+
17
+ /**
18
+ * 計算數值陣列的平均值
19
+ */
20
+ export function mean(values: (number | null)[]): number | null {
21
+ const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
22
+ if (validValues.length === 0) return null
23
+ const total = validValues.reduce((acc, val) => acc + val, 0)
24
+ return total / validValues.length
25
+ }
26
+
27
+ /**
28
+ * 計算數值陣列的中位數
29
+ */
30
+ export function median(values: (number | null)[]): number | null {
31
+ const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
32
+ if (validValues.length === 0) return null
33
+
34
+ const sorted = [...validValues].sort((a, b) => a - b)
35
+ const mid = Math.floor(sorted.length / 2)
36
+
37
+ if (sorted.length % 2 === 0) {
38
+ return (sorted[mid - 1] + sorted[mid]) / 2
39
+ } else {
40
+ return sorted[mid]
41
+ }
42
+ }
43
+
44
+ /**
45
+ * 計算數值陣列的最小值
46
+ */
47
+ export function min(values: (number | null)[]): number | null {
48
+ const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
49
+ if (validValues.length === 0) return null
50
+ return Math.min(...validValues)
51
+ }
52
+
53
+ /**
54
+ * 計算數值陣列的最大值
55
+ */
56
+ export function max(values: (number | null)[]): number | null {
57
+ const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
58
+ if (validValues.length === 0) return null
59
+ return Math.max(...validValues)
60
+ }
61
+
62
+ /**
63
+ * 計算數值陣列的有效數量
64
+ */
65
+ export function count(values: (number | null)[]): number {
66
+ return values.filter((v): v is number => v !== null && !isNaN(v)).length
67
+ }
68
+
69
+ /**
70
+ * 不進行聚合,返回第一個有效值
71
+ */
72
+ export function none(values: (number | null)[]): number | null {
73
+ const validValues = values.filter((v): v is number => v !== null && !isNaN(v))
74
+ return validValues.length > 0 ? validValues[0] : null
75
+ }
76
+
77
+ /**
78
+ * 根據聚合類型執行對應的聚合函數
79
+ */
80
+ export function aggregate(values: (number | null)[], type: AggregateType): number | null {
81
+ switch (type) {
82
+ case 'sum':
83
+ return sum(values)
84
+ case 'mean':
85
+ return mean(values)
86
+ case 'median':
87
+ return median(values)
88
+ case 'min':
89
+ return min(values)
90
+ case 'max':
91
+ return max(values)
92
+ case 'count':
93
+ return count(values)
94
+ case 'none':
95
+ return none(values)
96
+ default:
97
+ throw new Error(`Unknown aggregate type: ${type}`)
98
+ }
99
+ }
@@ -1,63 +1,63 @@
1
- import type { Theme } from '../types'
2
-
3
- /**
4
- * 根據索引和主題計算對應的顏色
5
- * @param index 索引值
6
- * @param theme 主題設定
7
- * @returns 對應的顏色(hex 格式)
8
- */
9
- export function getColorByIndex(index: number, theme: Theme): string {
10
- // 根據 colorScheme 決定使用哪個色彩方案
11
- let colorScheme: 'light' | 'dark'
12
- if (theme.colorScheme === 'auto') {
13
- // 可以根據系統設定或其他邏輯來決定,這裡預設使用 light
14
- colorScheme = 'light'
15
- } else {
16
- colorScheme = theme.colorScheme
17
- }
18
-
19
- const dataColors = theme.colors[colorScheme].data
20
-
21
- // 使用模運算來循環使用色票
22
- const colorIndex = index % dataColors.length
23
- return dataColors[colorIndex]
24
- }
25
-
26
- /**
27
- * 根據不同的 encoding.color.from 計算顏色
28
- * @param colorFrom 顏色來源類型
29
- * @param options 包含所有可能索引的選項物件
30
- * @param theme 主題設定
31
- * @returns 對應的顏色(hex 格式)
32
- */
33
- export function getColorByFrom(
34
- colorFrom: 'index' | 'series' | 'category' | 'dataset',
35
- options: {
36
- index?: number
37
- seriesIndex?: number
38
- categoryIndex?: number
39
- datasetIndex?: number
40
- },
41
- theme: Theme
42
- ): string {
43
- let targetIndex: number
44
-
45
- switch (colorFrom) {
46
- case 'index':
47
- targetIndex = options.index ?? 0
48
- break
49
- case 'series':
50
- targetIndex = options.seriesIndex ?? 0
51
- break
52
- case 'category':
53
- targetIndex = options.categoryIndex ?? 0
54
- break
55
- case 'dataset':
56
- targetIndex = options.datasetIndex ?? 0
57
- break
58
- default:
59
- targetIndex = 0
60
- }
61
-
62
- return getColorByIndex(targetIndex, theme)
63
- }
1
+ import type { Theme } from '../types'
2
+
3
+ /**
4
+ * 根據索引和主題計算對應的顏色
5
+ * @param index 索引值
6
+ * @param theme 主題設定
7
+ * @returns 對應的顏色(hex 格式)
8
+ */
9
+ export function getColorByIndex(index: number, theme: Theme): string {
10
+ // 根據 colorScheme 決定使用哪個色彩方案
11
+ let colorScheme: 'light' | 'dark'
12
+ if (theme.colorScheme === 'auto') {
13
+ // 可以根據系統設定或其他邏輯來決定,這裡預設使用 light
14
+ colorScheme = 'light'
15
+ } else {
16
+ colorScheme = theme.colorScheme
17
+ }
18
+
19
+ const dataColors = theme.colors[colorScheme].data
20
+
21
+ // 使用模運算來循環使用色票
22
+ const colorIndex = index % dataColors.length
23
+ return dataColors[colorIndex]
24
+ }
25
+
26
+ /**
27
+ * 根據不同的 encoding.color.from 計算顏色
28
+ * @param colorFrom 顏色來源類型
29
+ * @param options 包含所有可能索引的選項物件
30
+ * @param theme 主題設定
31
+ * @returns 對應的顏色(hex 格式)
32
+ */
33
+ export function getColorByFrom(
34
+ colorFrom: 'index' | 'series' | 'category' | 'dataset',
35
+ options: {
36
+ index?: number
37
+ seriesIndex?: number
38
+ categoryIndex?: number
39
+ datasetIndex?: number
40
+ },
41
+ theme: Theme
42
+ ): string {
43
+ let targetIndex: number
44
+
45
+ switch (colorFrom) {
46
+ case 'index':
47
+ targetIndex = options.index ?? 0
48
+ break
49
+ case 'series':
50
+ targetIndex = options.seriesIndex ?? 0
51
+ break
52
+ case 'category':
53
+ targetIndex = options.categoryIndex ?? 0
54
+ break
55
+ case 'dataset':
56
+ targetIndex = options.datasetIndex ?? 0
57
+ break
58
+ default:
59
+ targetIndex = 0
60
+ }
61
+
62
+ return getColorByIndex(targetIndex, theme)
63
+ }
@@ -1,56 +1,56 @@
1
- import { DeepPartial } from "../types/Common";
2
-
3
- // 是否為原始物件
4
- export function isPlainObject(variable: any) {
5
- return Object.prototype.toString.call(variable) === "[object Object]";
6
- }
7
-
8
- // 是否為function
9
- export function isFunction(fn: any) {
10
- // return !!fn && !fn.nodename && fn.constructor != String && fn.constructor != RegExp && fn.constructor != Array && /function/i.test(fn + "");
11
- return Object.prototype.toString.call(fn) === '[object Function]'
12
- }
13
-
14
- // 是否為dom
15
- export function isDom(obj: any) {
16
- return !!(obj && obj.nodeType);
17
- }
18
-
19
- // 將可選的參數和預設值合併
20
- export function deepOverwrite<DeepRecord extends Record<string, any>>(full: DeepRecord, options: DeepPartial<DeepRecord>): DeepRecord {
21
- if (isPlainObject(options) === false || isPlainObject(full) === false) {
22
- return Object.assign({}, full)
23
- }
24
- const mergeObject = (_full: DeepRecord, _options: DeepPartial<DeepRecord>) => {
25
- const obj: DeepRecord = (Object.assign({}, _full) as any)
26
- for (let key of Object.keys(_options)) {
27
- if ((key in _full) == false) {
28
- continue
29
- }
30
- let objValue: any = undefined
31
- // 下一層的plain object
32
- if (isPlainObject(_options[key]) && isPlainObject(_full[key])) {
33
- objValue = mergeObject(_full[key], _options[key])
34
- obj[key as keyof DeepRecord] = objValue
35
- }
36
- // 不是plain object直接賦值
37
- else {
38
- obj[key as keyof DeepRecord] = _options[key] as DeepRecord[typeof key]
39
- }
40
- }
41
- return obj
42
- }
43
-
44
- return mergeObject(full, options)
45
- }
46
-
47
- // 加上千分位 ,
48
- export function formatCommaNumber (num = 0): string {
49
- try {
50
- let parts = num.toString().split('.');
51
- parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
52
- return parts.join('.');
53
- } catch (e: any) {
54
- console.error(e)
55
- }
56
- }
1
+ import { DeepPartial } from "../types/Common";
2
+
3
+ // 是否為原始物件
4
+ export function isPlainObject(variable: any) {
5
+ return Object.prototype.toString.call(variable) === "[object Object]";
6
+ }
7
+
8
+ // 是否為function
9
+ export function isFunction(fn: any) {
10
+ // return !!fn && !fn.nodename && fn.constructor != String && fn.constructor != RegExp && fn.constructor != Array && /function/i.test(fn + "");
11
+ return Object.prototype.toString.call(fn) === '[object Function]'
12
+ }
13
+
14
+ // 是否為dom
15
+ export function isDom(obj: any) {
16
+ return !!(obj && obj.nodeType);
17
+ }
18
+
19
+ // 將可選的參數和預設值合併
20
+ export function deepOverwrite<DeepRecord extends Record<string, any>>(full: DeepRecord, options: DeepPartial<DeepRecord>): DeepRecord {
21
+ if (isPlainObject(options) === false || isPlainObject(full) === false) {
22
+ return Object.assign({}, full)
23
+ }
24
+ const mergeObject = (_full: DeepRecord, _options: DeepPartial<DeepRecord>) => {
25
+ const obj: DeepRecord = (Object.assign({}, _full) as any)
26
+ for (let key of Object.keys(_options)) {
27
+ if ((key in _full) == false) {
28
+ continue
29
+ }
30
+ let objValue: any = undefined
31
+ // 下一層的plain object
32
+ if (isPlainObject(_options[key]) && isPlainObject(_full[key])) {
33
+ objValue = mergeObject(_full[key], _options[key])
34
+ obj[key as keyof DeepRecord] = objValue
35
+ }
36
+ // 不是plain object直接賦值
37
+ else {
38
+ obj[key as keyof DeepRecord] = _options[key] as DeepRecord[typeof key]
39
+ }
40
+ }
41
+ return obj
42
+ }
43
+
44
+ return mergeObject(full, options)
45
+ }
46
+
47
+ // 加上千分位 ,
48
+ export function formatCommaNumber (num = 0): string {
49
+ try {
50
+ let parts = num.toString().split('.');
51
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
52
+ return parts.join('.');
53
+ } catch (e: any) {
54
+ console.error(e)
55
+ }
56
+ }