[Small Program] Canvas draws five-dimensional diagrams

I received a request a few days ago to draw a five-dimensional graph based on five pieces of data. In order to better meet the requirements of the product manager, I chose to use canvas to draw it.

After looking at the drawing method, I drew the renderings carelessly. Now I would like to share my experience.

First, understand that  
the coordinate origin of the canvas in the coordinate system applet is in the upper left corner, the x-axis is positive to the right, and the y-axis is positive downward.
For example: knowing the coordinates (X, Y) of a certain point A, the distance between point B and A on the X-axis and Y-axis is obtained through calculation, through the position of B relative to A, and through "← minus → addition, ↑ The calculation method of "minus ↓ plus" calculates the coordinates of B on X and Y.

After a preliminary understanding, I started to sharpen the gun on the view while going into battle.

First add canvas in wxml

<view style="position: relative;display: flex;flex-direction: column;height: 400rpx;align-items: center;">
    <canvas id="myCanvas" type="2d" style="height: 400rpx;width: 600rpx;" />
</view>

Then add the method in the mini program document to the js file.

 DrawFive() {
        let _this = this
        wx.createSelectorQuery()
            .select('#myCanvas') // 在 WXML 中填入的 id
            .fields({ node: true, size: true })
            .exec((res) => {
                // Canvas 对象
                const canvas = res[0].node
                // Canvas 画布的实际绘制宽高
                const renderWidth = res[0].width
                const renderHeight = res[0].height
                // Canvas 绘制上下文
                const ctx = canvas.getContext('2d')

                // 初始化画布大小
                const dpr = wx.getWindowInfo().pixelRatio
                canvas.width = renderWidth * dpr
                canvas.height = renderHeight * dpr
                ctx.scale(dpr, dpr)
                // 绘制前清空画布
                ctx.clearRect(0, 0, canvas.width, canvas.height)
                //后续操作
             
            })
    }

Considering that the picture we want to draw uses trigonometric functions, we need to declare some methods and constants.

        const cos = Math.cos
        const sin = Math.sin
        const PI = Math.PI

Regarding Math.PI refers to our circumference pi. It should be noted that Math.cos and Math.sin are different from those in our mathematical calculations. In mathematics, cos60° is an angle, and Math.cos(1.05) is a radian.

Formulas for calculating radians and angles:

弧度 = 角度*PI/180
角度 = 弧度*180/PI

 Our canvas is defined as 200*300px in wxml. We set the point and radius, set the color and line width to draw the outermost circle.

                var p0x = 150
                var p0y = 110
                var r = 70


                ctx.beginPath()
                ctx.strokeStyle = '#EB37221A'
                ctx.lineWidth = '4'
                ctx.arc(p0x, p0y, r, 0, 2 * Math.PI, true)
                ctx.stroke()
                ctx.closePath()

Then reset the color and line width and draw five lines

                ctx.beginPath()
                ctx.strokeStyle = '#EB37221A'
                ctx.lineWidth = '1'
                ctx.stroke()
                ctx.moveTo(p0x, p0y)
                ctx.lineTo(p0x, p0y - r)
                ctx.stroke();
                var p1y = r * sin(PI / 180 * 18)
                var p1x = r * cos(PI / 180 * 15)

                ctx.moveTo(p0x, p0y)
                ctx.lineTo(p0x + p1x, p0y - p1y)
                ctx.stroke()
                var p2y = r * sin(PI / 180 * 54)
                var p2x = r * cos(PI / 180 * 54)

                ctx.moveTo(p0x, p0y)
                ctx.lineTo(p0x + p2x, p0y + p2y)
                ctx.stroke()
                var p3y = p2y
                var p3x = p2x

                ctx.moveTo(p0x, p0y)
                ctx.lineTo(p0x - p3x, p0y + p3y)
                ctx.stroke()
                var p4y = p1y
                var p4x = p1x
                ctx.moveTo(p0x, p0y)
                ctx.lineTo(p0x - p4x, p0y - p4y)
                ctx.stroke()
                ctx.closePath()

moveTo(x,y) means to move the pointer to this position, just move it there and that's it.

lineTo(x,y) means to draw from the current point to the point (x,y), draw all the way, and draw a line when you reach it.

After drawing the line, we mark the outer words and numbers.

