canvas

202 阅读3分钟

一:画直线

1.使用canvas标签---HTML

<canvas width="500px" height = '500px'>您的浏览器暂不支持canvas标签,请更换浏览器</canvas>

canvas标签里面的内容会在浏览器不兼容canvas的情况下进行显示

使用js操控canvas---JavaScript

    // 获取画布
    let canvas = document.querySelector('canvas')
    // 获取画布的上下文
    let ctx = canvas.getContext('2d')
    // 开始一条路径
    ctx.beginPath()
    // 确定起始点
    ctx.moveTo(100,100)
    // 确定结束点
    ctx.lineTo(400,100)
    // 着色
    ctx.stroke()
    // 结束路径
    ctx.closePath()

image-20210924085101103.png

二、设置颜色和宽

我们只需要在着色之前 改变画笔的颜色

    // 在着色之前设置颜色和线宽
    ctx.strokeStyle = 'red'   // 设置颜色
    ctx.lineWidth = 5   		// 设置线的宽度
	// 着色
    ctx.stroke()

image-20210924085334711.png

三、画矩形

    // rect矩形
    // x,y,宽,高
    ctx.rect(100,100,300,200)
    // 描边
    ctx.strokeStyle = 'red'
    ctx.lineWidth = 5
    // 填充,一定先填充,后进行着色边框
    ctx.fillStyle = 'pink'  // 填充颜色
    ctx.fill()
    ctx.stroke()

image-20210924085802231.png

四、画统计图

    let ctx = canvas.getContext('2d')
    // 画线
    ctx.beginPath()
    ctx.moveTo(100,100)
    ctx.lineTo(100,400)
    ctx.lineTo(400,400)
    ctx.stroke()
    // 画矩形
    ctx.fillStyle = 'red'
    ctx.fillRect(200,200,20,200)
    ctx.stroke()

image-20210924090340246.png

随机画统计图

    let canvas = document.querySelector('canvas')
    let ctx = canvas.getContext('2d')
    // 画线
    ctx.beginPath()
    ctx.moveTo(100,100)
    ctx.lineTo(100,400)
    ctx.lineTo(400,400)
    ctx.stroke()
    // 画矩形
    for (let i = 0; i < 6; i++) {
        // 随机一个高度
        let height =Math.floor( Math.random() * 280 + 10)
        // 随机一个颜色
        ctx.fillStyle = '#' + parseInt(Math.random() * 0xffffff).toString(16)
        ctx.fillRect(120 + 40 * i,400 - height ,20,height)
    }

image-20210925193434176.png

五、案例

    let canvas = document.querySelector('canvas')
    let ctx = canvas.getContext('2d')
    // 1,画一张填充矩形
    ctx.fillRect(20,20,100,100)
    // 2,清除画布
    ctx.clearRect(40,40,60,60)
    // 3,画一个着边的矩形,不填充内部只有边框
    ctx.strokeRect(50,50,40,40)

image-20210924090354519.png

六、绘制三角形

    ctx.beginPath()
    // 起点。第一个点
    ctx.moveTo(50,50)
    // 第二个点
    ctx.lineTo(100,100)
    // 第三个点
    ctx.lineTo(100,0)
    // 填充实心
    // ctx.fill()
    // 接到起始点 or 自动闭合
    // ctx.lineTo(50,50)
    ctx.closePath()

    ctx.stroke()

image-20210924091812967.png

七、圆的组成

    // 圆的组成:
    // 圆心(x,y)
    // 开始角度
    // 结束角度
    // 顺时针/逆时针

    ctx.strokeStyle = 'orange'
    ctx.lineWidth = 10
    // 画圆
    // x,y,半径,开始角度(默认三点钟方向),最后的具体角度,是否顺时针
    // ctx.arc(x,y,radius,startAngle,endAngle,anticlockwise)
    // ctx.arc(300,300,100,0,Math.PI,true)
    ctx.arc(300,300,100,0,Math.PI/2,false)
    ctx.stroke()

