canvas-简单的动画

简单的匀速直线动画

canvas的动画还是离不开js的定时器机制

js定时器主要分为两种

  • 1.setInterval (这个就不介绍了)
  • 2.window.requestAnimationFrame

window.requestAnimationFrame (推荐使用)

告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
当你准备更新动画时你应该调用此方法。这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数(即你的回调函数)。回调函数执行次数通常是每秒60次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。

范例

引用自MDN developer.mozilla.org/zh-CN/docs/…

const element = document.getElementById('some-element-you-want-to-animate');
let start;

function step(timestamp) {
  if (start === undefined)
    start = timestamp;
  const elapsed = timestamp - start;

  //这里使用`Math.min()`确保元素刚好停在200px的位置。
  element.style.transform = 'translateX(' + Math.min(0.1 * elapsed, 200) + 'px)';

  if (elapsed < 2000) { // 在两秒后停止动画
    window.requestAnimationFrame(step);
  }
}

window.requestAnimationFrame(step);
复制代码

做一个小球的匀速运动

1112.gif

<canvas id="tutorial" width="1260px" height="800px" ref="canvas" style="border: 1px solid #999;"></canvas>

初始化canvas (使用的vue语法)
// 获取canvas元素 this.canvas = document.getElementById('tutorial') // 获取绘制二维上下文 this.ctx = this.canvas.getContext('2d')

