canvas简述(一)

canvas是HTML5推出的画布技术 有2D和3D 目前3D兼容性很差但相信随着VR的兴起 3D也会逐渐发力 目前只讲述关于2D 相关的API 以及 业务逻辑 常用场景 游戏等等

API部分

    <style>
        canvas{
            border:solid 2px red
        }
    </style>
    <canvas id="cvs" width="800" height="800"></canvas>
</head>
<body>
<script>
    //获取canvas以及其上下文对象
    var cvs = document.querySelector('#cvs')
    var ctx = cvs.getContext('2d')

    //开始绘制

    ctx.beginPath()
    ctx.moveTo(200,200)
    ctx.lineTo(200,400)
    ctx.lineTo(100,400)
    ctx.lineWidth = 15
    ctx.closePath()
    ctx.strokeStyle = 'red'
    ctx.fillStyle = 'blue'
    ctx.stroke()
    ctx.fill()
    //上面自己绘制了一个三角形
    
    

</script>

上面自己绘制了一个三角形 在canvas中的路径 良好的习惯每次 绘制结束 都要闭合 每次绘制开始都要重新开启路径 第一步定点 然后 绘制 路径 填充非常简单

下面放canvas绘制矩形 以及 圆弧 以及 绘制图片的API demo

    ctx.fillStyle = 'red'
    ctx.fillRect(200,200,200,200)

    ctx.strokeStyle = 'blue'
    ctx.strokeRect(400,400,400,400)

上面绘制了两个canvas预定义的 实心矩形和 空心矩形

在绘制圆形之前首先要明白canvas 圆形绘制是根据弧度制的 也就是角度跟弧度弧度是成比例的 是什么一个关系 圆的周长 = 2πr  如果将360° 跟 周长划一个关系的话 那么必须提取一个唯一的变量那就是r 在不同大小的圆下r也是不同的 

将r提取出来 周长 / 2π = r   360° / 2π = 57.29° 那么我们就可以说 无论在什么情况下 1r 的弧度就等于 = 57.29° 的角度 那么有了这个对等的关系就非常简单了 我们可以假设360°就是 2π 的弧度 实际上canvas也是这么实现的 这两个是常量 在角度 和 r 有一个对等的比例关系下 可以将其忽略 在这个前提下 那么如果我们要计算30°的弧度是多少就非常简单了 就是360 / 30 * 2π 这样我们就计算出了30 的弧度 下面讲述一下API用法

    //下面是圆弧的绘制
    ctx.arc(200,200,100,0,2 * Math.PI,false)
    ctx.fillStyle = 'red'
    ctx.lineWidth = 10
    ctx.strokeStyle = 'blue'
    ctx.fill()
    ctx.stroke()

在canvas中所有呈现出来的元素立即被像素化 因此无法像DOM一样操作canvas中的元素 只能通过画布帧动画的概念来实现各种动画游戏效果

下面一个圆球动画的简例:

    //获取canvas以及其上下文对象
    var cvs = document.querySelector('#cvs')
    var ctx = cvs.getContext('2d')
    let x = 100,
        x1 = 100,
        x2 = 100
    setInterval(function(){
        x += 20
        x1 += 40
        x2 += 60
        ctx.clearRect(0,0,800,800)
        ctx.beginPath()
        ctx.fillStyle = 'blue'
        ctx.arc(x,100,50,0,2*Math.PI,false)
        ctx.fill()

        ctx.beginPath()
        ctx.fillStyle = 'blue'
        ctx.arc(x1,200,50,0,2*Math.PI,false)
        ctx.fill()

        ctx.beginPath()
        ctx.fillStyle = 'blue'
        ctx.arc(x2,300,50,0,2*Math.PI,false)
        ctx.fill()
    },100)

 在多个元素运动和canvas游戏中一般采用的是 面向对象的方式 接下来用渐进增强的方式慢慢解析 

<script>
    //获取canvas以及其上下文对象
    var cvs = document.querySelector('#cvs')
    var ctx = cvs.getContext('2d')
    //运动元素构造函数
    function Ball (x,y,r,speed){
        this.x = x
        this.y = y
        this.r = r
        this.speed = speed
        actorsAll.push(this)
    }
    const actorsAll = []
    //更新函数
    Ball.prototype.update = function(){
        this.x += this.speed
    }
    //渲染函数
    Ball.prototype.render = function(){
        ctx.beginPath()
        ctx.arc(this.x,this.y,this.r,0,2 * Math.PI,false)
        ctx.fillStyle = 'yellow'
        ctx.fill()
    }
    
    new Ball(100,100,30,1)

    new Ball(100,200,30,2)

    new Ball(100,300,30,3)

    new Ball(100,400,30,4)

    setInterval(function(){
        ctx.clearRect(0,0,800,800)
        actorsAll.forEach(value => {
            value.update()
            value.render()
        })
    })
</script>

使用面向会使代码更加的规整 已读 canvas中运用面向对象是一种非常好的思路

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        canvas{
            border:solid 2px red
        }
    </style>
    <canvas id="cvs" ></canvas>
</head>
<body>
<script>
    //获取canvas以及其上下文对象
    var cvs = document.querySelector('#cvs')
    var ctx = cvs.getContext('2d')

    cvs.width = document.documentElement.clientWidth
    cvs.height = document.documentElement.clientHeight
    //运动元素构造函数
    function Ball(x,y){
        this.x = x
        this.y = y
        this.color = `rgba(${parseInt(Math.random()*256)},${parseInt(Math.random()*256)},${parseInt(Math.random()*256)},0.8)`
        this.r = 30
        this.dx = parseInt(Math.random() * 17) - 8
        this.dy = parseInt(Math.random() * 17) - 8
        actorAll.push(this)
    }
    const actorAll = []
    //渲染函数
    Ball.prototype.render = function(){
        ctx.beginPath()
        ctx.fillStyle = this.color
        ctx.arc(this.x,this.y,this.r,0,2 * Math.PI,false)
        ctx.fill()
    }
    //更新函数
    Ball.prototype.update = function(){
        console.log(this.x)
        console.log(this.y)
        this.x += this.dx
        this.y += this.dy
        this.r --
        if(this.r <= 0){
            this.godie()
        }
    }
    //删除函数
    Ball.prototype.godie = function(){
        actorAll.forEach((value,i) => {
            if(this === value){
                actorAll.splice(i,1)
            }
        })
    }
    cvs.addEventListener('mousemove',function(event){
        new Ball(event.clientX,event.clientY)
    })
    setInterval(function(){
        ctx.clearRect(0,0,cvs.width,cvs.height)
        actorAll.forEach(value => {
            value.update()
            value.render()
        })
    },30)

</script>
</body>
</html>
原文地址:https://www.cnblogs.com/tengx/p/9245651.html