八、循环建圆

    for (let i = 0; i < 4; i++){
        for (let j = 0; j < 3; j++){
            ctx.beginPath()
            let x = 25 + j *80
            let y = 25 + i * 80
            let radius = 20
            let startAngel = 0
            let endAngel = Math.PI + (Math.PI * j) / 2
            let flag = (i % 2) === 0 ? false : true
            ctx.arc(x,y,radius,startAngel,endAngel, flag)
            if (i < 2){
                ctx.stroke()
            }else {
                ctx.fillStyle = 'pink'
                ctx.fill()
            }
        }
    }

image-20210924104657227.png

九、画茶杯

let canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')
// 画杯身
ctx.lineWidth = 2
ctx.strokeRect(100,200,200,200)
// 画把手
drawCircle(300,300,50,6,false)
// 热气
// drawCircle(140,120,20,1,true)
// drawCircle(140,160,20,1,false)
//
// drawCircle(180,120,20,1,true)
// drawCircle(180,160,20,1,false)
//
// drawCircle(220,120,20,1,true)
// drawCircle(220,160,20,1,false)
//
// drawCircle(260,120,20,1,true)
// drawCircle(260,160,20,1,false)
// 使用循环
for (let i = 0; i < 4; i++) {
    drawCircle(140 + i * 40,120,20,1,true)
    drawCircle(140 + i * 40,160,20,1,false)
}
function drawCircle(x, y, r,width,flag){
    ctx.beginPath()
    ctx.arc(x, y, r,-Math.PI/2,Math.PI/2,flag)
    ctx.lineWidth = width
    ctx.stroke()
}

image-20210926193155549.png

十、圆形统计图

let canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')

let deg = Math.PI*2/360
let count = 1

let timer = setInterval(() => {
    count++
    ctx.beginPath()
    // 从是12点方向开始
    ctx.arc(250, 250, 200,-Math.PI/2,count*deg - Math.PI/2,false)
    ctx.lineWidth = 2
    ctx.stroke()
    if (count === 360) clearInterval(timer)
},10)

image-20210926193244836.png

十一、碰撞检测

let canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')
// 定义x y 半径
let x = 100
let y = 30
let r = 30
// 画布的宽高
let h = w = 500
// 控制小球速度
let xSpeed = 1
let ySpeed = 3
setInterval(function () {
    // 清除画布
    ctx.clearRect(0, 0, w, h)
    x += xSpeed
    y += ySpeed
    // 当球到达边界时,进行更改
    if (x - r <= 0 || x + r >= w){
        xSpeed = -xSpeed
    }
    if (y - r <= 0 || y + r >= h){
       ySpeed = -ySpeed
    }
    drawCircle(x, y, r)
}, 0)
function drawCircle(x, y, r) {
    ctx.beginPath()
    ctx.arc(x, y, r, 0, Math.PI * 2)
    ctx.fillStyle = 'pink'
    ctx.fill()
}

上面代码使用的是定时器,使用定时器会有卡顿的效果

那么bom提供了一个方法

window.requestAnimationFrame()

参数填方法名,下面是把定时器替换掉后的函数

  function test(){
        // 清除画布
        ctx.clearRect(0, 0, w, h)
        x += xSpeed
        y += ySpeed
        // 当球到达边界时,进行更改
        if (x - r <= 0 || x + r >= w){
            xSpeed = -xSpeed
        }
        if (y - r <= 0 || y + r >= h){
            ySpeed = -ySpeed
        }
        drawCircle(x, y, r)
        window.requestAnimationFrame(test)
    }
    test()

