canvas雷达图

发布时间 2023-07-05 15:12:18作者: <好嗨哦!>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 500px;
height: 500px;
border: 1px solid red;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
class Radar {
constructor(json) {
this.cvs = document.createElement("canvas");
this.w = json.dom.offsetWidth;
this.h = json.dom.offsetHeight;
this.cvs.width = this.w;
this.cvs.height = this.h;
json.dom.appendChild(this.cvs);

this.ctx = this.cvs.getContext("2d");
// 数据最大值
this.maxData = 150;
// 半径
this.r = Math.min(this.w, this.h) / 2 - 50;
// 雷达图圈数
this.number = 5;
this.data = json.data;
this.point = {
x: this.w / 2,
y: this.h / 2
};
this.colors = ['#ffffff', '#ffd072', '#ffd98c', '#ffe2a7', '#fff2d9'];
this.drop();
}

drop() {
const r = this.r / this.number;
const angle = 360 / this.data.length;
const dataPoints = [];
for (let i = this.number - 1; i >= 0; i--) {
const linePoints = [];
for (let j = 0; j < this.data.length; j++) {
linePoints.push({
x: this.point.x + Math.cos(Math.PI * 2 / 360 * (angle * j - 90)) * (r * i),
y: this.point.y + Math.sin(Math.PI * 2 / 360 * (angle * j - 90)) * (r * i)
});

if (i + 1 === this.number) {
dataPoints.push({
x: this.point.x + Math.cos(Math.PI * 2 / 360 * (angle * j - 90)) * ((this.r - r) / this.maxData * this.data[j].value),
y: this.point.y + Math.sin(Math.PI * 2 / 360 * (angle * j - 90)) * ((this.r - r) / this.maxData * this.data[j].value)
});
}
}
this.drawRect(linePoints, i);
}
this.dataArc(dataPoints);
this.dataLine(dataPoints);
this.drawLabel();
}

dataArc(points) {
for (let i = 0; i < points.length; i++) {
this.ctx.beginPath();
this.ctx.arc(points[i].x, points[i].y, 7, 0, 2 * Math.PI);
this.ctx.fillStyle = "#ffab01";
this.ctx.fill();
this.ctx.closePath();
}
}

dataLine(points) {
this.ctx.beginPath();
this.ctx.lineWidth = 4;
this.ctx.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
this.ctx.lineTo(points[i].x, points[i].y);
}
this.ctx.lineTo(points[0].x, points[0].y);
this.ctx.strokeStyle = "#ffab01";
this.ctx.stroke();
this.ctx.closePath();
}

drawLabel() {
const angle = 360 / this.data.length;
for (let i = 0; i < this.data.length; i++) {
const point = {
x: this.point.x + Math.cos(Math.PI * 2 / 360 * (angle * i - 90)) * this.r,
y: this.point.y + Math.sin(Math.PI * 2 / 360 * (angle * i - 90)) * this.r
}
switch (i) {
case 0:
point.y += 30;
break;
case 1:
case 4:
point.y += 20;
break;
case 2:
case 3:
point.y -= 10;
break;
}
this.ctx.beginPath();
this.ctx.font = "normal bold 16px Georgia";
this.ctx.fillStyle = this.data[i].color;
const width = this.ctx.measureText(this.data[i].name).width;
this.ctx.fillText(this.data[i].name, point.x - width / 2, point.y);
this.ctx.closePath();
}
}

drawRect(points, index) {
const radius = 12;
this.ctx.beginPath();
this.ctx.moveTo((points[0].x + points[points.length - 1].x) / 2,(points[0].y + points[points.length - 1].y) / 2);
for (let i = 0; i < points.length; i++) {
if (i === points.length - 1) {
this.ctx.arcTo(points[i].x, points[i].y, points[0].x, points[0].y, radius);
} else {
this.ctx.arcTo(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, radius);
}
}
this.ctx.fillStyle = this.colors[index];
this.ctx.fill();
this.ctx.closePath();
}
}

new Radar({
dom: document.getElementById("box"),
data: [
{name: "思维力", value: 108, color: "#ffab01"},
{name: "注意力", value: 98, color: "#ef717a"},
{name: "记忆力", value: 88, color: "#63c061"},
{name: "反应力", value: 48, color: "#cc65a3"},
{name: "自控力", value: 129, color: "#59a6f2"},
]
})
</script>
</body>
</html>