feat: 修改雷达图为圆形
This commit is contained in:
@@ -28,89 +28,39 @@ const RadarChart: React.FC = () => {
|
|||||||
.exec((res) => {
|
.exec((res) => {
|
||||||
const canvas = res[0].node as HTMLCanvasElement;
|
const canvas = res[0].node as HTMLCanvasElement;
|
||||||
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||||
|
|
||||||
// 设置像素比,保证清晰
|
|
||||||
const dpr = Taro.getSystemInfoSync().pixelRatio;
|
const dpr = Taro.getSystemInfoSync().pixelRatio;
|
||||||
canvas.width = res[0].width * dpr;
|
canvas.width = res[0].width * dpr;
|
||||||
canvas.height = res[0].height * dpr;
|
canvas.height = res[0].height * dpr;
|
||||||
ctx.scale(dpr, dpr);
|
ctx.scale(dpr, dpr);
|
||||||
|
|
||||||
// 绘制网格
|
// === 绘制圆形网格 ===
|
||||||
ctx.strokeStyle = "#ddd";
|
|
||||||
// for (let i = 1; i <= levels; i++) {
|
|
||||||
// const r = (radius / levels) * i;
|
|
||||||
// ctx.beginPath();
|
|
||||||
// labels.forEach((_, j) => {
|
|
||||||
// const angle = ((Math.PI * 2) / labels.length) * j - Math.PI / 2;
|
|
||||||
// const x = center.x + r * Math.cos(angle);
|
|
||||||
// const y = center.y + r * Math.sin(angle);
|
|
||||||
// if (j === 0) ctx.moveTo(x, y);
|
|
||||||
// else ctx.lineTo(x, y);
|
|
||||||
// });
|
|
||||||
// ctx.closePath();
|
|
||||||
// ctx.stroke();
|
|
||||||
// }
|
|
||||||
|
|
||||||
for (let i = 1; i <= levels; i++) {
|
for (let i = 1; i <= levels; i++) {
|
||||||
const r = (radius / levels) * i;
|
const r = (radius / levels) * i;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
labels.forEach((_, j) => {
|
ctx.arc(center.x, center.y, r, 0, Math.PI * 2);
|
||||||
const angle = ((Math.PI * 2) / labels.length) * j - Math.PI / 2;
|
|
||||||
const x = center.x + r * Math.cos(angle);
|
|
||||||
const y = center.y + r * Math.sin(angle);
|
|
||||||
if (j === 0) ctx.moveTo(x, y);
|
|
||||||
else ctx.lineTo(x, y);
|
|
||||||
});
|
|
||||||
ctx.closePath();
|
|
||||||
|
|
||||||
// === 偶数环填充颜色 ===
|
|
||||||
if (i % 2 === 0) {
|
if (i % 2 === 0) {
|
||||||
ctx.fillStyle = "rgba(0, 150, 200, 0.1)"; // 浅色填充,透明度可调
|
ctx.fillStyle = "rgba(0, 150, 200, 0.1)";
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
ctx.strokeStyle = "#bbb";
|
||||||
// 保留线条
|
|
||||||
ctx.strokeStyle = "#bbb"; // 边框颜色
|
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === 坐标轴 & 标签 ===
|
||||||
|
|
||||||
// 坐标轴 & 标签
|
|
||||||
ctx.fillStyle = "#333";
|
|
||||||
ctx.font = "12px sans-serif";
|
|
||||||
// labels.forEach((label, i) => {
|
|
||||||
// const angle = ((Math.PI * 2) / labels.length) * i - Math.PI / 2;
|
|
||||||
// const x = center.x + radius * Math.cos(angle);
|
|
||||||
// const y = center.y + radius * Math.sin(angle);
|
|
||||||
// ctx.beginPath();
|
|
||||||
// ctx.moveTo(center.x, center.y);
|
|
||||||
// ctx.lineTo(x, y);
|
|
||||||
// ctx.strokeStyle = "#bbb";
|
|
||||||
// ctx.stroke();
|
|
||||||
// ctx.fillText(
|
|
||||||
// label,
|
|
||||||
// x + Math.cos(angle) * 20,
|
|
||||||
// y + Math.sin(angle) * 20
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
|
|
||||||
labels.forEach((label, i) => {
|
labels.forEach((label, i) => {
|
||||||
const angle = ((Math.PI * 2) / labels.length) * i - Math.PI / 2;
|
const angle = ((Math.PI * 2) / labels.length) * i - Math.PI / 2;
|
||||||
|
|
||||||
// 线条终点(半径)
|
|
||||||
const x = center.x + radius * Math.cos(angle);
|
const x = center.x + radius * Math.cos(angle);
|
||||||
const y = center.y + radius * Math.sin(angle);
|
const y = center.y + radius * Math.sin(angle);
|
||||||
|
|
||||||
// 画坐标轴线
|
// 坐标轴
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(center.x, center.y);
|
ctx.moveTo(center.x, center.y);
|
||||||
ctx.lineTo(x, y);
|
ctx.lineTo(x, y);
|
||||||
ctx.strokeStyle = "#bbb";
|
ctx.strokeStyle = "#bbb";
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// === 改造后的文字位置 ===
|
// 标签
|
||||||
const offset = 10; // 标签离图形的距离
|
const offset = 10;
|
||||||
const textX = center.x + (radius + offset) * Math.cos(angle);
|
const textX = center.x + (radius + offset) * Math.cos(angle);
|
||||||
const textY = center.y + (radius + offset) * Math.sin(angle);
|
const textY = center.y + (radius + offset) * Math.sin(angle);
|
||||||
|
|
||||||
@@ -118,25 +68,18 @@ const RadarChart: React.FC = () => {
|
|||||||
ctx.fillStyle = "#333";
|
ctx.fillStyle = "#333";
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
|
|
||||||
console.log(label, angle)
|
|
||||||
|
|
||||||
// 根据角度调整文字对齐方式
|
|
||||||
if (Math.abs(angle) < 0.01 || Math.abs(Math.abs(angle) - Math.PI) < 0.01) {
|
if (Math.abs(angle) < 0.01 || Math.abs(Math.abs(angle) - Math.PI) < 0.01) {
|
||||||
// 顶部或底部
|
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
} else if (angle > -Math.PI / 2 && angle < Math.PI / 2) {
|
} else if (angle > -Math.PI / 2 && angle < Math.PI / 2) {
|
||||||
// 右侧
|
|
||||||
ctx.textAlign = "left";
|
ctx.textAlign = "left";
|
||||||
} else {
|
} else {
|
||||||
// 左侧
|
|
||||||
ctx.textAlign = "right";
|
ctx.textAlign = "right";
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.fillText(label, textX, textY);
|
ctx.fillText(label, textX, textY);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// === 数据区域 ===
|
||||||
// 数据区域
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
values.forEach((val, i) => {
|
values.forEach((val, i) => {
|
||||||
const angle = ((Math.PI * 2) / labels.length) * i - Math.PI / 2;
|
const angle = ((Math.PI * 2) / labels.length) * i - Math.PI / 2;
|
||||||
@@ -155,6 +98,7 @@ const RadarChart: React.FC = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 保存为图片
|
// 保存为图片
|
||||||
const saveImage = () => {
|
const saveImage = () => {
|
||||||
Taro.canvasToTempFilePath({
|
Taro.canvasToTempFilePath({
|
||||||
|
|||||||
Reference in New Issue
Block a user