Canvas动画

Canvas动画


在 canvas 上绘制内容是用 canvas 提供的或者自定义的方法,而通常我们仅仅在脚本执行结束后才能看见结果,所以想在 for 循环里面完成动画是不可能的。那么为了实现动画,我们需要一些可以定时执行重绘的方法。

setInterval(function, delay)
定时器,当设定好间隔时间后,function 会定期执行。

setTimeout(function, delay)
延时器,在设定好的时间之后执行函数

requestAnimationFrame(callback)
告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画。

如果不需要与用户互动,可以使用 setInterval() 方法,它可以定期执行指定的代码。
如果需要做游戏,可以使用键盘或者鼠标事件配合上 setTimeout() 方法来实现。
通过设置事件监听,可以捕捉用户的交互,并执行相应的动作。

requestAnimationFrame()方法提供了更加平缓且有效率的方式来执行动画,当系统准备好重绘条件后才会调用绘制动画帧。一般每秒钟回调函数执行 60 次,也有可能会被降低

因为通常情况下requestAnimationFrame()方法会遵循 W3C 的建议,浏览器中的回调函数执行次数通常与浏览器屏幕刷新次数相匹配。
还有为了提高性能和电池寿命,通常 requestAnimationFrame() 方法运行在后台标签页或者隐藏时,requestAnimationFrame() 方法会暂停调用以提升性能和电池寿命。

总结一下绘制动画的基本步骤

  • 清空 canvas:除非接下来要画的内容会完全充满 canvas(例如背景图),否则需要清空所有。最简单的做法就是用 clearRect 方法。
  • 保存 canvas 状态:如果要改变 canvas 状态的设置(样式,变形之类的),之后又要在每画一帧之时都是原始状态的情况时,需要先保存一下。
  • 绘制动画图形(animated shapes)
  • 恢复 canvas 状态:如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。



const canvas = document.querySelector('.canvas')
    const sun = new Image()
    const moon = new Image()
    const earth = new Image()
    let time = +new Date()
    if (canvas.getContext) {
        const ctx = canvas.getContext('2d')
        ctx.globalCompositeOperation = 'destination-over'
        const init  = () => {
            sun.src = './doc/imgLib/else/sun.png'
            moon.src = './doc/imgLib/else/moon.png'
            earth.src = './doc/imgLib/else/earth.png'
            window.requestAnimationFrame(draw)
        }
        const draw = () => {
            ctx.clearRect(0, 0, 500, 500)
            ctx.fillStyle = "rgba(3, 3, 3, 0.1)"
            ctx.strokeStyle = "rgba(0, 0, 0, 0.1)"
            ctx.save()
            ctx.save()
            ctx.save()
            const nowTime = +new Date()
            const decSec = nowTime - time
            
            ctx.beginPath()
            ctx.translate(250, 250)
            ctx.rotate(Math.PI * 2 / 6000 * decSec)
            ctx.translate(200, 0)
            ctx.drawImage(earth, 20 , 20, 300, 300, -30, -30, 60, 60)
            // ctx.restore()


            ctx.beginPath()
            // ctx.translate(250, 250)
            ctx.rotate(Math.PI * 2 / 2000 * decSec)
            ctx.translate(60, 0)
            ctx.drawImage(moon, 20 , 20, 300, 300, -20, -20, 40, 40)
            ctx.restore()



            ctx.translate(250, 250)
            ctx.beginPath()
            ctx.arc(0, 0, 200, 0, Math.PI * 2, false);
            ctx.drawImage(sun, 20 , 20, 300, 300, -40, -40, 80, 80)
            ctx.stroke()
            ctx.restore()

            window.requestAnimationFrame(draw)
            
        }
        init()
        
    }



高级动画

在初级动画的基础上加上一些符合物理的运动,这样就能使动画更生动

const canvas = document.querySelector('.canvas')
    if (canvas.getContext) {
        const ctx = canvas.getContext('2d')
        const init  = () => {
            window.requestAnimationFrame(draw)
        }
        const ball = {
            x: 50,
            y: 50,
            vx: 1,
            vy: 3,
            radius: 20,
            speed: .25,
            color: "rgba(3, 3, 3, 0.1)",
            draw: function() {
                ctx.beginPath()
                ctx.fillStyle = this.color
                ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false)
                ctx.closePath()
                ctx.fill()
            }
        }
        const draw = () => {
            // ctx.clearRect(0, 0, 500, 500)
            // 用带透明度的矩形代替清空就可以保留上一次运动的痕迹
            ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
            ctx.fillRect(0, 0, canvas.width, canvas.height)
            ctx.save()

            ball.draw()

            ball.y += ball.vy
            ball.x += ball.vx

            ball.vy = ball.vy * .99
            ball.vx = ball.vx * .9995
            
            ball.vy += ball.speed
            ball.speed = ball.speed - .0002 > 0 ? ball.speed - .0002: 0
            if(ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0){
                ball.vy = -ball.vy
            }
            if(ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0){
                ball.vx = -ball.vx
            }

            ctx.restore()
            window.requestAnimationFrame(draw)        
        }
        init()
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Raccom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值