这是在微信小程序中的代码,部分API有点不同。网页端需要对canvas做一些兼容。
canvas画布大小为180px*180px,按钮为半径65px的圆形,第一次接触canvas,做的时候不知道有requestAnimationFrame来专门制作动画,使用了setTimeout来画动画帧。后面补充使用requestAnimationFrame的例子,当然这么好用的东西微信肯定不会支持的…
示例看这里!
没有使用requestAnimationFrame, 快速点击按钮时会出现卡顿,丢帧的情况。
class Animate{
constructor(id){
this.ctx = {}
this.id = id
//起始半径
this.r = 65
//扩散长度
this.long = 30
//起始透明度
this.opacity = 1
//结束透明度
this.end_opacity = 0
this.step_r = 0
this.step_opacity = 0
this.center = [90, 90]
this.size = [180, 180]
this.fps = 20
//帧间隔
this.frame_interval = 0
//一个扩散持续的时间,单位为ms
this.interval = 800
//绘制数组
this.DRAW_ARR = []
//是否在更新
this.isUpdating = false;
//上一帧时间戳
this.lastTime = 0;
this.init()
}
/**
* 初始化获取上下文对象
*/
init(){
let context = wx.createCanvasContext(this.id)
this.ctx = context
let frame_interval = Math.ceil(1000/this.fps)
//限制最高20帧
if (frame_interval<50){
frame_interval = 50
}
this.frame_interval = frame_interval
if(this.interval<200){
this.interval = 200
}
//计算单个元素声明间隔步数
let step = this.interval / this.frame_interval
//计算步进半径
this.step_r = this.long / step
//计算步进透明度
this.step_opacity = (this.opacity - this.end_opacity) / step
}
/**
* 添加一个
*/
add() {
// this.paint()
let now = new Date().getTime();
//如果时间戳间隔超过渲染间隔则重置
if ((now - this.lastTime) > this.frame_interval){
this.lastTime = now
}
//小步数
let small_step = (new Date().getTime() - this.lastTime) / this.frame_interval
this.DRAW_ARR.unshift([
this.r + this.step_r * small_step, this.opacity - this.step_opacity * small_step
])
if (!this.isUpdating){
//如果没有更新则开始更新
this.update()
}
}
/**
* 更新数据
*/
update(){
//处理动画序列
this.paint()
//临时序列
let tmp = [];
for (let i = 0; i < this.DRAW_ARR.length; i++) {
let target_r = this.DRAW_ARR[i][0] + this.step_r
let target_opacity = this.DRAW_ARR[i][1] - this.step_opacity
//目标半径未超过最大半径,透明度没有小于0
if (target_r < (this.r + this.long) && target_opacity > this.end_opacity){
tmp.push([
target_r, target_opacity
])
}
}
this.DRAW_ARR = tmp
if (this.DRAW_ARR.length <= 0){
// 序列为空,停止更新
this.isUpdating = false;
} else {
//更新时间戳
this.lastTime = new Date().getTime();
let that = this
setTimeout(function () {
that.update()
}, this.frame_interval)
}
}
/**
* 绘制
*/
paint(){
let context = this.ctx
// 清空画板
context.clearRect(0, 0, this.size[0], this.size[1]);
context.setStrokeStyle("#ffe100")
context.setLineWidth(1)
for (let i = 0; i < this.DRAW_ARR.length; i++){
context.globalAlpha = this.DRAW_ARR[i][1]
context.arc(this.center[0], this.center[1], this.DRAW_ARR[i][0], 0, 2 * Math.PI)
context.stroke()
}
context.draw()
context.globalAlpha = 1
}
}
export default Animate
使用方法:
// 导入
import Animate from './Animate.js'
// 传入Canvas的id实例化
let animate = new Animate('animate')
//点击按钮的时候触发add()方法
animate.add()
使用了requestAnimationFrame,动画流畅,没有丢帧,丝般顺滑,啧啧~~真香
有空再看看canvas怎么优化
let ctx = {}
let id
//起始半径
let r = 65
//扩散长度
let long = 30
//起始透明度
let opacity = 1
//结束透明度
let end_opacity = 0
let step
let step_r = 0
let step_opacity = 0
let center = [90, 90]
let size = [180, 180]
let fps = 30
//帧间隔
let frame_interval = 0
//一个扩散持续的时间,单位为ms
let interval = 1500
//绘制数组
let DRAW_ARR = []
const init = (id) => {
id = id
ctx = wx.createCanvasContext(id)
frame_interval = Math.ceil(1000 / fps)
if (interval < 200) {
interval = 200
}
//计算单个元素声明间隔步数
step = interval / frame_interval
//计算步进半径
step_r = long / step
//计算步进透明度
step_opacity = (opacity - end_opacity) / step
animate()
}
const add = () => {
DRAW_ARR.unshift([
r, opacity
])
}
const update = () =>{
let tmp = [];
for (let i = 0; i < DRAW_ARR.length; i++) {
let target_r = DRAW_ARR[i][0] + step_r
let target_opacity = DRAW_ARR[i][1] - step_opacity
//目标半径未超过最大半径,透明度没有小于0
if (target_r < (r + long) && target_opacity > end_opacity) {
tmp.push([
target_r, target_opacity
])
}
}
DRAW_ARR = tmp
}
const animate = () => {
console.log('animate')
paint()
update()
requestAnimationFrame(animate)
}
const paint = () =>{
let context = ctx
// 清空画板
context.clearRect(0, 0, size[0], size[1]);
context.setStrokeStyle("#ffe100")
context.setLineWidth(1)
for (let i = 0; i < DRAW_ARR.length; i++) {
context.globalAlpha = DRAW_ARR[i][1]
context.arc(center[0], center[1], DRAW_ARR[i][0], 0, 2 * Math.PI)
context.stroke()
}
context.draw()
context.globalAlpha = 1
}
module.exports = {
init: init,
add: add
}
使用方法:
// 导入
let Animate = require('./Animate.js')
// 初始化
Animate.init('animate')
//点击按钮的时候触发add()方法
Animate.add()
有空再补充canvas优化的实例