十二、面向对象的小球

    let canvas = document.querySelector('canvas')
    let ctx = canvas.getContext('2d')

    // 画布的宽高
    let h = w = 500
    /**
     * 面向对象
     */
    function r(num){
        return Math.random()*num
    }

    /**
     * @param x     起始x坐标
     * @param y     起始y坐标
     * @param color 小球半径
     * @param xSpeed x轴速度
     * @param ySpeed y轴速度
     * @constructor
     */
    function Ball(){
        // this.x = r(500)
        // this.y = r(500)
        this.x = r(50)+60
        this.y = r(300)+60

        this.r = r(50) + 10 // [10 - 60]

        this.color = '#' + parseInt(Math.random() * 0xffffff).toString(16)
        this.xSpeed = r(5)
        this.ySpeed = r(5)

    }
    // 定义小球显示方法
    Ball.prototype.show = function (){
        ctx.beginPath()
        ctx.arc(this.x,this.y,this.r,0,Math.PI*2)
        ctx.fillStyle = this.color
        ctx.fill()
    }

    // 定义小球运动(碰撞检测)
    Ball.prototype.run = function (){
        // 当球到达边界时,进行更改
        if (this.x - this.r <= 0 || this.x + this.r >= w){
            this.xSpeed = -this.xSpeed
        }
        this.x = this.x + this.xSpeed
        if (this.y - this.r <= 0 || this.y + this.r >= w){
            this.ySpeed = -this.ySpeed
        }
        this.y = this.y + this.ySpeed
    }
    // 存放小球的数组
    let ballArr = []
    // 创建一个小球
    for (let i = 0; i < 30; i++) {
        let ball = new Ball()
        ballArr.push(ball)
        ball.show()
    }
    console.log(ballArr)
    // 小球运动
    setInterval(function () {
        // ctx.clearRect(0,0,w,h)
        // for (let i = 0; i < ballArr.length; i++) {
        //     let ball = ballArr[i]
        //     // 更新坐标 显示小球
        //     ball.run()
        //     ball.show()
        // }
    },10)
    function test(){
        ctx.clearRect(0,0,w,h)
        for (let i = 0; i < ballArr.length; i++) {
            let ball = ballArr[i]
            // 更新坐标 显示小球
            ball.run()
            ball.show()
        }
    window.requestAnimationFrame(test)
    }
    test()

十三、画文字

// 获取画布
let canvas = document.querySelector('canvas')
// 获取画布的上下文
let ctx = canvas.getContext('2d')

// 设置字体相关样式
ctx.font = '100px 宋体'
ctx.fillStyle = 'red'
// 绘制实心文字
ctx.fillText('hello',250,250)
// 绘制空心文字
ctx.strokeText('你好',0,250)

ctx.font = '100px 宋体'
ctx.fillText('hello canvas!',100,100,400) // 限制宽度

image-20210928192012272.png

十四、渐变文字

// 获取画布
let canvas = document.querySelector('canvas')
// 获取画布的上下文
let ctx = canvas.getContext('2d')

// 设置字体相关样式
ctx.font = '100px 宋体'

// 设置线性渐变
let gradient = ctx.createLinearGradient(0,0,500,0)
gradient.addColorStop(0,'yellow')
gradient.addColorStop(0.5,'blue')
gradient.addColorStop(1,'red')
// 填充
ctx.fillStyle = gradient
ctx.fillText('今天天气很好,你有想我吗?',0,100,500)
ctx.strokeStyle = gradient
ctx.strokeText('炸鸡很好吃,但是它热量很高',0,200,500)

image-20210928192100800.png

十五、文字位置

// 获取画布
let canvas = document.querySelector('canvas')
// 获取画布的上下文
let ctx = canvas.getContext('2d')
// 画直线
ctx.beginPath()
ctx.moveTo(250,0)
ctx.lineTo(250,500)
ctx.closePath()
ctx.stroke()
ctx.beginPath()
ctx.moveTo(0,250)
ctx.lineTo(500,250)
ctx.closePath()
ctx.stroke()
// 设置字体相关样式
ctx.font = '100px 宋体'
/***
 * 水平文字的属性值textAlign:start end left right
 * 垂直文字的属性值textBaseline = top bottom middle
 */
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText('HTML5',250,250)

image-20210928192135660.png