使用canvas画一个小球

        // vx 代表水平x的左边
        initcanvascircle(vx) {
            this.ctx.fillStyle = '#EEEEEE'
            this.ctx.fillRect(0, 0, 1260, 800)
            this.ctx.strokeStyle = '#000000'
            this.ctx.strokeRect(1, 1, 1258, 798)
            // 开始绘制图形
            this.ctx.beginPath()
            this.ctx.fillStyle = 'HotPink'
            this.ctx.arc(vx, 100, 30, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.fill()
        }
复制代码

定义小球的运动动画


        startevent() {
            var easing = 1 //运动速率
            let nvx = 100
            let self = this
            ;(function frame() { // 自执行函数写法,防止全局变量污染
                let globalID = window.requestAnimationFrame(frame)
                nvx = nvx + easing
                if (nvx < 700) {
                    // self.ctx.clearRect(0, 0, 800, 800)
                    self.initcanvascircle(nvx)
                } else {
                   window.cancelAnimationFrame(globalID) // 结束动画
                }
            })()
        },
复制代码

简单的变速直线运动

小球的运动速率是剩余距离的百分之一,因为剩余距离越来越短,所最终速度为趋向于0,那么这样我们可以得到一个变速运动的小球

11123.gif

    startevent2() {
            let nvx = 100
            let self = this
            ;(function frame() {
                // 自执行函数写法,防止全局变量污染
                let globalID = window.requestAnimationFrame(frame)
                nvx = nvx + (700 - nvx) * 0.01
                if (nvx < 700) {
                    // self.ctx.clearRect(0, 0, 800, 800)
                    self.initcanvascircle(nvx)
                } else {
                    window.cancelAnimationFrame(globalID) // 结束动画
                }
            })()
        }
复制代码

画一个简单的摆球(考虑无摩擦力情况,小球能一直运行下去,因重力影响,小球一直做减速运动)

因小球不是做变加速直线运动,(有点复杂,所有我们模拟成均加速直线运动)

初始化钟摆图形

111234.gif

// degree 初始钟摆角度
initcanvasZb(degree) {
            let x = 400 + 200 * Math.cos(degree)
            let y = 100 + 200 * Math.sin(degree)
            // 绘制背景
            /* this.ctx.fillStyle = '#EEEEEE'
            this.ctx.fillRect(0, 0, 1260, 800)
            this.ctx.strokeStyle = '#000000'
            this.ctx.strokeRect(1, 1, 1258, 798) */
            this.ctx.clearRect(0, 0, 1260, 800)
            // 开始绘制图形 小球
            this.ctx.beginPath()
            this.ctx.fillStyle = 'HotPink'
            this.ctx.arc(x, y, 50, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.fill()
            // 开始绘制图形 摆线
            this.ctx.strokeStyle = 'HotPink'
            this.ctx.moveTo(400, 100)
            this.ctx.lineTo(x, y)
            this.ctx.stroke()
        },
复制代码

定义钟摆动画,初始角度,初始速度,加速度

注意的一些点, 1.临界值, 2.图形一定要先画圆,调用fill()方法,


startevent3() {
            let nvx = 60 // 初始角度
            let speed = 0 // 初始速度
            let aspeed = 0.01 // 初始加速度
            let self = this
            ;(function frame() {
                // 自执行函数写法,防止全局变量污染
                let globalID = window.requestAnimationFrame(frame)
                if (nvx >= 60 && nvx < 90) {
                    // 临界值判断
                    if (speed < 0 && nvx + speed < 60) {
                        speed = 0
                        nvx = 60
                    } else {
                        speed += aspeed
                        nvx = nvx + speed
                    }
                    // self.ctx.clearRect(0, 0, 800, 800)
                    self.initcanvasZb((nvx * Math.PI) / 180)
                } else if (nvx >= 90 && nvx <= 120) {
                    if (speed > 0 && nvx + speed > 120) {
                        speed = 0
                        nvx = 120
                    } else {
                        speed -= aspeed
                        nvx = nvx + speed
                    }
                    self.initcanvasZb((nvx * Math.PI) / 180)
                }
            })()
        },

复制代码

太阳系运动

1112345.gif

初始化太阳
    // 初始化太阳
        initSun() {
            this.ctx.beginPath()
            this.ctx.arc(300, 300, 50, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.fillStyle = 'HotPink'
            this.ctx.fill()
        },
复制代码
初始化地球运动轨迹
// 初始化地球轨迹
        initEarthgj() {
            this.ctx.beginPath()
            this.ctx.arc(300, 300, 200, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.strokeStyle = '#e01f15'
            this.ctx.stroke()
        },

复制代码
初始化地球
// 初始化地球
        initEarth(addindex) {
            this.ctx.beginPath()
            let x = 300 + Math.cos((addindex * Math.PI) / 720) * 200
            let y = 300 + Math.sin((addindex * Math.PI) / 720) * 200
            this.ctx.arc(x, y, 20, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.fillStyle = '#987b7b'
            this.ctx.fill()
            this.initMouthgj(x, y)
            this.initMouth(x, y, addindex)
        },
复制代码
绘制月球的轨迹 初始化月球

//绘制月球的轨迹
        // 初始化月球
        initMouthgj(x, y) {
            this.ctx.beginPath()
            this.ctx.arc(x, y, 50, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.strokeStyle = '#ccc'
            this.ctx.stroke()
        },
        initMouth(x, y, addindex) {
            this.ctx.beginPath()
            let x1 = x + Math.cos((addindex * Math.PI) / 360) * 50
            let y1 = y + Math.sin((addindex * Math.PI) / 360) * 50
            this.ctx.arc(x1, y1, 10, (0 * Math.PI) / 180, (360 * Math.PI) / 180, true)
            this.ctx.closePath()
            this.ctx.fillStyle = '#987b7b'
            this.ctx.fill()
        }
复制代码
天体开始运动,定义运动动画
run() {
            // eslint-disable-next-line
            let addindex = 0
            let _self = this
            ;(function goframe() {
                _self.ctx.clearRect(0, 0, 600, 600)
                let globalID = window.requestAnimationFrame(goframe)
                _self.initSun()
                _self.initEarthgj()
                _self.initEarth(addindex)
                if (addindex < 1440) {
                    addindex++
                } else {
                    addindex = 0
                }
            })()
        },

复制代码

上面都是一些简单的canvasl动画

  • 贝塞尔曲线 2次 3次
  • 弹性碰撞,摩擦力碰撞
  • 等等

浙江大华技术股份有限公司-软研-智慧城市产品研发部招聘高级前端,欢迎来撩,有意向可发送简历到chen_zhen@dahuatech.com 各种福利多、加班少。 摸鱼干活。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享