Canvas-绘制圆形

312 阅读4分钟

Canvas绘制圆形

圆形也是开发中常见的图形,本章我将会学习如何和绘制一个圆形,并开发一个在canvas中的圆形跟随鼠标的案例,主要是圆形的内容实在是不多,单独一章内容太少,写入矩形,但又不恰当,基础图形不止圆形一个,所以想了一下,还是单独开一章节加一个案例的形式来写作。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      #container {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <canvas id="container" width="1000" height="600"></canvas>
    <script src="./index.js"></script>
  </body>
</html>

绘制一个基础的圆

context.arc()是canvas提供的一个圆弧绘制工具,可以根据不同的参数绘制出,半圆,整圆,圆弧等图形

const canvas = document.getElementById("container");
const context = canvas.getContext("2d");

context.arc(x, y, radius, startAngle, endAngle, [anticlockwise]);

参数解释:

  • x:圆弧中心(圆心)的 x 轴坐标。
  • y:圆弧中心(圆心)的 y 轴坐标。
  • radius:圆弧的半径,必须为正值
  • startAngle:圆弧的起始点,从 x 轴方向开始计算,以弧度为单位。
  • endAngle:圆弧的终点,从 x 轴方向开始计算,以弧度为单位。
  • anticlockwise:可选的布尔值,如果为true,逆时针绘制圆弧,反之,顺时针绘制。默认为false顺时针。

绘制一个顺/逆时针的圆弧,顺时针路径为一个弧度,逆时针相反,注意(x,y)是圆心距离画布的位置,并非圆的边缘,所以在确定圆的位置的时候,要考虑是否能够显示完整的半径。

// 顺时针
// 起始点0 结束点1 顺时针:图一
context.beginPath();
context.arc(200, 150, 100, 0, 1, false);
context.stroke()

// 起始点0 结束点1 逆时针:图二
context.beginPath();
context.arc(500, 150, 100, 0, 1, true);
context.stroke()

// 顺时针绘制一个大圆弧 起始点1 结束点6 顺时针:图三
context.beginPath();
context.arc(800, 150, 100, 1, 6, false);
context.stroke()

// 绘制一个半圆 顺时针:图四
context.beginPath();
context.arc(200, 450, 100, 0, Math.PI, false);
context.fill()

// 绘制一个半圆 逆时针:图五
context.beginPath();
context.arc(500, 450, 100, 0, Math.PI, true);
context.fill()

// 绘制一个90度的扇形圆弧 顺时针:图六
context.beginPath();
context.arc(800, 450, 100, 0, Math.PI / 2, false);
context.fill()

image.png

解释:

  1. 图一为例,1圆弧约等于57°,完整的弧度为360°,弧度的理解可以参考百度百科弧度
  2. 绘制的起始点默认为0,可以理解为3点钟位置,然后分别顺/逆时针绘制一个圆弧,弧度的表达也可写成圆周率Π即代码表达Math.PI,1Π=180°,可以结合图四参考理解,当然,写成3.14也是正确的,比如3.14 * 2就会绘制一个完成圆,3.14 / 2 就会绘制一个角度为90°的圆弧,这里要注意,fill()并不会补全为一个完整的扇形,因为闭合是以两点划线,也就是开始点和结束点连接,形成闭合。

实现一个跟随鼠标的彩球扩散特效

实现思路:

  1. 绑定canvas的鼠标移动事件
  2. 在鼠标移动时,用定时器改变小球的位置与大小(在退出时记得清除定时器哦)
  3. 将半径小于0的小球删除,因为已经失去了显示的意义,删除可以节省性能
const canvas = document.getElementById("container");
const context = canvas.getContext("2d");
const ballList = [] // 储存圆得实例
let timer = null

class Ball {
    constructor(id, x, y, radius) {
        this.id = id // id
        this.x = x // 距离画布的水平位置
        this.y = y // 距离画布的垂直位置
        this.radius = radius // 半径
        this.moveX = parseInt(Math.random() * 10) - 5 // 每50毫秒移动的距离,如果需要一个扩散的效果,那么就需要一些负数移动所以这里再 -5
        this.moveY = parseInt(Math.random() * 10) - 5
    }
    renderRound() {
        // 渲染圆
        const { x, y, radius } = this
        context.beginPath();
        context.arc(x, y, radius, 0, Math.PI * 2, false);
        const color = this.getRandomColor()
        context.fillStyle = color;
        context.fill()
        context.closePath();
    }
    updateRound() {
        // 更新圆
        this.x += this.moveX // 更新圆得位置
        this.y += this.moveY // 更新圆得位置
        this.radius -= 0.5 // 更新圆的大小
        if (this.radius <= 0) {
            // 半径小于0,直接删除当前得实例
            this.removeRound()
        } else {
            // 渲染圆
            this.renderRound()
        }
    }
    removeRound() {
        // 删除圆
        for (let i = 0; i < ballList.length; i++) {
            if (this.id === ballList[i].id) {
                ballList.splice(i, 1)
            }
        }
    }
    getRandomColor() {
        // 获取随机颜色
        const colorStr = '1,2,3,4,5,6,a,b,c,d,e,f'
        const colorSplit = colorStr.split(',')
        let color = '#'
        for (let i = 0; i < 6; i++) {
            const r = parseInt(Math.random() * colorSplit.length)
            color += colorSplit[r]
        }
        return color
    }
}

canvas.addEventListener('mousemove', function (event) {
    // 鼠标每次移动时,创建一个圆
    const id = new Date().getTime() * parseInt(Math.random() * 10)
    const ball = new Ball(id, event.offsetX, event.offsetY, 20)
    ballList.push(ball)
})


timer = setInterval(() => {
    context.clearRect(0, 0, canvas.width, canvas.height);
    for (let i = 0; i < ballList.length; i++) {
        if (ballList[i]) {
            ballList[i].updateRound()
        }
    }
}, 50);

// // 根据需要清除定时器
// clearInterval(timer)

oory2-838wc.gif

结尾

本章节我们再次回顾了canvas面向对象的编程思维,所用到的也是之前章节的部分技术,我们在学习圆形绘制的时候,可能通过文字表达,会有一些生涩难懂,也有可能是我表达的不够准确,望见谅,有好的建议和希望我加入的其他抒写方式,也可以私我,合适的话我调整,争取能写出通俗能懂得文章。

感谢观看!!!