feat: 新增饼图/雷达图图表类型

- 单图模式图表类型新增:饼图(环形占比,第一列=名称/第一系列=数值)、雷达图(多维度对比,第一列=维度/每系列=多边形)
- 多图合并的每张图也可选饼图/雷达图
- 后端 /api/chart 与 /api/combine 的 chartType 支持 pie/radar
- 饼图/雷达图自动隐藏坐标轴/网格/双轴等不适用配置
This commit is contained in:
2026-08-19 17:12:18 +08:00
parent d7c7c08407
commit 7a03ecc063
5 changed files with 231 additions and 6 deletions
+69 -3
View File
@@ -130,6 +130,72 @@ function buildChartOption(params) {
const textColor = theme === 'dark' ? '#e0e0e0' : '#333333';
const axisLineColor = theme === 'dark' ? '#444' : '#ddd';
// 饼图/雷达图:专用构建逻辑(无坐标轴/网格)
if (chartType === 'pie' || chartType === 'radar') {
const bgC = theme === 'dark' ? '#1a1a2e' : '#ffffff';
const txtC = theme === 'dark' ? '#e0e0e0' : '#333333';
const tTitle = title ? { text: title, left: 'center', top: 15, textStyle: { color: txtC, fontSize: 18, fontWeight: 600 } } : undefined;
if (chartType === 'pie') {
// 饼图:第一列=名称,第一个系列=数值
const sName = parsedData.seriesNames[0];
const data = parsedData.seriesData[sName];
const pieData = parsedData.categories.map((c, i) => ({ name: c, value: data[i] || 0 }));
return {
backgroundColor: bgC,
title: tTitle,
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
legend: showLegend ? { orient: 'vertical', left: 'left', top: title ? 50 : 20, textStyle: { color: txtC, fontSize: 12 } } : { show: false },
color: seriesColorsArr,
series: [{
type: 'pie',
radius: ['38%', '68%'],
center: ['52%', '55%'],
itemStyle: { borderRadius: 6, borderColor: bgC, borderWidth: 2 },
label: { show: showLabel, formatter: '{b}: {d}%', color: txtC },
labelLine: { show: showLabel },
data: pieData
}],
animation: false
};
} else {
// 雷达图:第一列=维度名,每个系列=一个雷达多边形
const indicator = parsedData.categories.map(c => {
let max = 0;
parsedData.seriesNames.forEach(n => { parsedData.seriesData[n].forEach(v => { if (v > max) max = v; }); });
return { name: c, max: Math.ceil(max * 1.2) || 100 };
});
return {
backgroundColor: bgC,
title: tTitle,
tooltip: { trigger: 'item' },
legend: showLegend ? { orient: 'horizontal', left: 'center', top: title ? 48 : 15, textStyle: { color: txtC, fontSize: 12 } } : { show: false },
color: seriesColorsArr,
radar: {
indicator,
radius: '62%',
center: ['50%', '55%'],
splitNumber: 5,
axisName: { color: txtC, fontSize: 12 },
splitLine: { lineStyle: { color: theme === 'dark' ? '#444' : '#ddd' } },
splitArea: {
areaStyle: {
color: theme === 'dark' ? ['rgba(79,195,247,0.03)', 'rgba(79,195,247,0.06)'] : ['rgba(79,70,229,0.03)', 'rgba(79,70,229,0.06)']
}
},
axisLine: { lineStyle: { color: theme === 'dark' ? '#444' : '#ddd' } }
},
series: parsedData.seriesNames.map(n => ({
type: 'radar',
name: n,
data: [{ value: parsedData.seriesData[n], name: n }],
symbolSize: 4,
areaStyle: { opacity: 0.15 }
})),
animation: false
};
}
}
// 构建系列
const series = parsedData.seriesNames.map((name, idx) => {
const dataArr = parsedData.seriesData[name];
@@ -928,7 +994,7 @@ app.get('/api/health', (req, res) => {
res.json({
status: 'ok',
service: 'data-chart-tool',
version: '1.13.1',
version: '1.14.0',
endpoints: {
'POST /api/chart': '生成图表图片(JSON body',
'GET /api/chart': '生成图表图片(URL 参数)',
@@ -943,7 +1009,7 @@ app.get('/api/health', (req, res) => {
app.get('/api/docs', (req, res) => {
res.json({
name: '数据可视化图表生成器 API',
version: '1.13.1',
version: '1.14.0',
endpoints: [
{
method: 'POST',
@@ -952,7 +1018,7 @@ app.get('/api/docs', (req, res) => {
'Content-Type': 'application/json',
params: {
data: { type: 'string', required: true, description: 'CSV 格式数据(第一行表头,第一列横坐标)' },
chartType: { type: 'string', default: 'bar', options: ['bar', 'line', 'bar-line'], description: '图表类型' },
chartType: { type: 'string', default: 'bar', options: ['bar', 'line', 'bar-line', 'pie', 'radar'], description: '图表类型' },
title: { type: 'string', default: '', description: '图表标题' },
theme: { type: 'string', default: 'default', options: ['default', 'dark', 'macarons', 'gradient', 'retro', 'ocean', 'forest', 'sunset', 'lavender', 'minimal', 'cherry', 'midnight', 'gold', 'coral', 'mint'], description: '主题风格' },
showLegend: { type: 'boolean', default: true, description: '是否显示图例' },