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.