We first add default data in Js data

    data: {
        result: { "radar_map": [{ "id": 1, "name": "字词认读", "score": 20 }, { "id": 2, "name": "观察感知", "score": 20 }, { "id": 3, "name": "分析判断", "score": 20 }, { "id": 4, "name": "推理想象", "score": 10 }, { "id": 5, "name": "语言表达", "score": 20 }] }

    },

Then get these values

                var key0 = _this.data.result.radar_map[0].name
                var score0 = _this.data.result.radar_map[0].score
                var key1 = _this.data.result.radar_map[1].name
                var score1 = _this.data.result.radar_map[1].score
                var key2 = _this.data.result.radar_map[2].name
                var score2 = _this.data.result.radar_map[2].score
                var key3 = _this.data.result.radar_map[3].name
                var score3 = _this.data.result.radar_map[3].score
                var key4 = _this.data.result.radar_map[4].name
                var score4 = _this.data.result.radar_map[4].score

Set the color and fine-tune the position, and draw the data on it

                ctx.fillStyle = '#666666'
                ctx.fillText(key0, p0x - 20, p0y - r - 10 - 15)
                ctx.fillText(key1, p0x + r + 10, p0y - p1y - 10)
                ctx.fillText(key2, p0x + p2x + 10, p0y + p2y + 10)
                ctx.fillText(key3, p0x - p3x - 60, p0y + p3y + 10)
                ctx.fillText(key4, p0x - p4x - 60, p0y - p4y - 10)

                ctx.fillStyle = '#EB3722'
                ctx.fillText(' ' + score0, p0x - 20 + 15, p0y - r - 10 - 15 + 15)
                ctx.fillStyle = '#000AFF'
                ctx.fillText(' ' + score1, p0x + r + 10 + 15, p0y - p1y - 10 + 15)
                ctx.fillStyle = '#EB22D7'
                ctx.fillText(' ' + score2, p0x + p2x + 10 + 15, p0y + p2y + 10 + 15)
                ctx.fillStyle = '#32EB22'
                ctx.fillText(' ' + score3, p0x - p3x - 60 + 15, p0y + p3y + 10 + 15)
                ctx.fillStyle = '#EBA722'
                ctx.fillText(' ' + score4, p0x - p4x - 60 + 15, p0y - p4y - 10 + 15)
                ctx.stroke()

Finally, set the fill color and line color, and calculate the proportion. My requirement is that each item should be at most 20.

                ctx.beginPath()
                ctx.fillStyle = '#EB372280';
                ctx.strokeStyle = '#EB3722'

                var pp0y = p0y - r * score0 / 20
                var pp0x = p0x
                ctx.moveTo(pp0x, pp0y)
                var pp1y = r * sin(PI / 180 * 18) * score1 / 20
                var pp1x = r * cos(PI / 180 * 15) * score1 / 20

                ctx.lineTo(p0x + pp1x, p0y - pp1y)
                ctx.stroke()
                var pp2y = r * sin(PI / 180 * 54) * score2 / 20
                var pp2x = r * cos(PI / 180 * 54) * score2 / 20


                ctx.lineTo(p0x + pp2x, p0y + pp2y)
                ctx.stroke()
                var pp3y = r * sin(PI / 180 * 54) * score3 / 20
                var pp3x = r * cos(PI / 180 * 54) * score3 / 20


                ctx.lineTo(p0x - pp3x, p0y + pp3y)
                ctx.stroke()
                var pp4y = r * sin(PI / 180 * 18) * score4 / 20
                var pp4x = r * cos(PI / 180 * 15) * score4 / 20

                ctx.lineTo(p0x - pp4x, p0y - pp4y)
                ctx.stroke()
                ctx.lineTo(pp0x, pp0y)
                ctx.stroke()
                ctx.fill()
                ctx.closePath()

At this point, the drawing is almost inseparable.

The effect is as follows:

in conclusion,

1. Understand the coordinate system of canvas

2. Understand Math.cos and Math.sin 

3. To configure different stroke colors, wrap them with beginPath() and closePath()

4. In the WeChat API demonstration, setStrokeStyle(), setLineWidth(), and setFillStyle() must all be changed to strokeStyle='', lineWidth='', and fillStyle=''.

I personally think that the fourth point is the most confusing, because the previous questions are all documented.

Okay, this is the end of the novice operation.

Welcome everyone’s criticism and correction!

Guess you like

Origin blog.csdn.net/u010055598/article/details/132407110