内容简介:这是一道笔试题,要求是这么说的 定义了多组坐标数据,要实现坐标之间的连线动画(不考虑曲线),以及暂停与播放功能,还有重置,这可太难了呀,还不让依赖工具,于是我就放弃了。放弃不可能,还是试一下吧!html css js 用div做.....怎么做呢...我艹,算了,换canvas吧,还是canvas爽一点。 那么我特么为什么要用canvas呢
这是一道笔试题,要求是这么说的 定义了多组坐标数据,要实现坐标之间的连线动画(不考虑曲线),以及暂停与播放功能,还有重置,这可太难了呀,还不让依赖工具,于是我就放弃了。
放弃不可能,还是试一下吧!
技术选型
html css js 用div做.....怎么做呢...我艹,算了,换canvas吧,还是canvas爽一点。 那么我特么为什么要用canvas呢
- 绘制点到点的动画,多是利用插值技术,也不排除一些骚操作
- canvas绘制之后不清除是会一直存留的,不必在插值的路径上去创建像素
- canvas对交互动画有着一定的天然优势,如果人家非要让我用div或者svg,那我也只要自闭了
创建依赖
依赖总是我最喜欢写的东西,2D总是离不开Vector2,开始构建我们可爱的VV
var Vector = function(x = 0,y = 0) { this.x = x; this.y = y; } 复制代码
然后稍微加工一下
Vector.prototype={ add:function(v){ return new Vector(this.x+v.x,this.y+v.y); }, subtract:function(v){ return new Vector(v.x-this.x,v.y-this.y); }, length:function(){ return Math.sqrt(this.x*this.x+this.y*this.y); }, divide:function(n){ return new Vector(this.x/n,this.y/n); }, unit:function(){ return this.divide(this.length()); }, lerp:function(v){ let dirV = this.subtract(v); let unit = dirV.unit(); return this.add(unit); } } 复制代码
如此一来,基本的核心功能就出来了
BALL的构建
至于为什么叫BALL,也许是因为热衷于球吧。
var ball = function(x = 0,y = 0 ){ this.x = x; this.y = y; this.status = MOVEING; } ball.prototype.render = function(context){ let self = this; context.save(); context.fillStyle = fillStyle; context.rect(self.x, self.y,5,5); context.fill(); context.restore(); } ball.prototype.lerp = function(site){ //插值计算,不断更新坐标 let self = this; let dirV = new Vector(...site); self.site = new Vector(this.x,this.y); let n_site = self.site.lerp(dirV); self.x = n_site.x; self.y = n_site.y; } 复制代码
正如你所见,利用了向量的插值计算来不断更新当前坐标来实现超速移动。
使用 status
来处理不同状态的BALL,善于使用状态量会使代码逻辑更加舒适,这里定义了所需要的状态
const PEDDING = 'PEDDING'; const MOVEING = 'MOVING'; const RESETING ='RESETING'; 复制代码
主逻辑
整体的主要逻辑就是不断对BALL进行插值更新,同时要处理小球的状态
function move(pos){ context.clearRect(0, 0, can.width, can.height); a.render(context); switch (a.status) { case 'PEDDING': break; case 'MOVING': a.lerp(pos); break; // case 'RESETING': // //小球RESETING状态,有BUG,可有可无 // a = null; // context.clearRect(0, 0, can.width, can.height); // a = new ball(...site[0]); // index=0; // //a.status = MOVEING; // break; default: break; } } 复制代码
不要太在意那个BUG,程序员的BUG能叫BUG吗?
渲染部分
function run(){ let x = site[index+1][0]; let y = site[index+1][1]; console.log(index) if(a.x>=x-1&&a.y>=y-1){ index=index+1; } if(site[index+1]){ move(site[index+1]); requestAnimationFrame(run) } if(a.status==RESETING){ context.clearRect(0, 0,2000,1000); //这里弃用 } } (function(){ site.length>=2?requestAnimationFrame(run):' '; })() 复制代码
这里只需要注意坐标序列的长度,避免只有一个坐标,还有就是当前索引归属于下一个索引的存在与否。
这里是个小TIP,不要再动画的循环中写过多的逻辑,能封装出去的逻辑尽量封装出去,不然会显得代码异常臃肿。
交互部分
<button onclick="pause()">暂停</button> <button onclick="play()">播放</button> <button onclick="reset()">重置</button> 复制代码
//重置 暂停 运行 function reset(){ location.reload(); //a.status = RESETING; } function pause(){ a.status = PEDDING; } function play(){ a.status = MOVEING; } 复制代码
由于canvas的clearRect有点问题,效果一直出不来,这里直接采用强行F5的安全措施,保证安全。
效果也算是完成了,其实还可以有很多拓展的部分,比如曲线连接,回放效果等,不知道你有啥骚操作呢,come on !
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【Android 动画】动画详解之属性动画(三)
- 【Android 动画】动画详解之属性动画(五)
- Flutter 动画全解析(动画四要素、动画组件、隐式动画组件原理等)
- 【Android 动画】动画详解之补间动画(一)
- 系统学习iOS动画之一:视图动画
- 初识属性动画——使用Animator创建动画
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。