简单的匀速直线动画
canvas的动画还是离不开js的定时器机制
js定时器主要分为两种
- 1.setInterval (这个就不介绍了)
- 2.window.requestAnimationFrame
window.requestAnimationFrame (推荐使用)
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
当你准备更新动画时你应该调用此方法。这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数(即你的回调函数)。回调函数执行次数通常是每秒60次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。
范例
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);
复制代码
做一个小球的匀速运动
<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,那么这样我们可以得到一个变速运动的小球
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) // 结束动画
}
})()
}
复制代码
画一个简单的摆球(考虑无摩擦力情况,小球能一直运行下去,因重力影响,小球一直做减速运动)
因小球不是做变加速直线运动,(有点复杂,所有我们模拟成均加速直线运动)
初始化钟摆图形
// 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)
}
})()
},
复制代码
太阳系运动
初始化太阳
// 初始化太阳
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 各种福利多、加班少。 摸鱼干活。