feat: 问卷调查

This commit is contained in:
2025-09-26 15:31:24 +08:00
parent 16c7be700b
commit 3cc2a24be5
13 changed files with 1197 additions and 73 deletions

View File

@@ -0,0 +1,183 @@
import Taro, { useReady } from "@tarojs/taro";
import { View, Canvas, Button } from "@tarojs/components";
import { useEffect } from "react";
const RadarChart: React.FC = () => {
const labels = [
"正手球质",
"正手控制",
"反手球质",
"反手控制",
"底线相持",
"场地覆盖",
"发球接发",
"接随机球",
"战术设计",
];
const values = [50, 75, 60, 20, 40, 70, 65, 35, 75];
const maxValue = 100;
const levels = 4;
const radius = 100;
const center = { x: 160, y: 160 };
useReady(() => {
const query = Taro.createSelectorQuery();
query
.select("#radarCanvas")
.fields({ node: true, size: true })
.exec((res) => {
const canvas = res[0].node as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
// 设置像素比,保证清晰
const dpr = Taro.getSystemInfoSync().pixelRatio;
canvas.width = res[0].width * dpr;
canvas.height = res[0].height * 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++) {
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();
// === 偶数环填充颜色 ===
if (i % 2 === 0) {
ctx.fillStyle = "rgba(0, 150, 200, 0.1)"; // 浅色填充,透明度可调
ctx.fill();
}
// 保留线条
ctx.strokeStyle = "#bbb"; // 边框颜色
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) => {
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();
// === 改造后的文字位置 ===
const offset = 10; // 标签离图形的距离
const textX = center.x + (radius + offset) * Math.cos(angle);
const textY = center.y + (radius + offset) * Math.sin(angle);
ctx.font = "12px sans-serif";
ctx.fillStyle = "#333";
ctx.textBaseline = "middle";
console.log(label, angle)
// 根据角度调整文字对齐方式
if (Math.abs(angle) < 0.01 || Math.abs(Math.abs(angle) - Math.PI) < 0.01) {
// 顶部或底部
ctx.textAlign = "center";
} else if (angle > -Math.PI / 2 && angle < Math.PI / 2) {
// 右侧
ctx.textAlign = "left";
} else {
// 左侧
ctx.textAlign = "right";
}
ctx.fillText(label, textX, textY);
});
// 数据区域
ctx.beginPath();
values.forEach((val, i) => {
const angle = ((Math.PI * 2) / labels.length) * i - Math.PI / 2;
const r = (val / maxValue) * radius;
const x = center.x + r * Math.cos(angle);
const y = center.y + r * Math.sin(angle);
if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
});
ctx.closePath();
ctx.fillStyle = "rgba(0,200,180,0.3)";
ctx.fill();
ctx.strokeStyle = "#00c8b4";
ctx.lineWidth = 4;
ctx.stroke();
});
});
// 保存为图片
const saveImage = () => {
Taro.canvasToTempFilePath({
canvasId: "radarCanvas",
success: (res) => {
Taro.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => Taro.showToast({ title: "保存成功" }),
});
},
});
};
return (
<View>
<Canvas
type="2d"
id="radarCanvas"
style={{ width: "320px", height: "320px", background: "transparent" }}
/>
{/* <Button onClick={saveImage}>保存为图片</Button> */}
</View>
);
};
export default RadarChart;