|
|
|
|
@ -51,9 +51,18 @@ const startDraw = function () {
|
|
|
|
|
if (custom) {
|
|
|
|
|
// === custom 为 true 时 (最外层) ===
|
|
|
|
|
// 绘制虚线边框,且在每个角留出空隙给文字
|
|
|
|
|
const gap = 40; // 避让距离,根据文字大小调整
|
|
|
|
|
const gap = 40; // 基础避让距离
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < 6; i++) {
|
|
|
|
|
// 针对特定边调整 gap,实现"往下延伸"的效果
|
|
|
|
|
let startGap = gap;
|
|
|
|
|
let endGap = gap;
|
|
|
|
|
|
|
|
|
|
// i=1: 定期寿险(下) -> 储蓄养老(上)。往下延伸 = 减少起点的 gap
|
|
|
|
|
if (i === 1) startGap -= 15;
|
|
|
|
|
// i=4: 重疾险(上) -> 意外险(下)。往下延伸 = 减少终点的 gap
|
|
|
|
|
if (i === 4) endGap -= 15;
|
|
|
|
|
|
|
|
|
|
// 当前顶点 (起点)
|
|
|
|
|
const angle1 = (Math.PI / 3) * i + Math.PI / 2;
|
|
|
|
|
const x1 = centerX + radius * Math.cos(angle1);
|
|
|
|
|
@ -69,16 +78,16 @@ const startDraw = function () {
|
|
|
|
|
const dy = y2 - y1;
|
|
|
|
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
|
|
|
|
|
|
// 只有当边长大于 2*gap 时才绘制,防止交叉
|
|
|
|
|
if (dist > 2 * gap) {
|
|
|
|
|
// 只有当边长大于 gap 之和时才绘制
|
|
|
|
|
if (dist > startGap + endGap) {
|
|
|
|
|
const ux = dx / dist;
|
|
|
|
|
const uy = dy / dist;
|
|
|
|
|
|
|
|
|
|
// 计算避让后的起点和终点
|
|
|
|
|
const sx = x1 + ux * gap;
|
|
|
|
|
const sy = y1 + uy * gap;
|
|
|
|
|
const ex = x2 - ux * gap;
|
|
|
|
|
const ey = y2 - uy * gap;
|
|
|
|
|
const sx = x1 + ux * startGap;
|
|
|
|
|
const sy = y1 + uy * startGap;
|
|
|
|
|
const ex = x2 - ux * endGap;
|
|
|
|
|
const ey = y2 - uy * endGap;
|
|
|
|
|
|
|
|
|
|
ctx.moveTo(sx, sy);
|
|
|
|
|
ctx.lineTo(ex, ey);
|
|
|
|
|
@ -122,26 +131,96 @@ const startDraw = function () {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加文本到六边形的角上
|
|
|
|
|
function drawTextAtCorners(radius, textArray) {
|
|
|
|
|
// 文本内容数组,对应六边形的6个角
|
|
|
|
|
const text = textArray || ['医疗险', '定期寿险', '储蓄养老', '家财宠险', '重疾险', '意外险'];
|
|
|
|
|
const textColors = ['#333', '#333', '#333', '#333', '#333', '#333']; // 文本颜色
|
|
|
|
|
const textSizes = [20, 20, 20, 20, 20, 20]; // 文本大小
|
|
|
|
|
function drawTextAtCorners(radius, dataArray) {
|
|
|
|
|
// 默认兜底数据
|
|
|
|
|
const data = dataArray;
|
|
|
|
|
const titleSize = 20; // 标题文本大小
|
|
|
|
|
const statusSize = 14; // 状态文本大小
|
|
|
|
|
const rowGap = 10; // 标题与状态行的间距
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < 6; i++) {
|
|
|
|
|
const angle = (Math.PI / 3) * i + Math.PI / 2; // 当前角的角度(从顶部开始)
|
|
|
|
|
const item = data[i];
|
|
|
|
|
const angle = (Math.PI / 3) * i + Math.PI / 2; // 当前角的角度
|
|
|
|
|
const x = centerX + radius * Math.cos(angle);
|
|
|
|
|
const y = centerY + radius * Math.sin(angle);
|
|
|
|
|
|
|
|
|
|
// 设置文本样式
|
|
|
|
|
ctx.font = `bold ${textSizes[i]}px Arial`;
|
|
|
|
|
ctx.fillStyle = textColors[i];
|
|
|
|
|
// === 1. 绘制标题 ===
|
|
|
|
|
ctx.font = `bold ${titleSize}px Arial`;
|
|
|
|
|
ctx.fillStyle = '#333';
|
|
|
|
|
ctx.textAlign = 'center';
|
|
|
|
|
ctx.textBaseline = 'middle';
|
|
|
|
|
ctx.fillText(item.title, x, y);
|
|
|
|
|
|
|
|
|
|
// === 2. 绘制状态行 (图标 + 文字) ===
|
|
|
|
|
const isGuaranteed = item.status;
|
|
|
|
|
const statusText = isGuaranteed ? '已保障' : '未保障';
|
|
|
|
|
const activeColor = '#67C23A'; // 高亮绿色
|
|
|
|
|
const inactiveColor = '#909399'; // 置灰颜色
|
|
|
|
|
const color = isGuaranteed ? activeColor : inactiveColor;
|
|
|
|
|
|
|
|
|
|
// 计算位置
|
|
|
|
|
// 标题中心是 y,下移距离 = 标题半高 + 间距 + 状态文字半高
|
|
|
|
|
// 简单估算:y + 10 (标题下沿) + 10 (间距) + 7 (状态文字中心) ≈ y + 27
|
|
|
|
|
const statusY = y + 27;
|
|
|
|
|
|
|
|
|
|
// 测量宽度以实现整体居中
|
|
|
|
|
ctx.font = `normal ${statusSize}px Arial`;
|
|
|
|
|
const textWidth = ctx.measureText(statusText).width;
|
|
|
|
|
const iconRadius = 4;
|
|
|
|
|
const iconGap = 4; // 图标与文字间距
|
|
|
|
|
const totalWidth = iconRadius * 2 + iconGap + textWidth;
|
|
|
|
|
|
|
|
|
|
// 计算起始 X 坐标 (使得 [图标+间距+文字] 整体居中)
|
|
|
|
|
// 整体左边缘 = 中心点x - 总宽的一半
|
|
|
|
|
// 图标中心x = 整体左边缘 + 半径
|
|
|
|
|
const iconCenterX = x - totalWidth / 2 + iconRadius;
|
|
|
|
|
|
|
|
|
|
// A. 绘制图标 (实心圆)
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
ctx.arc(iconCenterX, statusY, iconRadius, 0, Math.PI * 2);
|
|
|
|
|
ctx.fillStyle = color;
|
|
|
|
|
ctx.fill();
|
|
|
|
|
|
|
|
|
|
// B. 绘制状态文字
|
|
|
|
|
ctx.fillStyle = color;
|
|
|
|
|
ctx.textAlign = 'left'; // 改为左对齐,基于图标位置排列
|
|
|
|
|
ctx.textBaseline = 'middle';
|
|
|
|
|
const textX = iconCenterX + iconRadius + iconGap;
|
|
|
|
|
ctx.fillText(statusText, textX, statusY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 绘制文本
|
|
|
|
|
ctx.fillText(text[i], x, y);
|
|
|
|
|
// 绘制雷达图区域
|
|
|
|
|
function drawRadar(maxRadius, data) {
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
for (let i = 0; i < 6; i++) {
|
|
|
|
|
const value = data[i].value || 0;
|
|
|
|
|
// 计算当前点的半径长度:(值 / 100) * 最大半径
|
|
|
|
|
const currentRadius = (value / 100) * maxRadius;
|
|
|
|
|
|
|
|
|
|
const angle = (Math.PI / 3) * i + Math.PI / 2;
|
|
|
|
|
const x = centerX + currentRadius * Math.cos(angle);
|
|
|
|
|
const y = centerY + currentRadius * Math.sin(angle);
|
|
|
|
|
|
|
|
|
|
if (i === 0) {
|
|
|
|
|
ctx.moveTo(x, y);
|
|
|
|
|
} else {
|
|
|
|
|
ctx.lineTo(x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx.closePath();
|
|
|
|
|
|
|
|
|
|
// 径向渐变:中心深 -> 边缘浅
|
|
|
|
|
const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, maxRadius);
|
|
|
|
|
gradient.addColorStop(1, 'rgba(255, 240, 231, 0)');
|
|
|
|
|
gradient.addColorStop(0, 'rgba(248, 159, 107, 1)');
|
|
|
|
|
|
|
|
|
|
ctx.fillStyle = gradient;
|
|
|
|
|
ctx.fill();
|
|
|
|
|
// 可选:添加一条描边增加清晰度
|
|
|
|
|
// ctx.strokeStyle = 'rgba(252, 201, 169, 1)';
|
|
|
|
|
// ctx.lineWidth = 1;
|
|
|
|
|
// ctx.stroke();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawBackground();
|
|
|
|
|
@ -151,7 +230,19 @@ const startDraw = function () {
|
|
|
|
|
drawHexagon(50);
|
|
|
|
|
|
|
|
|
|
// 在最外层六边形的角上添加文本
|
|
|
|
|
drawTextAtCorners(200, ['医疗险', '定期寿险', '储蓄养老', '家财宠险', '重疾险', '意外险']);
|
|
|
|
|
const cornerData = [
|
|
|
|
|
{ title: '医疗险', status: true, value: 0 },
|
|
|
|
|
{ title: '定期寿险', status: true, value: 100 }, // 已保障 -> 100
|
|
|
|
|
{ title: '储蓄养老', status: false, value: 25 }, // 未保障 -> 25
|
|
|
|
|
{ title: '家财宠险', status: true, value: 100 }, // 已保障 -> 100
|
|
|
|
|
{ title: '重疾险', status: true, value: 0 },
|
|
|
|
|
{ title: '意外险', status: false, value: 0 },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 绘制雷达图 (最大半径对应第三个实心六边形,即150)
|
|
|
|
|
drawRadar(150, cornerData);
|
|
|
|
|
|
|
|
|
|
drawTextAtCorners(200, cornerData);
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|