Commit 937af939 authored by 水玉婷's avatar 水玉婷
Browse files

feat:数据过多时优化折线图,柱图,饼图,表格配置

parent 12b90ac5
......@@ -81,7 +81,7 @@
<div class="chart-render-area">
<!-- 表格渲染 -->
<div v-if="selectedChartType === CHART_TYPES.TABLE" class="table-render">
<div v-html="tableHtml" class="message-table"></div>
<div v-html="tableHtml" class="message-chart"></div>
</div>
<!-- 柱状图渲染 -->
......
......@@ -140,19 +140,29 @@ const formatData = (data: any) => {
/**
* 基础图表配置
*/
const getBaseChartConfig = () => ({
responsive: true,
animation: true,
animationDuration: 500,
animationEasing: 'cubicOut' as const,
grid: {
left: '3%',
right: '3%',
bottom: '3%',
top: '70px', // 增加顶部间距,为legend留出更多空间
containLabel: true
const getBaseChartConfig = (xAxisDataLength: number) => {
// 根据数据量动态调整底部边距,为dataZoom留出空间
let bottomMargin = '3%';
if (xAxisDataLength > 15) {
bottomMargin = '8%'; // 数据项多时增加底部边距
} else if (xAxisDataLength > 10) {
bottomMargin = '5%';
}
});
return {
responsive: true,
animation: true,
animationDuration: 500,
animationEasing: 'cubicOut' as const,
grid: {
left: '3%',
right: '3%',
bottom: bottomMargin,
top: '70px', // 增加顶部间距,为legend留出更多空间
containLabel: true
}
};
};
/**
* 基础legend配置 - 始终放在顶部,与折线图保持一致
......@@ -245,16 +255,74 @@ const getBaseTooltipConfig = () => ({
/**
* 基础x轴配置
*/
const getXAxisConfig = (xAxisData: string[]) => ({
type: 'category' as const,
data: xAxisData,
axisLabel: {
interval: 0,
rotate: xAxisData.length > 6 ? 45 : 0,
margin: 8,
fontSize: 14
const getXAxisConfig = (xAxisData: string[]) => {
// 根据数据量智能设置标签配置
const dataLength = xAxisData.length;
let rotate = 0;
let margin = 12;
let fontSize = 14;
let interval = 0;
if (dataLength > 20) {
// 数据项非常多时,旋转45度,增加间距
rotate = 45;
margin = 15;
fontSize = 12;
interval = 1; // 每2个显示一个标签(每隔一个显示)
} else if (dataLength > 12) {
// 数据项较多时,旋转30度
rotate = 30;
margin = 12;
fontSize = 13;
interval = 1; // 每2个显示一个标签
} else if (dataLength > 6) {
// 数据项适中时,旋转15度
rotate = 15;
margin = 10;
interval = 1; // 每2个显示一个标签
} else {
// 数据项较少时,显示所有标签
interval = 0;
}
});
return {
type: 'category' as const,
data: xAxisData,
axisLabel: {
interval: interval,
rotate: rotate,
margin: margin,
fontSize: fontSize,
color: '#666',
fontWeight: 'normal',
align: rotate > 0 ? 'right' : 'center',
verticalAlign: rotate > 0 ? 'middle' : 'top',
overflow: 'truncate',
width: rotate > 0 ? 80 : null,
lineHeight: 16
},
axisTick: {
show: true,
alignWithLabel: true,
length: 4,
lineStyle: {
color: '#ccc',
width: 1
}
},
axisLine: {
show: true,
lineStyle: {
color: '#d9d9d9',
width: 1
}
},
splitLine: {
show: false
}
};
};
/**
* 基础y轴配置
......@@ -316,6 +384,105 @@ const getDualYAxisConfig = (yFields: string[]) => [
}
];
/**
* dataZoom配置
*/
const getDataZoomConfig = (xAxisDataLength: number) => {
// 当数据项超过15个时启用dataZoom
if (xAxisDataLength <= 15) {
return [];
}
// 根据数据量智能设置初始显示范围
let start = 0;
let end = 100;
if (xAxisDataLength > 30) {
// 数据项非常多时,显示约1/3的数据
start = 65;
end = 85;
} else if (xAxisDataLength > 20) {
// 数据项较多时,显示约一半的数据
start = 50;
end = 75;
} else {
// 数据项适中时,显示大部分数据
start = 30;
end = 80;
}
return [
{
show: true,
type: 'slider' as const,
realtime: true,
start: start,
end: end,
height: 25,
bottom: 5,
backgroundColor: '#f5f5f5',
dataBackground: {
lineStyle: {
color: '#ccc'
},
areaStyle: {
color: '#e8e8e8'
}
},
selectedDataBackground: {
lineStyle: {
color: '#1890ff'
},
areaStyle: {
color: '#e6f7ff'
}
},
borderColor: '#d9d9d9',
fillerColor: 'rgba(24, 144, 255, 0.2)',
handleStyle: {
color: '#1890ff',
borderColor: '#1890ff',
borderWidth: 1,
shadowBlur: 2,
shadowColor: 'rgba(0,0,0,0.1)'
},
handleSize: 12,
brushSelect: false,
showDetail: true,
showDataShadow: 'auto',
emphasis: {
handleStyle: {
color: '#096dd9',
borderColor: '#096dd9'
}
},
textStyle: {
fontSize: 11,
color: '#666'
},
alwaysShowContent: true,
label: {
show: true,
position: 'top',
formatter: '{c}%'
},
detailFormatter: (value: number) => {
return `${value}%`;
}
},
{
type: 'inside' as const,
realtime: true,
start: start,
end: end,
zoomOnMouseWheel: 'shift' as const,
moveOnMouseWheel: true,
moveOnMouseMove: true,
preventDefaultMouseMove: true
}
];
};
/**
* 基础系列配置
*/
......@@ -351,27 +518,29 @@ const createSingleColumnOption = (chartConfig: any): echarts.EChartsOption => {
});
return {
...getBaseChartConfig(),
...getBaseChartConfig(xAxisData.length),
tooltip: {
...getBaseTooltipConfig()
},
legend: getBaseLegendConfig(groups),
xAxis: getXAxisConfig(xAxisData),
yAxis: getYAxisConfig(),
series
series,
dataZoom: getDataZoomConfig(xAxisData.length)
};
} else {
const seriesData = chartConfig.data.map((item: any) => item[chartConfig.yField]);
return {
...getBaseChartConfig(),
...getBaseChartConfig(xAxisData.length),
tooltip: {
...getBaseTooltipConfig()
},
legend: { show: false },
xAxis: getXAxisConfig(xAxisData),
yAxis: getYAxisConfig(),
series: [getBaseSeriesConfig(chartConfig.yField, seriesData, colors[0], 0, xAxisData.length)]
series: [getBaseSeriesConfig(chartConfig.yField, seriesData, colors[0], 0, xAxisData.length)],
dataZoom: getDataZoomConfig(xAxisData.length)
};
}
};
......@@ -403,21 +572,22 @@ const createDualColumnOption = (chartConfig: any): echarts.EChartsOption => {
});
return {
...getBaseChartConfig(),
...getBaseChartConfig(xAxisData.length),
tooltip: {
...getBaseTooltipConfig()
},
legend: getBaseLegendConfig([...series1, ...series2].map(s => s.name)),
xAxis: getXAxisConfig(xAxisData),
yAxis: getDualYAxisConfig(chartConfig.yFields),
series: [...series1, ...series2]
series: [...series1, ...series2],
dataZoom: getDataZoomConfig(xAxisData.length)
};
} else {
const series1Data = chartConfig.data.map((item: any) => item[chartConfig.yFields[0]]);
const series2Data = chartConfig.data.map((item: any) => item[chartConfig.yFields[1]]);
return {
...getBaseChartConfig(),
...getBaseChartConfig(xAxisData.length),
tooltip: {
...getBaseTooltipConfig()
},
......@@ -427,7 +597,8 @@ const createDualColumnOption = (chartConfig: any): echarts.EChartsOption => {
series: [
getBaseSeriesConfig(chartConfig.yFields[0], series1Data, colors[0], 0, xAxisData.length),
getBaseSeriesConfig(chartConfig.yFields[1], series2Data, colors[1], 1, xAxisData.length)
]
],
dataZoom: getDataZoomConfig(xAxisData.length)
};
}
};
......
......@@ -140,20 +140,29 @@ const formatData = (data: any) => {
/**
* 基础图表配置
*/
const getBaseChartConfig = () => ({
responsive: true,
animation: true,
animationDuration: 500,
animationEasing: 'cubicOut' as const,
grid: {
left: '2%',
right: '2%',
bottom: '3%',
top: '70px', // 增加顶部间距,为legend留出更多空间
containLabel: true
const getBaseChartConfig = (xAxisDataLength: number) => {
// 根据数据量动态调整底部边距,为dataZoom留出空间
let bottomMargin = '3%';
if (xAxisDataLength > 15) {
bottomMargin = '8%'; // 数据项多时增加底部边距
} else if (xAxisDataLength > 10) {
bottomMargin = '5%';
}
});
return {
responsive: true,
animation: true,
animationDuration: 500,
animationEasing: 'cubicOut' as const,
grid: {
left: '3%',
right: '3%',
bottom: bottomMargin,
top: '70px', // 增加顶部间距,为legend留出更多空间
containLabel: true
}
};
};
/**
* 基础legend配置 - 始终放在顶部
*/
......@@ -245,16 +254,74 @@ const getBaseTooltipConfig = () => ({
/**
* 基础x轴配置
*/
const getXAxisConfig = (xAxisData: string[]) => ({
type: 'category' as const,
data: xAxisData,
axisLabel: {
interval: 0,
rotate: xAxisData.length > 6 ? 45 : 0,
margin: 8,
fontSize: 14
const getXAxisConfig = (xAxisData: string[]) => {
// 根据数据量智能设置标签配置
const dataLength = xAxisData.length;
let rotate = 0;
let margin = 12;
let fontSize = 14;
let interval = 0;
if (dataLength > 20) {
// 数据项非常多时,旋转45度,增加间距
rotate = 45;
margin = 15;
fontSize = 12;
interval = 1; // 每2个显示一个标签(每隔一个显示)
} else if (dataLength > 12) {
// 数据项较多时,旋转30度
rotate = 30;
margin = 12;
fontSize = 13;
interval = 1; // 每2个显示一个标签
} else if (dataLength > 6) {
// 数据项适中时,旋转15度
rotate = 15;
margin = 10;
interval = 1; // 每2个显示一个标签
} else {
// 数据项较少时,显示所有标签
interval = 0;
}
});
return {
type: 'category' as const,
data: xAxisData,
axisLabel: {
interval: interval,
rotate: rotate,
margin: margin,
fontSize: fontSize,
color: '#666',
fontWeight: 'normal',
align: rotate > 0 ? 'right' : 'center',
verticalAlign: rotate > 0 ? 'middle' : 'top',
overflow: 'truncate',
width: rotate > 0 ? 80 : null,
lineHeight: 16
},
axisTick: {
show: true,
alignWithLabel: true,
length: 4,
lineStyle: {
color: '#ccc',
width: 1
}
},
axisLine: {
show: true,
lineStyle: {
color: '#d9d9d9',
width: 1
}
},
splitLine: {
show: false
}
};
};
/**
* 基础y轴配置
......@@ -316,6 +383,105 @@ const getDualYAxisConfig = (yFields: string[]) => [
}
];
/**
* dataZoom配置
*/
const getDataZoomConfig = (xAxisDataLength: number) => {
// 当数据项超过15个时启用dataZoom
if (xAxisDataLength <= 15) {
return [];
}
// 根据数据量智能设置初始显示范围
let start = 0;
let end = 100;
if (xAxisDataLength > 30) {
// 数据项非常多时,显示约1/3的数据
start = 65;
end = 85;
} else if (xAxisDataLength > 20) {
// 数据项较多时,显示约一半的数据
start = 50;
end = 75;
} else {
// 数据项适中时,显示大部分数据
start = 30;
end = 80;
}
return [
{
show: true,
type: 'slider' as const,
realtime: true,
start: start,
end: end,
height: 25,
bottom: 5,
backgroundColor: '#f5f5f5',
dataBackground: {
lineStyle: {
color: '#ccc'
},
areaStyle: {
color: '#e8e8e8'
}
},
selectedDataBackground: {
lineStyle: {
color: '#1890ff'
},
areaStyle: {
color: '#e6f7ff'
}
},
borderColor: '#d9d9d9',
fillerColor: 'rgba(24, 144, 255, 0.2)',
handleStyle: {
color: '#1890ff',
borderColor: '#1890ff',
borderWidth: 1,
shadowBlur: 2,
shadowColor: 'rgba(0,0,0,0.1)'
},
handleSize: 12,
brushSelect: false,
showDetail: true,
showDataShadow: 'auto',
emphasis: {
handleStyle: {
color: '#096dd9',
borderColor: '#096dd9'
}
},
textStyle: {
fontSize: 11,
color: '#666'
},
alwaysShowContent: true,
label: {
show: true,
position: 'top',
formatter: '{c}%'
},
detailFormatter: (value: number) => {
return `${value}%`;
}
},
{
type: 'inside' as const,
realtime: true,
start: start,
end: end,
zoomOnMouseWheel: 'shift' as const,
moveOnMouseWheel: true,
moveOnMouseMove: true,
preventDefaultMouseMove: true
}
];
};
/**
* 基础系列配置 - 折线图专用
*/
......@@ -364,7 +530,8 @@ const createSingleLineOption = (chartConfig: any): echarts.EChartsOption => {
legend: getBaseLegendConfig(groups),
xAxis: getXAxisConfig(xAxisData),
yAxis: getYAxisConfig(),
series
series,
dataZoom: getDataZoomConfig(xAxisData.length)
};
} else {
const seriesData = chartConfig.data.map((item: any) => item[chartConfig.yField]);
......@@ -375,7 +542,8 @@ const createSingleLineOption = (chartConfig: any): echarts.EChartsOption => {
legend: { show: false },
xAxis: getXAxisConfig(xAxisData),
yAxis: getYAxisConfig(),
series: [getBaseSeriesConfig(chartConfig.yField, seriesData, colors[0])]
series: [getBaseSeriesConfig(chartConfig.yField, seriesData, colors[0])],
dataZoom: getDataZoomConfig(xAxisData.length)
};
}
};
......@@ -414,7 +582,8 @@ const createDualLineOption = (chartConfig: any): echarts.EChartsOption => {
legend: getBaseLegendConfig(legendData),
xAxis: getXAxisConfig(xAxisData),
yAxis: getDualYAxisConfig(chartConfig.yFields),
series: [...series1, ...series2]
series: [...series1, ...series2],
dataZoom: getDataZoomConfig(xAxisData.length)
};
} else {
const series1Data = chartConfig.data.map((item: any) => item[chartConfig.yFields[0]]);
......@@ -429,7 +598,8 @@ const createDualLineOption = (chartConfig: any): echarts.EChartsOption => {
series: [
getBaseSeriesConfig(chartConfig.yFields[0], series1Data, colors[0], 0),
getBaseSeriesConfig(chartConfig.yFields[1], series2Data, colors[1], 1)
]
],
dataZoom: getDataZoomConfig(xAxisData.length)
};
}
};
......
......@@ -368,23 +368,23 @@ const getResponsiveLayout = (isManyItems: boolean) => {
if (screenWidth < 768) { // 小屏幕
return {
top: isManyItems ? '15%' : '10%',
top: isManyItems ? '5%' : '10%',
left: '5%',
right: '5%',
radius: isManyItems ? ['25%', '50%'] : ['35%', '60%']
radius: isManyItems ? ['35%', '80%'] : ['35%', '80%']
};
} else if (screenWidth < 1200) { // 中等屏幕
return {
top: isManyItems ? '15%' : '10%',
top: isManyItems ? '5%' : '10%',
left: '25%',
right: '25%',
radius: isManyItems ? ['30%', '55%'] : ['40%', '65%']
radius: isManyItems ? ['35%', '80%'] : ['40%', '80%']
};
} else { // 大屏幕
return {
left: '30%',
right: '30%',
radius: isManyItems ? ['35%', '60%'] : ['45%', '70%']
radius: isManyItems ? ['35%', '80%'] : ['45%', '80%']
};
}
};
......
......@@ -876,7 +876,13 @@ li {
}
.table-title {
font-size: 14px;
font-size: 16px;
font-weight: bold;
margin-bottom: 8px;
color: #333;
width: 100%;
box-sizing: border-box;
text-align: center;
}
.table-summary {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment