Editor’s note: This article is from che Dadao’s contribution
Background: a night off work I quietly rely on the corner to listen to the song, then “drop! Drop!” A burst of QQ news came from my mobile phone. I was asking how the king of Glory radar image was made on the page, and someone answered that it was painted on canvas. So the problem is that I haven’t used canvas to draw things for a long time.
The basic components of the Honor of Kings radar map
The radar chart in the chat record is not very clear, so I took a screenshot of my own radar chart.
Is not scared by my record, harm not afraid! Anyway, let’s get back to the point. As shown in the screenshot above, the basic body of the radar diagram is a regular hexagon with corresponding text description for each vertex. And then you have the red area in the middle and then you have a circle of dots on the diagonal. So we call it data filling area, so this radar diagram is divided into three steps: ① regular hexagon, ② data filling area, ③ drawing text.
Coordinate point analysis of hexagon deformation
Before drawing the regular hexagon, let’s do a simple mathematical analysis of the regular hexagon. Here, I’m going to draw a square six on my palette, and then I’m going to cut and Angle it.
Right? Well, in high school or middle school math, the interior angles of a regular hexagon add up to 720 degrees, so each diagonal Angle is 120 degrees. You know the length of the diagonal. So from sine of 60 degrees, cosine of 60 degrees, whatever, you can figure out the sides of each triangle.
But here’s the problem. What we’re trying to calculate here are the coordinate points. The canvas coordinate axis is the single-quadrant coordinate axis from the origin (0,0) in the upper left corner. Assuming that the center point of the hexagon is (250,250) and the length of the diagonal is 1002, then the trigonometric function can be deduced as follows:
Bottom-center coordinates: (250, 250+100) Bottom-center coordinates: (250, 250+100) 250-100sin (60°), 250+100cos(60°)
Top-left coordinates :(250-100sin (60°), 250-100cos(60°))
Top-center coordinates: (250, 250-100) Top-right coordinates: (250 + 100sin(60°), 250-100cos(60°)
Bottom-right coordinates :(250+100 sin(60°), 250+100 cos(60°))
The coordinates are out, but it’s too low to paint point by point! How to do? La la la la!
So it’s time for us to find a pattern!
But while looking for the rule, the X-axis of the center point of the wool is different from others, adding and subtracting the wool for a while.
So when thinking about the rules of coordinate point parameters, let’s first review the previous function Angle diagram
After looking at the function reference diagram, let me revise the way the 6 points are written again. (250 + 100*sin(0°), 250 + 100*cos(0°)) (250+100* sin(240°), 250+100*cos(300°)) (250+100* sin(240°), 250+100*cos(240°)) (250 +100*sin(120°), 250 +100* cos(120°)) bottom-right: (250 +100*sin(120°), 250 +100* cos(120°)) (250+100 sin60°), 250+100 cos(60°)
This time to look at the group of coordinate data points, is not the feeling a little interesting!
Then we can use a for loop to record the six points in an array.
var pointArr = [];
for (var i = 0; i < 6; i++) {
pointArr[i] = {};
pointArr[i].x = 250 + 100 * Math.sin(60 * i);
pointArr[i].y = 250 + 100 * Math.cos(60 * i);
}
Copy the code
1.1 Drawing regular hexagon
The coordinates of the regular hexagon are resolved by a for loop. So that’s code drawing regular hexagon:
<style> canvas { display: block; width: 500px; height: 500px; }</style>
<body> <canvas class="radar"></canvas> </body>
<script>
var canvas = document.getElementsByClassName('radar')[0];
canvas.width = 500;
canvas.height = 500;
var ctx = canvas.getContext('2d');
ctx.save();
ctx.strokeStyle = '#888888'; // Set the line color
var lineArr = [];
var rAngle = Math.PI * 2 / 6; // Find the sum of each of the interior angles
console.log(rAngle);
var rCenter = 250; // Determine the center point
var curR = 100; // Determine the radius length
ctx.beginPath();
for (var i = 0; i < 6; i++) {
lineArr[i] = {};
lineArr[i].y = rCenter + curR * Math.cos(rAngle * i);
lineArr[i].x = rCenter + curR * Math.sin(rAngle * i);
ctx.lineTo(lineArr[i].x, lineArr[i].y);
}
ctx.closePath();
ctx.stroke();
ctx.restore();
</script>
Copy the code
La la la la!! A regular hexagon is drawn like this.
Note: rAngle here is very flexible, if you draw 18 straight edges, divide by 18, and then loop for 18 times.
Ha ha!!!!! I feel like I’ve discovered a new continent! Drawing regular polygons seems to follow this rule!!
1.2 Draw diagonals
Since there is an array in front of each coordinate point, so let each diagonal diagonal point line want to connect ok!
ctx.strokeStyle = '#e8ddc7'; // PS a sucker
ctx.save();
ctx.beginPath();
// for (var j = 0; j < 3; j++) {
// ctx.lineTo(lineArr[j].x, lineArr[j].y);
// ctx.lineTo(lineArr[j+3].x, lineArr[j+3].y);
// ctx.stroke();
// }
for (var j = 0; j < 3; j++) {
//ctx.moveTo(lineArr[j].x, lineArr[j].y);
//ctx.lineTo(lineArr[j + 3].x, lineArr[j + 3].y);
//ctx.stroke();
}
ctx.closePath();
ctx.restore();
Copy the code
2.1 Data filling area
The data fill area, in the radar diagram, is an irregular red translucent hexagon. So you can kind of view it as a line segment between the center and the corners. And then you divide this interval into parts, how many parts of this interval do you occupy, full is the corner, zero is the origin.
Looking at the previous radar chart, grade B accounts for about 50% of a grade. B is preceded by grades A and S. So when you’re at S level, you can view it as an interval over one. Grade B is regarded as interval / 2, so A is interval / 1.5.
In this way, it can be concluded that the remaining C is the interval / 2.5 and D: the interval / 3
So instead of writing a for loop, I’m going to write an object by hand.
// Draw the data area
var letterData = {
'S': 1,
'A' : 1.5.
'B': 2,
'C' : 2.5,
'D': 3
}
ctx.save();
ctx.beginPath();
for (var i = 0; i < 6; i++) {
lineArr[i].yEnd = rCenter + curR * Math.cos(rAngle * i) / (letterData[rData[i][1]]);
lineArr[i].xEnd = rCenter + curR * Math.sin(rAngle * i) / (letterData[rData[i][1]]);
ctx.lineTo(lineArr[i].xEnd, lineArr[i].yEnd);
console.log(lineArr);
}
ctx.closePath();
ctx.stroke();
Ctx. fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fill();
Copy the code
2.2 Draw small dots and side lengths for the data-filled area
When we go back to the previous screenshot, we find that we need to strengthen the positions of each point in the data-filled area separately, and draw the edges and corners with deeper lines.
ctx.lineWidth = 2; // Set the line color for the data-filled area
ctx.strokeStyle = '#dd3f26'; // Set the color of the fill area
var point = 3; // Set the size of the dot in the data fill area
for (var i = 0; i < 6; i++) {
ctx.beginPath();
ctx.arc(lineArr[i].xEnd, lineArr[i].yEnd, point, 0, Math.PI * 2);
Ctx. fillStyle = 'rgba(255, 0, 0, 0.8)';
ctx.fill();
console.log(lineArr);
}
ctx.restore();
Copy the code
3.1 Drawing Text
King of Glory radar text is required to draw two points:
① Draw each description point with black 16px font
② Draw each point’s ability level in red 30px font
But I guess when I see the text drawn, I guess some of my friends will say. Instead of having an array to store the coordinates of each corner, a for loop will draw each point in turn.
// Draw text
var rData = [
[' survive ', 'S'],
[' economy ', 'S'],
[' output ', 'S'],
['KDA', 'B'],
[' play wild ', 'B'],
[' push ', 'S']
];
ctx.save();
ctx.font = '16px Microsoft Yahei'; // Set the font
ctx.fillStyle = '#000'; / / color
for (var i = 0; i < 6; i++) {
var y = rCenter + curR * Math.cos(rAngle * i);
var x = rCenter + curR * Math.sin(rAngle * i);
ctx.fillText(rData[i][0], x, y);
}
ctx.restore();
Copy the code
The final visual display of the browser:
Do you feel very surprised, here output, economic position is barely ok, but the rest of the text position is a lot of deviation. Therefore, when drawing the text, we have to adjust the coordinate position of the text.
3.2 Drawing text — Description
Since direct calls to coordinate positions can cause problems, let’s simply analyze them according to the rules of picture text above. ① If X axis == center point, then judge Y axis. Move the text down a bit more than the center and up a bit more than the center. ② If the X-axis is less than the center point, the X-axis position of the text will be moved a little to the left, and the distance will be moved to the right anyway.
// Draw text
ctx.save();
var fontSize = 16;
ctx.font = fontSize + 'px Microsoft Yahei';
ctx.textBaseline = "middle"; // Set baseline reference points
ctx.textAlign = "center"; // The text is centered
ctx.fillStyle = '#000';
for (var i = 0; i < 6; i++) {
var y = rCenter + curR * Math.cos(rAngle * i);
var x = rCenter + curR * Math.sin(rAngle * i);
console.log(Math.sin(rAngle * i))
var s_width = ctx.measureText(rData[i][0]).width; // Gets the font width of the current drawing
if (x == rCenter) {
if (y > rCenter) {
ctx.fillText(rData[i][0], x - s_width / 2, y + fontSize);
} else {
ctx.fillText(rData[i][0], x - s_width / 2, y - fontSize);
}
} else if (x > rCenter) {
console.log(rData[i][0]);
FillText (rData[I][0], x + s_width * 1.5, y); ctx.fillText(rData[I][0], x + s_width * 1.5, y);
} else {
FillText (rData[I][0], x-s_width * 1.5, y);
}
}
Copy the code
TextBaseline: set or return the current textBaseline used when drawing text. Ctx. textBaseline: set or return the current textBaseline used when drawing text
Instantly recalled that year was punished to copy English words years, a bitter tears ah.
Web design fonts also have a baseline, so the baseline point of canvas is to draw a horizontal baseline directly from the coordinate point. Here’s a screenshot from the network to see how the text position changes by setting the baseline reference position.
Ctx. textAlign: This text is horizontally centered, but unlike CSS centering, it splits the text by drawing a vertical line from the coordinates.
Ctx.measuretext: Returns an object containing the specified text width.
In plain English, get the width of the text you draw. Assume a row of text with the content ‘Hello World’ and the size of 16px text. In this case, the height is fixed at 16px, so all other canvas elements need to do is move the ‘size’ of the text on the Y-axis to avoid overwriting it.
But if you want to move the X axis, you don’t know the length of ‘Hello World’. The measureText method ctx.measureText is used to measure the width of the text you are currently drawing.
3.2 Draw text — Ability level
Now that the painting method described above has been introduced, follow suit. Let’s start drawing ability-level text all together.
// Draw text
ctx.save();
var fontSize = 16;
var maxfontSize = 30;
ctx.font = fontSize + 'px Microsoft Yahei';
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (var i = 0; i < 6; i++) {
var y = rCenter + curR * Math.cos(rAngle * i);
var x = rCenter + curR * Math.sin(rAngle * i);
console.log(Math.sin(rAngle * i)) var s_width = ctx.measureText(rData[i][0]).width;
if (x == rCenter) {
if (y > rCenter) {
ctx.fillText(rData[i][0], x - s_width / 2, y + fontSize);
} else {
ctx.fillText(rData[i][0], x - s_width / 2, y - fontSize);
}
} else if (x > rCenter) {
console.log(rData[i][0]);
FillText (rData[I][0], x + s_width * 1.5, y); ctx.fillText(rData[I][0], x + s_width * 1.5, y);
} else {
FillText (rData[I][0], x-s_width * 1.5, y);
}
}
ctx.restore();
ctx.save(); // Draw the level
ctx.font = '30px Microsoft Yahei bold';
ctx.fillStyle = '#d7431f';
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (var i = 0; i < 6; i++) {
var y = rCenter + curR * Math.cos(rAngle * i);
var x = rCenter + curR * Math.sin(rAngle * i);
var M_width = ctx.measureText(rData[i][1]).width;
if (x == rCenter) {
if (y > rCenter) {
ctx.fillText(rData[i][1], x + M_width / 2, y + fontSize);
} else {
ctx.fillText(rData[i][1], x + M_width / 2, y - fontSize);
}
} else if (x > rCenter) {
console.log(rData[i][0]);
ctx.fillText(rData[i][1], x + M_width, y);
} else {
ctx.fillText(rData[i][1], x - M_width, y);
}
}
ctx.restore();
ctx.save();
Copy the code
Final page effect:
At the end
All right! Above is my simple understanding and review of canvas painting, and I also reviewed some basic canvas property points. How to use canvas to play various tricks is up to you!
Tip: Be careful when using the CTx. measureText method. This method also relates the width reference object to the font size of the current painting environment.
For example, when drawing descriptive text. Font size is set to 16px, so CTx.measureText (‘ output ‘).width is 32. If font size is set to 32, ctx.measureText(‘ output ‘).width will not be 32, but 64 or.
Original article, writing is limited, talent is shallow, if there is a mistake in the article, once again again welcome you slap slap face to give advice. (There is an old saying that you should say an important word three times.)
I’m a car stick! I have eyes for myself!
About Weird Dance Weekly
Qiwu Weekly is a front-end technology community operated by qiwu Group, a professional front-end team of 360 Company. After paying attention to the public number, directly send the link to the background can contribute to us.