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. SO, I want to draw a Canvas radar map by myself and review the knowledge points of canvas.

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.

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. If the center point of the hexagon is (250, 250) and the length of the diagonal is 100*2, then the bottom-center coordinate (250, 250 + 100) is the bottom-left coordinate. (250-100* sin(60°), 250-100*cos(60°), 250-100*cos(60°)) (250 + 100*sin(60°), 250-100*cos(60°)) bottom-right coordinates: 250 plus 100 sin 60 degrees, 250 plus 100 cosine 60 degrees.

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. Bottom-center coordinates: (250 + 100*sin(0°), 250 + 100*cos(0°)) (250+100* sin(240°), 250+100*cos(240°), 250+100*cos(240°)) (250 +100*sin(120°), 250 +100* cos(120°)) (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

So, the coordinates of the regular hexagon are resolved through 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'; Var lineArr = []; var rAngle = Math.PI * 2 / 6; // Count each inner corner and console.log(rAngle); var rCenter = 250; Var curR = 100; 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();
Copy the code

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'; 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. 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. By analogy, it can be concluded that the remaining C is interval / 2.5 and D is interval / 3

So instead of writing a for loop, I’m going to write an object by hand.

2.1 Data Regional meeting Population

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 ctx.strokestyle = for the data-filled area'#dd3f26'; Var point = 3; // Set the size of the dot in the data fill areafor (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. Draw text

King of Glory radar text is required to draw two points,

① Draw the description points of each point with black 16px font; ② Draw the ability level of each point with 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.

Var rData = [['survival'.'S'],
        ['economic'.'S'],
        ['output'.'S'],
        ['KDA'.'B'],
        ['wild'.'B'],
        ['push'.'S']
    ]
    ctx.save();
    ctx.font = '16px Microsoft Yahei'; // Set the font ctx.fillstyle ='# 000'; / / colorfor (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.1 Drawing text – Type 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 the text ctx.save(); var fontSize = 16; ctx.font = fontSize +'px Microsoft Yahei';
    ctx.textBaseline="middle"; // Set the baseline reference point ctx.textalign ="center"; // Text 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 drawingif ( 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); }elseFillText (rData[I][0], x-s_width *1.5, y); ctx.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 the 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); }elseFillText (rData[I][0], x-s_width *1.5, y); ctx.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:

summary

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.)


The original article was written on December 07, 2017, and is now moved into “Cheettuzai Daily Life”.


PS: If you are interested in the full blogDemo code, you can read it on github.

Source code Demo portal address

I’m a car stick! I bring my own eyes, I bring my own salt!

(A xi bar, before every day at the bottom of the article pulled for their own eyes. And it turns out that after this year’s checkup, and a trip to the hospital, I have to carry salt with me every day. I don’t…

Gentlemen, it is the body that is the capital of revolution.