lowcoder-map-component 0.1.1
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.
- package/README.md +37 -0
- package/icons/demo-icon.svg +10 -0
- package/icons/hills.svg +17 -0
- package/index.css +27 -0
- package/index.html +35 -0
- package/index.tsx +20 -0
- package/loader.mjs +11 -0
- package/package.json +175 -0
- package/src/README.md +35 -0
- package/src/components/ChartPropertyView.tsx +961 -0
- package/src/components/SeriesComp.tsx +368 -0
- package/src/components/TabPropertyView.tsx +127 -0
- package/src/comps/Barcharts/comp.tsx +338 -0
- package/src/comps/Barcharts/constants.tsx +77 -0
- package/src/comps/Linecharts/comp.tsx +350 -0
- package/src/comps/Linecharts/constants.tsx +53 -0
- package/src/comps/Linechartsv2/comp.tsx +350 -0
- package/src/comps/Linechartsv2/constants.tsx +68 -0
- package/src/comps/Mapcharts/comp.tsx +381 -0
- package/src/comps/Mapcharts/constants.tsx +312 -0
- package/src/comps/Mapchartsv2/comp.tsx +393 -0
- package/src/comps/Mapchartsv2/constants.tsx +340 -0
- package/src/comps/MixedLineBarCharts/comp.tsx +353 -0
- package/src/comps/MixedLineBarCharts/constants.tsx +60 -0
- package/src/comps/MultiLineCharts/comp.tsx +362 -0
- package/src/comps/MultiLineCharts/constants.tsx +96 -0
- package/src/comps/PercentageCharts/comp.tsx +359 -0
- package/src/comps/PercentageCharts/constants.tsx +98 -0
- package/src/comps/Piecharts/comp.tsx +334 -0
- package/src/comps/Piecharts/constants.tsx +48 -0
- package/src/comps/Tablecharts/comp.tsx +429 -0
- package/src/comps/Tablecharts/constants.tsx +97 -0
- package/src/comps/Totalcharts/comp.tsx +463 -0
- package/src/comps/Totalcharts/constants.tsx +66 -0
- package/src/comps/TwoLineCharts/comp.tsx +350 -0
- package/src/comps/TwoLineCharts/constants.tsx +82 -0
- package/src/comps/mapComponent/comp.tsx +338 -0
- package/src/comps/mapComponent/constants.tsx +2149 -0
- package/src/comps/tab/comp.tsx +283 -0
- package/src/comps/tab/constants.tsx +79 -0
- package/src/configs/barChartConfig.tsx +153 -0
- package/src/configs/baseConfig.tsx +66 -0
- package/src/configs/candleStickChartConfig.tsx +35 -0
- package/src/configs/cartesianAxisConfig.tsx +314 -0
- package/src/configs/chartUrls.tsx +9 -0
- package/src/configs/echartConfig.tsx +260 -0
- package/src/configs/echartsLabelConfig.tsx +47 -0
- package/src/configs/echartsLegendConfig.tsx +29 -0
- package/src/configs/echartsTitleConfig.tsx +49 -0
- package/src/configs/echartsTitleVerticalConfig.tsx +50 -0
- package/src/configs/funnelChartConfig.tsx +35 -0
- package/src/configs/gaugeChartConfig.tsx +31 -0
- package/src/configs/graphChartConfig.tsx +31 -0
- package/src/configs/heatmapChartConfig.tsx +31 -0
- package/src/configs/legendConfig.tsx +55 -0
- package/src/configs/lineChartConfig.tsx +246 -0
- package/src/configs/lineChartConfigv2.tsx +246 -0
- package/src/configs/mapChartConfig.tsx +106 -0
- package/src/configs/mapChartConfigv2.tsx +106 -0
- package/src/configs/mixedChartConfig.tsx +21 -0
- package/src/configs/pieChartConfig.tsx +156 -0
- package/src/configs/radarChartConfig.tsx +31 -0
- package/src/configs/sankeyChartConfig.tsx +35 -0
- package/src/configs/scatterChartConfig.tsx +152 -0
- package/src/configs/sunburstChartConfig.tsx +31 -0
- package/src/configs/tabConfig.tsx +0 -0
- package/src/configs/tableChartConfig.tsx +81 -0
- package/src/configs/themeriverChartConfig.tsx +31 -0
- package/src/configs/totalChartConfig.tsx +670 -0
- package/src/configs/treeChartConfig.tsx +31 -0
- package/src/configs/treemapChartConfig.tsx +31 -0
- package/src/controls/AnimationsControls.tsx +3 -0
- package/src/controls/AutoHeightControl.tsx +2 -0
- package/src/controls/AxisControls.tsx +146 -0
- package/src/controls/AxisVisibilityControl.tsx +14 -0
- package/src/controls/ChartTypeControl.tsx +15 -0
- package/src/controls/ColorScaleControl.tsx +221 -0
- package/src/controls/ColumnControl.tsx +204 -0
- package/src/controls/ConfigControl.tsx +37 -0
- package/src/controls/DirectionControls.tsx +20 -0
- package/src/controls/IconControl.tsx +88 -0
- package/src/controls/LegendControl.tsx +8 -0
- package/src/controls/RowLimitControl.tsx +91 -0
- package/src/controls/StyleControls.tsx +22 -0
- package/src/controls/TimeControls.tsx +41 -0
- package/src/controls/TrendlineControl.tsx +89 -0
- package/src/controls/UIEventControl.tsx +21 -0
- package/src/controls/index.ts +16 -0
- package/src/controls/radioControl.tsx +88 -0
- package/src/exposing/index.ts +3 -0
- package/src/exposing/setPoint.ts +19 -0
- package/src/geo/vn.geo.json +369897 -0
- package/src/geo/world.geo.json +32127 -0
- package/src/i18n/comps/index.tsx +39 -0
- package/src/i18n/comps/locales/en.ts +558 -0
- package/src/i18n/comps/locales/enObj.tsx +7186 -0
- package/src/i18n/comps/locales/index.ts +7 -0
- package/src/i18n/comps/locales/pt.ts +37 -0
- package/src/i18n/comps/locales/ptObj.tsx +40 -0
- package/src/i18n/comps/locales/types.tsx +622 -0
- package/src/i18n/comps/locales/zh.ts +3 -0
- package/src/i18n/comps/locales/zhObj.tsx +4 -0
- package/src/index.ts +31 -0
- package/src/types/global.d.ts +9 -0
- package/src/types/lowcoder-sdk.d.ts +578 -0
- package/src/utils/chartStyle.util.ts +121 -0
- package/src/utils/columnExtractor.util.ts +41 -0
- package/src/utils/dataTransform.util.ts +37 -0
- package/src/utils/deepEqual.util.ts +29 -0
- package/src/utils/echarts.util.tsx +822 -0
- package/src/utils/getDataKey.util.ts +115 -0
- package/src/utils/getLinearRegression.util.ts +46 -0
- package/src/utils/googleMaps.util.ts +28 -0
- package/src/utils/isEmpty.util.ts +10 -0
- package/src/utils/move.util.ts +6 -0
- package/src/utils/selection.util.ts +73 -0
- package/src/utils/style.util.ts +315 -0
- package/src/utils/time.util.ts +221 -0
- package/src/utils/timeFormatter.util.ts +104 -0
- package/src/utils/timeProcessing.util.ts +38 -0
- package/src/utils/trendline.util.ts +342 -0
- package/tsconfig.json +25 -0
- package/vite.config.js +19 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { JSONObject } from "lowcoder-sdk";
|
|
2
|
+
type DataTypeOption = "number" | "string" | "boolean" | "object" | "array";
|
|
3
|
+
|
|
4
|
+
type DataTypeResult = {
|
|
5
|
+
all: string[];
|
|
6
|
+
number?: string[];
|
|
7
|
+
string?: string[];
|
|
8
|
+
boolean?: string[];
|
|
9
|
+
object?: string[];
|
|
10
|
+
array?: string[];
|
|
11
|
+
};
|
|
12
|
+
export function getDataKeys(args: {
|
|
13
|
+
data: Array<JSONObject>;
|
|
14
|
+
dataType?: DataTypeOption | DataTypeOption[];
|
|
15
|
+
targetKey?: string;
|
|
16
|
+
fallBack?: (keys: Array<string> | DataTypeResult) => void;
|
|
17
|
+
}): Array<string>;
|
|
18
|
+
|
|
19
|
+
export function getDataKeys(args: {
|
|
20
|
+
data: Array<JSONObject>;
|
|
21
|
+
dataType: DataTypeOption[];
|
|
22
|
+
targetKey?: string;
|
|
23
|
+
fallBack?: (keys: Array<string> | DataTypeResult) => void;
|
|
24
|
+
}): DataTypeResult;
|
|
25
|
+
|
|
26
|
+
// Implementation
|
|
27
|
+
export function getDataKeys({
|
|
28
|
+
data,
|
|
29
|
+
dataType,
|
|
30
|
+
targetKey,
|
|
31
|
+
fallBack,
|
|
32
|
+
}: {
|
|
33
|
+
data: Array<JSONObject>;
|
|
34
|
+
dataType?: DataTypeOption | DataTypeOption[];
|
|
35
|
+
targetKey?: string;
|
|
36
|
+
fallBack?: (keys: Array<string> | DataTypeResult) => void;
|
|
37
|
+
}): Array<string> | DataTypeResult {
|
|
38
|
+
if (!data?.length) return [];
|
|
39
|
+
|
|
40
|
+
let sourceData = data;
|
|
41
|
+
if (targetKey) {
|
|
42
|
+
sourceData = data
|
|
43
|
+
.map((d) => d[targetKey])
|
|
44
|
+
.filter((item) => {
|
|
45
|
+
if (Array.isArray(item)) return true;
|
|
46
|
+
return item && typeof item === "object";
|
|
47
|
+
})
|
|
48
|
+
.flatMap((item) =>
|
|
49
|
+
Array.isArray(item) ? item : [item]
|
|
50
|
+
) as Array<JSONObject>;
|
|
51
|
+
|
|
52
|
+
if (!sourceData.length) return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(dataType)) {
|
|
56
|
+
const result: DataTypeResult = { all: [] };
|
|
57
|
+
const allKeys = new Set<string>();
|
|
58
|
+
|
|
59
|
+
sourceData.slice(0, 50).forEach((d) => {
|
|
60
|
+
Object.keys(d).forEach((key) => {
|
|
61
|
+
allKeys.add(key);
|
|
62
|
+
dataType.forEach((type) => {
|
|
63
|
+
if (!result[type]) result[type] = [];
|
|
64
|
+
|
|
65
|
+
const hasMatchingType = sourceData.some((item) => {
|
|
66
|
+
const value = item[key];
|
|
67
|
+
if (type === "array") return Array.isArray(value);
|
|
68
|
+
if (type === "object")
|
|
69
|
+
return (
|
|
70
|
+
typeof value === "object" &&
|
|
71
|
+
!Array.isArray(value) &&
|
|
72
|
+
value !== null
|
|
73
|
+
);
|
|
74
|
+
return typeof value === type;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (hasMatchingType && !result[type]!.includes(key)) {
|
|
78
|
+
result[type]!.push(key);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
result.all = Array.from(allKeys);
|
|
85
|
+
fallBack?.(result);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const dataKeys: Array<string> = [];
|
|
90
|
+
sourceData.slice(0, 50).forEach((d) => {
|
|
91
|
+
Object.keys(d).forEach((key) => {
|
|
92
|
+
if (!dataKeys.includes(key)) {
|
|
93
|
+
if (dataType) {
|
|
94
|
+
const hasMatchingType = sourceData.some((item) => {
|
|
95
|
+
const value = item[key];
|
|
96
|
+
if (dataType === "array") return Array.isArray(value);
|
|
97
|
+
if (dataType === "object")
|
|
98
|
+
return (
|
|
99
|
+
typeof value === "object" &&
|
|
100
|
+
!Array.isArray(value) &&
|
|
101
|
+
value !== null
|
|
102
|
+
);
|
|
103
|
+
return typeof value === dataType;
|
|
104
|
+
});
|
|
105
|
+
if (hasMatchingType) dataKeys.push(key);
|
|
106
|
+
} else {
|
|
107
|
+
dataKeys.push(key);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
fallBack?.(dataKeys);
|
|
114
|
+
return dataKeys;
|
|
115
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export function splitByKey<T extends Record<string, any>>(
|
|
2
|
+
data: T[]
|
|
3
|
+
): { x: any[]; y: any[] } {
|
|
4
|
+
if (data.length === 0) return { x: [], y: [] };
|
|
5
|
+
|
|
6
|
+
const keys = Object.keys(data[0]);
|
|
7
|
+
if (keys.length < 2) throw new Error("Require 2 object");
|
|
8
|
+
|
|
9
|
+
const [xKey, yKey] = keys;
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
x: data.map((item) => item[xKey]),
|
|
13
|
+
y: data.map((item) => item[yKey]),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getLinearRegression(
|
|
18
|
+
xData: number[],
|
|
19
|
+
yData: number[]
|
|
20
|
+
): number[] {
|
|
21
|
+
const n = xData?.length;
|
|
22
|
+
let sumX = 0,
|
|
23
|
+
sumY = 0,
|
|
24
|
+
sumXY = 0,
|
|
25
|
+
sumXX = 0;
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < n; i++) {
|
|
28
|
+
sumX += xData[i];
|
|
29
|
+
sumY += yData[i];
|
|
30
|
+
sumXY += xData[i] * yData[i];
|
|
31
|
+
sumXX += xData[i] * xData[i];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
|
|
35
|
+
const intercept = (sumY - slope * sumX) / n;
|
|
36
|
+
|
|
37
|
+
return xData.map((x) => slope * x + intercept);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getLinearRegressionByData<T extends Record<string, any>>(
|
|
41
|
+
data: T[]
|
|
42
|
+
): number[] {
|
|
43
|
+
const { x, y } = splitByKey(data);
|
|
44
|
+
|
|
45
|
+
return getLinearRegression(x, y);
|
|
46
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { googleMapsApiUrl } from "@/configs/chartUrls";
|
|
2
|
+
|
|
3
|
+
export function loadGoogleMapsScript(apiKey: string) {
|
|
4
|
+
const mapsUrl = `${googleMapsApiUrl}?key=${apiKey}`;
|
|
5
|
+
const scripts = document.getElementsByTagName("script");
|
|
6
|
+
|
|
7
|
+
const existingScript = Array.from(scripts).find(
|
|
8
|
+
(script) =>
|
|
9
|
+
script.src === mapsUrl || script.src.startsWith(googleMapsApiUrl)
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
if (existingScript) {
|
|
13
|
+
if (existingScript.src !== mapsUrl) {
|
|
14
|
+
existingScript.remove();
|
|
15
|
+
} else {
|
|
16
|
+
return existingScript;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const script = document.createElement("script");
|
|
21
|
+
script.type = "text/javascript";
|
|
22
|
+
script.src = mapsUrl;
|
|
23
|
+
script.async = true;
|
|
24
|
+
script.defer = true;
|
|
25
|
+
document.body.appendChild(script);
|
|
26
|
+
|
|
27
|
+
return script;
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const isEmpty = (value: any): boolean => {
|
|
2
|
+
if (value == null) return true;
|
|
3
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
4
|
+
return value.length === 0;
|
|
5
|
+
}
|
|
6
|
+
if (typeof value === "object") {
|
|
7
|
+
return Object.keys(value).length === 0;
|
|
8
|
+
}
|
|
9
|
+
return false;
|
|
10
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface Dataset {
|
|
2
|
+
source: Array<Record<string, any>>;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface Series {
|
|
6
|
+
name: string;
|
|
7
|
+
encode: {
|
|
8
|
+
x?: string;
|
|
9
|
+
y?: string;
|
|
10
|
+
itemName?: string;
|
|
11
|
+
value?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Option {
|
|
16
|
+
series: Series[];
|
|
17
|
+
dataset: Dataset[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SelectInfo {
|
|
21
|
+
seriesIndex: number;
|
|
22
|
+
dataIndex: number[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface Param {
|
|
26
|
+
selected: SelectInfo[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SelectedPoint {
|
|
30
|
+
seriesName: string;
|
|
31
|
+
itemName?: string;
|
|
32
|
+
value?: any;
|
|
33
|
+
x?: any;
|
|
34
|
+
y?: any;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getSelectedPoints(
|
|
38
|
+
param: Param,
|
|
39
|
+
option: Option
|
|
40
|
+
): SelectedPoint[] {
|
|
41
|
+
// Check if required properties exist
|
|
42
|
+
if (
|
|
43
|
+
!option.series ||
|
|
44
|
+
!Array.isArray(option.dataset) ||
|
|
45
|
+
!option.dataset[0]?.source
|
|
46
|
+
) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return param.selected.flatMap((selectInfo: SelectInfo) => {
|
|
51
|
+
const seriesInfo = option.series[selectInfo.seriesIndex];
|
|
52
|
+
if (!seriesInfo?.encode) return [];
|
|
53
|
+
|
|
54
|
+
return selectInfo.dataIndex.map((index: number) => {
|
|
55
|
+
const dataSource = option.dataset[0].source;
|
|
56
|
+
const commonResult = { seriesName: seriesInfo.name };
|
|
57
|
+
|
|
58
|
+
if (seriesInfo.encode.itemName && seriesInfo.encode.value) {
|
|
59
|
+
return {
|
|
60
|
+
...commonResult,
|
|
61
|
+
itemName: dataSource[index][seriesInfo.encode.itemName],
|
|
62
|
+
value: dataSource[index][seriesInfo.encode.value],
|
|
63
|
+
};
|
|
64
|
+
} else {
|
|
65
|
+
return {
|
|
66
|
+
...commonResult,
|
|
67
|
+
x: dataSource[index][seriesInfo.encode.x!],
|
|
68
|
+
y: dataSource[index][seriesInfo.encode.y!],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
interface ColorStop {
|
|
2
|
+
offset: number;
|
|
3
|
+
color: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface RadialGradient {
|
|
7
|
+
type: "radial";
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
r: number;
|
|
11
|
+
colorStops: ColorStop[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface LinearGradient {
|
|
15
|
+
type: "linear";
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
x2: number;
|
|
19
|
+
y2: number;
|
|
20
|
+
colorStops: ColorStop[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type Gradient = RadialGradient | LinearGradient;
|
|
24
|
+
|
|
25
|
+
interface StyleContainer {
|
|
26
|
+
fontFamily?: string;
|
|
27
|
+
textSize?: number;
|
|
28
|
+
textWeight?: string;
|
|
29
|
+
textColor?: string;
|
|
30
|
+
fontStyle?: string;
|
|
31
|
+
shadowColor?: string;
|
|
32
|
+
boxShadow?: string;
|
|
33
|
+
borderColor?: string;
|
|
34
|
+
borderWidth?: number;
|
|
35
|
+
borderStyle?: string;
|
|
36
|
+
borderRadius?: number;
|
|
37
|
+
backgroundColor?: string;
|
|
38
|
+
detailSize?: string;
|
|
39
|
+
padding?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface ThemeContainer {
|
|
43
|
+
fontFamily?: string;
|
|
44
|
+
textSize?: number;
|
|
45
|
+
fontWeight?: string;
|
|
46
|
+
fontColor?: string;
|
|
47
|
+
fontStyle?: string;
|
|
48
|
+
shadowColor?: string;
|
|
49
|
+
boxShadow?: string;
|
|
50
|
+
borderColor?: string;
|
|
51
|
+
borderWidth?: number;
|
|
52
|
+
borderType?: string;
|
|
53
|
+
borderRadius?: number;
|
|
54
|
+
backgroundColor?: string;
|
|
55
|
+
detailSize?: string;
|
|
56
|
+
padding?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface StyleWrapperResult {
|
|
60
|
+
fontFamily: string;
|
|
61
|
+
textSize: number;
|
|
62
|
+
fontWeight?: string;
|
|
63
|
+
color: string;
|
|
64
|
+
fontStyle?: string;
|
|
65
|
+
textShadowColor?: string;
|
|
66
|
+
textShadowBlur?: number;
|
|
67
|
+
textShadowOffsetX?: number;
|
|
68
|
+
textShadowOffsetY?: number;
|
|
69
|
+
borderColor: string;
|
|
70
|
+
borderWidth: number;
|
|
71
|
+
borderType?: string;
|
|
72
|
+
borderRadius: number;
|
|
73
|
+
backgroundColor: string | Gradient;
|
|
74
|
+
width?: number;
|
|
75
|
+
height?: number;
|
|
76
|
+
padding: number[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface ChartStyleWrapperResult {
|
|
80
|
+
shadowColor?: string;
|
|
81
|
+
shadowBlur?: number;
|
|
82
|
+
shadowOffsetX?: number;
|
|
83
|
+
shadowOffsetY?: number;
|
|
84
|
+
borderColor: string;
|
|
85
|
+
borderWidth: number;
|
|
86
|
+
borderType?: string;
|
|
87
|
+
borderRadius: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parses a radial-gradient CSS string into an ECharts-compatible object.
|
|
92
|
+
*/
|
|
93
|
+
function parseRadialGradient(gradient: string): RadialGradient {
|
|
94
|
+
const radialGradientRegex = /radial-gradient\(([^,]+),\s*(.+)\)/;
|
|
95
|
+
const match = gradient.match(radialGradientRegex);
|
|
96
|
+
|
|
97
|
+
if (!match) {
|
|
98
|
+
throw new Error("Invalid radial-gradient format");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const shape = match[1].trim();
|
|
102
|
+
const colorStops = parseColorStops(match[2]);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
type: "radial",
|
|
106
|
+
x: 0.5,
|
|
107
|
+
y: 0.5,
|
|
108
|
+
r: 0.8,
|
|
109
|
+
colorStops,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Parses color stops from a gradient string into an array of objects.
|
|
115
|
+
*/
|
|
116
|
+
function parseColorStops(colorStopsString: string): ColorStop[] {
|
|
117
|
+
const colorStopRegex =
|
|
118
|
+
/((?:rgba?|hsla?)\([^)]+\)|#[0-9a-fA-F]{3,8}|[a-zA-Z]+)\s+([\d.]+%)/g;
|
|
119
|
+
const colorStops: ColorStop[] = [];
|
|
120
|
+
let match: RegExpExecArray | null;
|
|
121
|
+
|
|
122
|
+
while (
|
|
123
|
+
(match = colorStopRegex.exec(colorStopsString.toLowerCase())) !== null
|
|
124
|
+
) {
|
|
125
|
+
const color = match[1].trim().toLowerCase();
|
|
126
|
+
const offset = parseFloat(match[2]) / 100;
|
|
127
|
+
colorStops.push({ offset, color });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return colorStops;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Parses a linear-gradient CSS string into an ECharts-compatible object.
|
|
135
|
+
*/
|
|
136
|
+
function parseLinearGradient(gradient: string): LinearGradient {
|
|
137
|
+
const linearGradientRegex = /linear-gradient\((\d+deg),\s*(.+)\)/;
|
|
138
|
+
const match = gradient.match(linearGradientRegex);
|
|
139
|
+
|
|
140
|
+
if (!match) {
|
|
141
|
+
throw new Error("Invalid linear-gradient format");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const angle = parseFloat(match[1]);
|
|
145
|
+
const colorStops = parseColorStops(match[2]);
|
|
146
|
+
|
|
147
|
+
const x2 = Math.sin((angle * Math.PI) / 180);
|
|
148
|
+
const y = Math.cos((angle * Math.PI) / 180);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
type: "linear",
|
|
152
|
+
x: 0,
|
|
153
|
+
y: 0,
|
|
154
|
+
x2,
|
|
155
|
+
y2: y,
|
|
156
|
+
colorStops,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Parses background value (gradient or solid color) into ECharts-compatible format.
|
|
162
|
+
*/
|
|
163
|
+
function parseBackground(background: string): string | Gradient {
|
|
164
|
+
if (background.startsWith("linear-gradient")) {
|
|
165
|
+
return parseLinearGradient(background);
|
|
166
|
+
} else if (background.startsWith("radial-gradient")) {
|
|
167
|
+
return parseRadialGradient(background);
|
|
168
|
+
} else {
|
|
169
|
+
return background;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Wraps style properties with fallbacks to theme and default values.
|
|
175
|
+
*/
|
|
176
|
+
function styleWrapper(
|
|
177
|
+
styleContainer: StyleContainer | undefined,
|
|
178
|
+
themeContainer: ThemeContainer | undefined,
|
|
179
|
+
defaultFontSize: number = 18,
|
|
180
|
+
defaultFontColor: string = "#000000",
|
|
181
|
+
detailBorderWidth: number = 0,
|
|
182
|
+
defaultBackgroundColor: string = ""
|
|
183
|
+
): StyleWrapperResult {
|
|
184
|
+
const parseSize = (sizeString?: string): number | undefined => {
|
|
185
|
+
if (!sizeString) return undefined;
|
|
186
|
+
const match = sizeString.match(/(\d+)px/);
|
|
187
|
+
return match ? parseInt(match[1], 10) : undefined;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const parseBoxShadow = (
|
|
191
|
+
boxShadow?: string
|
|
192
|
+
): { blur?: number; offsetX?: number; offsetY?: number } => {
|
|
193
|
+
if (!boxShadow) return {};
|
|
194
|
+
|
|
195
|
+
const parts = boxShadow.split("px").filter((part) => part.trim() !== "");
|
|
196
|
+
return {
|
|
197
|
+
blur: parts[0] ? parseInt(parts[0], 10) : undefined,
|
|
198
|
+
offsetX: parts[1] ? parseInt(parts[1], 10) : undefined,
|
|
199
|
+
offsetY: parts[2] ? parseInt(parts[2], 10) : undefined,
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const parsePadding = (padding?: string): number[] => {
|
|
204
|
+
if (!padding) return [0, 0, 0, 0];
|
|
205
|
+
|
|
206
|
+
const parts = padding
|
|
207
|
+
.split("px")
|
|
208
|
+
.map((part) => part.trim())
|
|
209
|
+
.filter((part) => part !== "")
|
|
210
|
+
.map((part) => parseInt(part, 10));
|
|
211
|
+
|
|
212
|
+
return parts.length === 0 ? [0, 0, 0, 0] : parts;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const boxShadowStyle = parseBoxShadow(styleContainer?.boxShadow);
|
|
216
|
+
const boxShadowTheme = parseBoxShadow(themeContainer?.boxShadow);
|
|
217
|
+
|
|
218
|
+
const backgroundColor =
|
|
219
|
+
styleContainer?.backgroundColor ||
|
|
220
|
+
themeContainer?.backgroundColor ||
|
|
221
|
+
defaultBackgroundColor;
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
fontFamily:
|
|
225
|
+
styleContainer?.fontFamily ||
|
|
226
|
+
themeContainer?.fontFamily ||
|
|
227
|
+
"Arial, sans-serif",
|
|
228
|
+
textSize:
|
|
229
|
+
styleContainer?.textSize || themeContainer?.textSize || defaultFontSize,
|
|
230
|
+
fontWeight: styleContainer?.textWeight || themeContainer?.fontWeight,
|
|
231
|
+
color:
|
|
232
|
+
styleContainer?.textColor ||
|
|
233
|
+
themeContainer?.fontColor ||
|
|
234
|
+
defaultFontColor,
|
|
235
|
+
fontStyle: styleContainer?.fontStyle || themeContainer?.fontStyle,
|
|
236
|
+
textShadowColor: styleContainer?.shadowColor || themeContainer?.shadowColor,
|
|
237
|
+
textShadowBlur: boxShadowStyle.blur || boxShadowTheme.blur,
|
|
238
|
+
textShadowOffsetX: boxShadowStyle.offsetX || boxShadowTheme.offsetX,
|
|
239
|
+
textShadowOffsetY: boxShadowStyle.offsetY || boxShadowTheme.offsetY,
|
|
240
|
+
borderColor:
|
|
241
|
+
styleContainer?.borderColor || themeContainer?.borderColor || "inherit",
|
|
242
|
+
borderWidth:
|
|
243
|
+
styleContainer?.borderWidth ||
|
|
244
|
+
themeContainer?.borderWidth ||
|
|
245
|
+
detailBorderWidth,
|
|
246
|
+
borderType: styleContainer?.borderStyle || themeContainer?.borderType,
|
|
247
|
+
borderRadius: Number(
|
|
248
|
+
styleContainer?.borderRadius || themeContainer?.borderRadius || 0
|
|
249
|
+
),
|
|
250
|
+
backgroundColor: backgroundColor.startsWith("gradient")
|
|
251
|
+
? parseBackground(backgroundColor)
|
|
252
|
+
: backgroundColor,
|
|
253
|
+
width:
|
|
254
|
+
parseSize(styleContainer?.detailSize) ||
|
|
255
|
+
parseSize(themeContainer?.detailSize),
|
|
256
|
+
height:
|
|
257
|
+
parseSize(styleContainer?.detailSize) ||
|
|
258
|
+
parseSize(themeContainer?.detailSize),
|
|
259
|
+
padding:
|
|
260
|
+
parsePadding(styleContainer?.padding) ||
|
|
261
|
+
parsePadding(themeContainer?.padding),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Wraps chart-specific style properties.
|
|
267
|
+
*/
|
|
268
|
+
function chartStyleWrapper(
|
|
269
|
+
styleContainer: StyleContainer | undefined,
|
|
270
|
+
themeContainer: ThemeContainer | undefined,
|
|
271
|
+
detailBorderWidth: number = 0
|
|
272
|
+
): ChartStyleWrapperResult {
|
|
273
|
+
const parseBoxShadow = (
|
|
274
|
+
boxShadow?: string
|
|
275
|
+
): { blur?: number; offsetX?: number; offsetY?: number } => {
|
|
276
|
+
if (!boxShadow) return {};
|
|
277
|
+
|
|
278
|
+
const parts = boxShadow.split("px").filter((part) => part.trim() !== "");
|
|
279
|
+
return {
|
|
280
|
+
blur: parts[0] ? parseInt(parts[0], 10) : undefined,
|
|
281
|
+
offsetX: parts[1] ? parseInt(parts[1], 10) : undefined,
|
|
282
|
+
offsetY: parts[2] ? parseInt(parts[2], 10) : undefined,
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const boxShadowStyle = parseBoxShadow(styleContainer?.boxShadow);
|
|
287
|
+
const boxShadowTheme = parseBoxShadow(themeContainer?.boxShadow);
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
shadowColor: styleContainer?.shadowColor || themeContainer?.shadowColor,
|
|
291
|
+
shadowBlur: boxShadowStyle.blur || boxShadowTheme.blur,
|
|
292
|
+
shadowOffsetX: boxShadowStyle.offsetX || boxShadowTheme.offsetX,
|
|
293
|
+
shadowOffsetY: boxShadowStyle.offsetY || boxShadowTheme.offsetY,
|
|
294
|
+
borderColor:
|
|
295
|
+
styleContainer?.borderColor || themeContainer?.borderColor || "inherit",
|
|
296
|
+
borderWidth:
|
|
297
|
+
styleContainer?.borderWidth ||
|
|
298
|
+
themeContainer?.borderWidth ||
|
|
299
|
+
detailBorderWidth,
|
|
300
|
+
borderType: styleContainer?.borderStyle || themeContainer?.borderType,
|
|
301
|
+
borderRadius: Number(
|
|
302
|
+
styleContainer?.borderRadius || themeContainer?.borderRadius || 0
|
|
303
|
+
),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { chartStyleWrapper, parseBackground, styleWrapper };
|
|
308
|
+
export type {
|
|
309
|
+
ChartStyleWrapperResult,
|
|
310
|
+
ColorStop,
|
|
311
|
+
Gradient,
|
|
312
|
+
StyleContainer,
|
|
313
|
+
StyleWrapperResult,
|
|
314
|
+
ThemeContainer,
|
|
315
|
+
};
|