十六、米字格

    // 获取画布
    let canvas = document.querySelector('canvas')
    // 获取画布的上下文
    let ctx = canvas.getContext('2d')

    // 1:画垂直和水平线
    drawLine(0, 250, 500, 250)
    drawLine(250, 0, 250, 500)
    // 画斜线
    // 方法一
    // for (let i = 0; i < 50; i++) {
    //     drawLine(i * 10, i * 10, i * 10 + 5, i * 10 + 5,'red')
    //     drawLine(500-i*10,i*10,500-(i*10+5),i*10+5,'red')
    // }
    // 方法二
    ctx.setLineDash([5,5])
    drawLine(0,0,500,500,"red")
    drawLine(500,0,0,500,"red")
    // 画字
    drawText('米', 250, 250)

    /***
     * 画直线方法
     */
    function drawLine(x1, y1, x2, y2, color) {
        ctx.beginPath()
        ctx.moveTo(x1, y1)
        ctx.lineTo(x2, y2)
        ctx.strokeStyle = color || '#000'
        ctx.stroke()
        ctx.closePath()
    }

    /***
     * 画文字
     */
    function drawText(text, x, y) {
        ctx.font = '400px 宋体'
        ctx.textAlign = 'center'
        ctx.textBaseline = 'middle'
        ctx.fillText(text, x, y)
    }

image-20210929085755349.png

十七、绘制图片

// 获取画布
let canvas = document.querySelector('canvas')
// 获取画布的上下文
let ctx = canvas.getContext('2d')
let img = new Image()
img.src = 'sxb.jpg'

/***
 * onload:图片加载成功后触发
 * onerror:图片加载失败后触发
 */
img.onload = function (e){
    // 获取当前图片的实际宽高
    console.log(img.width,img.height)
    /**
     * 1.在画布上定位图像
     * content.drawImage(img,x,y)
     * 2.在画布上定位图像,并规定图像的宽度和高度
     * content.drawImage(img,x,y,width,height)
     * 3.剪切图像,并在画布上定位被剪切的部分
     * context. drawImage( ing,sx,sy,swidth, sheight,x ,y ,width, height);
     * img 规定要使用的图像、画布或视频。
     * Sx可选。开始剪切的X坐标位置。
     * sy可选。开始剪切的y坐标位置。
     * swidth可选。 被剪切图像的宽度。
     * sheight可选。被剪切图像的高度。
     * x在画布上放置图像的X坐标位置。
     * y在画布上放置图像的y坐标位置。
     * width可选。 要使用的图像的宽度。( 伸展或缩小图像)
     * height可选。要使用的图像的高度。(伸展或缩小图像)
     */
    // 1
    // ctx.drawImage(img,0,0)
    // 2
    // ctx.drawImage(img,0,0,100,100)
    // 3
    ctx.drawImage(img,40,20,160,160,150,150,200,200)
}

十八、线性小球

// 获取画布
let canvas = document.querySelector('canvas')
// 获取画布的上下文
let ctx = canvas.getContext('2d')

// 画布的宽高
let h = 500, w = 500

// 随机数
function r(num) {
    return Math.random() * num
}

/**
 * @param x     起始x坐标
 * @param y     起始y坐标
 * @param color 小球半径
 * @param xSpeed x轴速度
 * @param ySpeed y轴速度
 * @constructor
 */
function Ball(text) {
    this.x = r(380) + 60 // [60,440]
    this.y = r(380) + 60 // [60,440]

    this.r = r(50) + 10 // [10,60]
    this.color = '#' + parseInt(Math.random() * 0xffffff).toString(16)
    this.xSpeed = r(5)
    this.ySpeed = r(5)
    // 接收外部参数
    this.text = text
}

Ball.prototype.show = function () {
    this.run()  // 更新坐标
    drawCir(this.x, this.y, this.r, this.color)  // 画小球
    drawText(this.text, this.x + this.r, this.y) // 画文字
}
// 定义小球运动(碰撞检测)
Ball.prototype.run = function () {
    // 当球到达边界时,进行更改
    if (this.x - this.r <= 0 || this.x + this.r >= w) {
        this.xSpeed = -this.xSpeed
    }
    this.x = this.x + this.xSpeed
    if (this.y - this.r <= 0 || this.y + this.r >= w) {
        this.ySpeed = -this.ySpeed
    }
    this.y = this.y + this.ySpeed
}

