JavaScript運動框架 解決速度正負取整問題(一)
這里說的運動是指緩沖運動,緩沖運動會使物體逐漸‘著陸’,而不是‘硬著陸’,到達目標位置的過程中速度越來越慢,看起來很舒服。
緩沖的特點:
- 速度隨著距離的縮短而降低
- 速度 = (目標值 - 當前值) / 縮放系數;
- 速度一定要是整數
比如,一個div從最左邊運動到left等于400的位置停下,可以如下實現(xiàn):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>運動框架(一)</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
#div1 {
width: 100px;
height: 100px;
background: orange;
position: absolute;
}
#div2 {
width: 1px;
height: 300px;
background: black;
position: absolute;
left: 400px;
}
#btn1 {
width: 60px;
height: 40px;
background: #fff;
position: absolute;
left: 10px;
top: 150px;
}
</style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<input id="btn1" type="button" value="start" onclick="startMove()" />
<script type="text/javascript">
var oDiv = document.getElementById('div1');
var oBtn = document.getElementById('btn1');
var timer = null;
function startMove() {
/* 每次啟動定時器應該把上次的定時器清理掉,
因為有的人會多次點擊按鈕,多次啟動定時器,速度會疊加越來越快!
*/
clearInterval(timer);
timer = setInterval(function() {
//每次速度都隨著距離的縮短而變慢
var speed = (400 - oDiv.offsetLeft) / 10;
if (oDiv.offsetLeft == 400) {
clearInterval(timer);
} else {
oDiv.style.left = oDiv.offsetLeft + speed + 'px';
document.title = oDiv.offsetLeft + ' , ' + speed;
}
}, 30);
}
</script>
</body>
</html>


你會發(fā)現(xiàn),啟動按鈕之后,div并沒有準確到達400的位置,再看看title上打印的實際目標和速度,我們發(fā)現(xiàn)最終落腳點是396,速度為0.4,我們知道:1px是最小單位,沒有小數的概念,所以0.4px是沒有的概念,會被計算機認為是0px,仔細分析,當div運行到396px的時候,還剩下4px,速度為4/10 = 0.4,下一個單位時間(30ms)向前運行0.4px,實際上是0,所以永遠的停下來了,而且永遠不會執(zhí)行清除定時器這一步!
怎么解決,Math中有個方法叫向上取整,也就是讓速度取整,向上取整,努力幫助div跨過這一步
Math.ceil(3.2) ==> 4 Math.ceil(-9.7) ==> -9 Math.floor(5.98) ==> 5
function startMove() {
clearInterval(timer);
timer = setInterval(function() {
var speed = (400 - oDiv.offsetLeft) / 10;
speed = Math.ceil(speed);//劃重點,劃重點
if (oDiv.offsetLeft == 400) {
clearInterval(timer);
} else {
oDiv.style.left = oDiv.offsetLeft + speed + 'px';
document.title = oDiv.offsetLeft + ' , ' + speed;
}
}, 30);
}

當然了,div除了可以正向運動,也可以負向運動,比如,從800運動到400.
如果不取整的話,依舊不能準確到達400。
#div1 {
width: 100px;
height: 100px;
background: orange;
position: absolute;
left: 800px;/*0 --> 800*/
}

function startMove() {
clearInterval(timer);
timer = setInterval(function() {
var speed = (400 - oDiv.offsetLeft) / 10;
console.log('speed = ' + speed);
speed = Math.floor(speed);//劃重點,劃重點,劃重點
if (oDiv.offsetLeft == 400) {
clearInterval(timer);
} else {
oDiv.style.left = oDiv.offsetLeft + speed + 'px';
document.title = oDiv.offsetLeft + ' , ' + speed;
}
}, 30);
}

總結:
正向運動(速度 > 0), Math.ceil(speed);
反向運動(速度 < 0), Math.floor(speed);
var speed = (iTarget - cur) / 系數; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
function startMove(iTarget) {
setInterval(function() {
var speed = (iTarget- oDiv.offsetLeft) / 10;
speed = speed > 0 ? Math.ceil(speed) : Match.floor(speed);
oDiv.style.left = oDiv.offsetLeft + speed + 'px';
}, 30);
}
速度取整,是為了最后時刻速度(絕對值)變大,跨過那一檻,不然只能停留在附近!
如果速度不取整,最后的結果就是停在目標值附近,還差幾個像素,這個值最后算出來的速度的絕對值肯定小于1,導致還差幾像素跨不過去了,如果你這時候讓速度取整達到1,最后幾個像素的距離其實就是勻速前行了,每次(30ms)都行走1px,因為最后幾次都速度算出來都是1,1px 1px的行走到目的地!
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Array, Array Constructor, for in loop, typeof, instanceOf
雖然在 JavaScript 中數組是是對象,但是沒有好的理由去使用 `for in` 循環(huán) 遍歷數組。相反,有一些好的理由不去使用 for in 遍歷數組。2011-09-09
three.js中正交與透視投影相機的實戰(zhàn)應用指南
在three.js中攝像機的作用就是不斷的拍攝我們創(chuàng)建好的場景,然后通過渲染器渲染到屏幕中,下面這篇文章主要給大家介紹了關于three.js中正交與透視投影相機應用的相關資料,需要的朋友可以參考下2022-08-08
javascript實現(xiàn)點擊商品列表checkbox實時統(tǒng)計金額的方法
這篇文章主要介紹了javascript實現(xiàn)點擊商品列表checkbox實時統(tǒng)計金額的方法,涉及javascript鼠標事件及頁面元素操作的相關技巧,需要的朋友可以參考下2015-05-05

