195 lines
5.4 KiB
React
195 lines
5.4 KiB
React
|
|
import { useRef, useEffect } from "react";
|
|||
|
|
import * as echarts from "echarts";
|
|||
|
|
|
|||
|
|
export default function RadarChart({
|
|||
|
|
data = [5, 8, 5, 8],
|
|||
|
|
value = null,
|
|||
|
|
indicator = [
|
|||
|
|
{ name: "Sales", max: 6500 },
|
|||
|
|
{ name: "Administration", max: 16000 },
|
|||
|
|
{ name: "Information Technology", max: 30000 },
|
|||
|
|
{ name: "Marketing", max: 25000 },
|
|||
|
|
],
|
|||
|
|
className = "",
|
|||
|
|
lineClolr = "#DCDFFF",
|
|||
|
|
areaColor = "#CCCDFC",
|
|||
|
|
areaBorderColor = "#BDB5FF",
|
|||
|
|
isGreenTheme = false, // 新增参数:是否使用绿色主题
|
|||
|
|
}) {
|
|||
|
|
const chartRef = useRef(null);
|
|||
|
|
const chartInstance = useRef(null);
|
|||
|
|
|
|||
|
|
// 获取实际数据值
|
|||
|
|
const actualData = value || data;
|
|||
|
|
|
|||
|
|
// 创建渐变色配置
|
|||
|
|
const gradientColor = isGreenTheme ? {
|
|||
|
|
type: 'radial',
|
|||
|
|
x: 0.5,
|
|||
|
|
y: 0.5,
|
|||
|
|
r: 0.5,
|
|||
|
|
colorStops: [{
|
|||
|
|
offset: 0,
|
|||
|
|
color: 'rgba(34, 197, 94, 0.3)' // 绿色中心
|
|||
|
|
}, {
|
|||
|
|
offset: 1,
|
|||
|
|
color: 'rgba(34, 197, 94, 0.8)' // 绿色边缘
|
|||
|
|
}]
|
|||
|
|
} : {
|
|||
|
|
type: 'radial',
|
|||
|
|
x: 0.5,
|
|||
|
|
y: 0.5,
|
|||
|
|
r: 0.5,
|
|||
|
|
colorStops: [{
|
|||
|
|
offset: 0,
|
|||
|
|
color: 'rgba(189, 181, 255, 0.3)' // 紫色中心
|
|||
|
|
}, {
|
|||
|
|
offset: 1,
|
|||
|
|
color: 'rgba(189, 181, 255, 0.8)' // 紫色边缘
|
|||
|
|
}]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 为指标添加分数显示
|
|||
|
|
const indicatorWithScore = indicator.map((item, index) => ({
|
|||
|
|
...item,
|
|||
|
|
name: item.name,
|
|||
|
|
value: actualData[index] // 存储分数值
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
const option = {
|
|||
|
|
tooltip: { show: false },
|
|||
|
|
grid: { show: false },
|
|||
|
|
radar: [
|
|||
|
|
{
|
|||
|
|
center: ["50%", "50%"],
|
|||
|
|
indicator: indicatorWithScore,
|
|||
|
|
radius: "45%", // 调小半径以确保文字和分数不超出容器
|
|||
|
|
nameGap: 35, // 增大间距,让文字距离雷达图更远
|
|||
|
|
shape: "circle", // 设置雷达图外圈为圆形
|
|||
|
|
// 网格线样式配置
|
|||
|
|
splitLine: {
|
|||
|
|
lineStyle: {
|
|||
|
|
color: lineClolr, // 网格线颜色
|
|||
|
|
width: 2,
|
|||
|
|
type: "solid", // 线条类型:solid, dashed, dotted
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
splitArea: { show: false },
|
|||
|
|
axisName: {
|
|||
|
|
color: "#4E5969",
|
|||
|
|
fontSize: 12,
|
|||
|
|
fontWeight: "900", // 更粗的文字
|
|||
|
|
lineHeight: 20,
|
|||
|
|
align: 'center', // 文本居中对齐
|
|||
|
|
rich: {
|
|||
|
|
score: {
|
|||
|
|
fontSize: 18,
|
|||
|
|
fontWeight: 'bold',
|
|||
|
|
color: isGreenTheme ? '#22c55e' : '#8b5cf6',
|
|||
|
|
padding: [0, 0, 8, 0],
|
|||
|
|
align: 'center',
|
|||
|
|
lineHeight: 24
|
|||
|
|
},
|
|||
|
|
name: {
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: '#4E5969',
|
|||
|
|
fontWeight: '900',
|
|||
|
|
align: 'center',
|
|||
|
|
lineHeight: 16
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
formatter: function(value, indicator) {
|
|||
|
|
const index = indicatorWithScore.findIndex(item => item.name === value);
|
|||
|
|
const score = actualData[index];
|
|||
|
|
// 已经包含换行符的处理
|
|||
|
|
if (value.includes('\n')) {
|
|||
|
|
const parts = value.split('\n');
|
|||
|
|
return '{score|' + score + '}\n{name|' + parts.join('\n') + '}';
|
|||
|
|
}
|
|||
|
|
// 对较长的文本进行换行处理
|
|||
|
|
if (value.length > 8) {
|
|||
|
|
const line1 = value.substring(0, 8);
|
|||
|
|
const line2 = value.substring(8);
|
|||
|
|
return '{score|' + score + '}\n{name|' + line1 + '\n' + line2 + '}';
|
|||
|
|
}
|
|||
|
|
return '{score|' + score + '}\n{name|' + value + '}';
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
axisLine: {
|
|||
|
|
lineStyle: {
|
|||
|
|
color: "#E5E6EB",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
series: [
|
|||
|
|
{
|
|||
|
|
type: "radar",
|
|||
|
|
radarIndex: 0,
|
|||
|
|
data: [{
|
|||
|
|
value: value || data,
|
|||
|
|
label: {
|
|||
|
|
show: false, // 关键:隐藏雷达图内的标签
|
|||
|
|
},
|
|||
|
|
emphasis: {
|
|||
|
|
label: {
|
|||
|
|
show: false, // 确保 hover 时也不显示
|
|||
|
|
},
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: "#333",
|
|||
|
|
},
|
|||
|
|
areaStyle: {
|
|||
|
|
color: gradientColor, // 使用渐变色
|
|||
|
|
}, // 关键:显示面积
|
|||
|
|
lineStyle: {
|
|||
|
|
color: isGreenTheme ? '#22c55e' : areaBorderColor, // 连接线颜色(边框颜色)
|
|||
|
|
width: 3, // 连接线宽度
|
|||
|
|
type: "solid", // 线条类型
|
|||
|
|
},
|
|||
|
|
symbol: "circle", // 显示端点
|
|||
|
|
symbolSize: 6, // 端点大小
|
|||
|
|
itemStyle: {
|
|||
|
|
color: "#fff", // 端点颜色
|
|||
|
|
borderColor: isGreenTheme ? '#22c55e' : areaBorderColor, // 端点边框颜色
|
|||
|
|
borderWidth: 2, // 端点边框宽度
|
|||
|
|
},
|
|||
|
|
}],
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (!chartRef.current) return;
|
|||
|
|
|
|||
|
|
// 如果实例不存在,则初始化
|
|||
|
|
if (!chartInstance.current) {
|
|||
|
|
chartInstance.current = echarts.init(chartRef.current);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置或更新配置,使用 notMerge: false 来避免重新触发动画
|
|||
|
|
chartInstance.current.setOption(option, {
|
|||
|
|
notMerge: false,
|
|||
|
|
lazyUpdate: true,
|
|||
|
|
silent: false,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleResize = () => {
|
|||
|
|
chartInstance.current?.resize();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.addEventListener("resize", handleResize);
|
|||
|
|
|
|||
|
|
return () => {
|
|||
|
|
window.removeEventListener("resize", handleResize);
|
|||
|
|
};
|
|||
|
|
}, [data, value, indicator]);
|
|||
|
|
|
|||
|
|
// 组件卸载时清理
|
|||
|
|
useEffect(() => {
|
|||
|
|
return () => {
|
|||
|
|
chartInstance.current?.dispose();
|
|||
|
|
};
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
return <div ref={chartRef} className={className} />;
|
|||
|
|
}
|