前提说明:
①左边是利用 Gojs 写的 diagram,放在canvas里进行操作。涉及到Gojs里面的配置代码不会做详细说明
②右边是用原生js写的抽屉组件
③达到下面图片这个效果很简单,flex 的响应式布局(左右两个div变化宽度) 和 动态切换右边抽屉 div 的class达到动画切换效果
最终效果:
接下来开始正文:
1.问题发现:
canvas的可视化变现不能及时相应?
2.原因:
两边div——“图”和“抽屉”和虽然可以动态变化宽度,但是“图”里面的canvas并不会根据其父容器div的变化而变化,除非我们在canvas里做出有效操作触发其更新(例如 拖动、点击等可以改变canvas展示的行为)
3.解决思路:
我们总不可能在“抽屉”滑动的过程中 时时刻刻点击canvas达到更新canvas的效果吧…我们可以让这个过程自动化!
3.1 定时器
① Vue兄弟组件传值,抽屉滑动的时候通知图在滑动过程中进行不断更新
②怎么更新? 调用 myDiagram 实例的requestUpdate()方法
③代码
beforeCreate(){
//兄弟组件传值
//监听抽屉的滑动,以免滑梯滑动之后canvas的面积不会被改变
this.bus.$on("toDiagramForArea",msg=>{
let time = setInterval(()=>{
this.myDiagram.requestUpdate();
},10)
setTimeout(()=>{
clearInterval(time);
},1000)
//this.upDateDiagramAnimationFrame(0)
})
}
④缺点
- 需要自己设定刷新时间,JS 动画都是通过在很短的时间内不停的渲染/绘制元素做到的,所以计时器一直是 Javascript动画的核心技术,所以动画的关键就是刷新的间隔时间。刷新间隔需要尽量短,这样才能动画效果显得平滑流畅,如流水等,同时刷新间隔又不能太短,这样才能确保浏览器有能力渲染动画。
- 最大的问题是setTimeout 和 setInterval精确度低!没法保证这个动画的刷新频率正好就是我们所设定的。【参考 事件循环机制】。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器 UI 线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。知道什么时候绘制下一帧是可是保证动画平滑的关键。
3.2 requestAnimationFrame()方法——用于请求浏览器调用指定的回调函数以在下次重绘渲染之前更新动画。
beforeCreate(){
//兄弟组件传值
//监听抽屉的滑动,以免滑梯滑动之后canvas的面积不会被改变
this.bus.$on("toDiagramForArea",msg=>{
this.upDateDiagramAnimationFrame(0)
})
}
methods中:
upDateDiagramAnimationFrame(count){
count++;
requestAnimationFrame(() => {
this.myDiagram.requestUpdate();
if(count<60){ this.upDateDiagramAnimationFrame(count); }
});
},
设置这个API,就是为了让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅。 requestAnimationFrame 是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用
requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率帧。