這是一道筆試題,要求是這麼說的 定義了多組座標數據,要實現座標之間的連線動畫(不考慮曲線),以及暫停與播放功能,還有重置,這可太難了呀,還不讓依賴工具,因而我就放棄了。javascript
放棄不可能,仍是試一下吧!css
html css js 用div作.....怎麼作呢...我艹,算了,換canvas吧,仍是canvas爽一點。 那麼我特麼爲何要用canvas呢html
依賴老是我最喜歡寫的東西,2D老是離不開Vector2,開始構建咱們可愛的VVjava
var Vector = function(x = 0,y = 0) {
this.x = x;
this.y = y;
}
複製代碼
而後稍微加工一下git
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,也許是由於熱衷於球吧。github
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,善於使用狀態量會使代碼邏輯更加溫馨,這裏定義了所須要的狀態canvas
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嗎?ide
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的安全措施,保證安全。