/**
 * 画直线
 * @param x1
 * @param y1
 * @param x2
 * @param y2
 * @param color
 */
function drawLine(x1, y1, x2, y2, color) {
    ctx.beginPath()
    ctx.moveTo(x1, y1)
    ctx.lineTo(x2, y2)
    ctx.strokeStyle = color || '#000'
    ctx.stroke()
    ctx.closePath()
}

/**
 * 画文字
 * @param text
 * @param x
 * @param y
 */
function drawText(text, x, y) {
    ctx.font = '16px 微软雅黑'
    ctx.textAlign = 'start'
    ctx.textBaseline = 'middle'
    ctx.fillText(text, x, y)
}

/**
 * 画圆
 * @param x
 * @param y
 * @param r
 * @param color
 */
function drawCir(x, y, r, color) {
    this.color = color
    ctx.beginPath()
    ctx.arc(x, y, r, 0, Math.PI * 2)
    ctx.fillStyle = this.color
    ctx.fill()
}

let titleArr = 'javascript HTML5前端 JAVA PHP Jquery Cnavas css css3 Angular Bootstrap'.split(' ')
console.log(titleArr)
// 存放小球
let ballArr = []
for (let i = 0; i < 5; i++) {
    // 当前小球
    let ball = new Ball(titleArr[i]) // 传入title
    ballArr.push(ball)
    ball.show()
}

//小球运动
function ballRun() {
    ctx.clearRect(0, 0, w, h)
    for (let i = 0; i < ballArr.length; i++) {
        ballArr[i].show()
        /**
         * 小球连线 a球和b球
         */
        for (let j = 0; j < i; j++) {
            // 取出当前小球前面的小球
            let prevBall = ballArr[j]
            console.log(prevBall)
            drawLine(ballArr[i].x, ballArr[i].y, prevBall.x, prevBall.y, ballArr[i].color)
        }
    }
    window.requestAnimationFrame(ballRun)
}
ballRun()

image-20210930112152467.png

十九、鼠标幻彩小球

HTML:

<canvas></canvas>

JavaScript:

// 获取画布
let canvas = document.querySelector('canvas')
// 获取画布的上下文
let ctx = canvas.getContext('2d')

// 获取窗口可视区域宽高
let w = document.documentElement.clientWidth - 6
let h = document.documentElement.clientHeight - 6
console.log(w, h)
// 更新canvas宽高
canvas.width = w
canvas.height = h

/**
 * @param x     起始x坐标
 * @param y     起始y坐标
 * @param color 小球半径
 * @constructor
 */
function Ball(x, y) {
    this.x = x
    this.y = y

    this.r = 30
    // 随机颜色
    this.color = '#' + parseInt(Math.random() * 0xffffff).toString(16)
}

Ball.prototype.show = function () {
    // 半径越来越小
    this.r--
    drawCir(this.x, this.y, this.r, this.color)  // 画小球
}

// 小球数组
let ballArr = []

// 鼠标滑动事件
document.onmousemove = function (e) {
    let ball = new Ball(e.x, e.y)
    ballArr.push(ball)
    ball.show()
}

/**
 * 画圆
 * @param x
 * @param y
 * @param r
 * @param color
 */
function drawCir(x, y, r, color) {
    this.color = color
    ctx.beginPath()
    ctx.arc(x, y, r, 0, Math.PI * 2)
    ctx.fillStyle = this.color
    ctx.fill()
}

setInterval(() => {
    ctx.clearRect(0, 0, w, h)
    for (let i = 0; i < ballArr.length; i++) {
        /**
         * 判断:如果小球半径r小于0 就要从数组中删除
         */
        if (ballArr[i].r <= 0) {
            ballArr.splice(i, 1)
        } else {
            ballArr[i].show()
        }

    }
}, 10)