javascript匀速、缓冲、弹性运动及模拟重力场实现代码
一、匀速运动
可以通过offsetLeft/top获取自身的实时位置,在自身的位置的基础上,通过定时器不断执行,每次在自身位置的基础上再加上一个恒定的速度值,即可形成一个简单的匀速运动。
function move1(dom, target) { clearInterval(dom.timer); dom.timer = setInterval(function () { if (dom.offsetLeft == target) { clearInterval(dom.timer); dom.style.left = target + 'px'; } else { dom.style.left = dom.offsetLeft + 10 + 'px'; } }, 30); }
二、缓冲运动
缓冲运动也就是速度由快到慢最后停止的一个过程。而方块的自身动态位置(或透明度)与终点的位置(或透明度)的差值,刚好满足这样一个速度变化的趋势。
//缓冲运动 function move2(dom, target) { clearInterval(dom.timer); dom.timer = setInterval(function () { //offsetLeft越来越大 iSpeed越来越小 var iSpeed = (target - dom.offsetLeft) / 7; //因为offsetLeft取出来会自动取整,忽略小数,最后每次加小数的时候都会死循环将自己变成整数不变,此时将最后加的小数取整,解决这个问题; iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); if (dom.offsetLeft == target) { clearInterval(dom.timer); dom.style.left = target + 'px'; } else { dom.style.left = dom.offsetLeft + iSpeed + 'px'; } }, 30); } //缓冲运动---改变透明度 //target应是(0-100)之间的数字 function changeOpacity(dom, target) { clearInterval(dom.timer); dom.timer = setInterval(function () { //因为透明度的值始终是一个0——1之间的数,速度变化太快,所以给它扩大100倍 var iCur = parseFloat(getStyle(dom, 'opacity')) * 100; var iSpeed = (target - iCur) / 7; iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); if (iCur == target) { clearInterval(dom.timer); //因为之前扩大了100倍,此处是将其值还原成0-1之间的数字 dom.style.opacity = iCur / 100; } else { //因为之前扩大了100倍,此处是将其值还原成0-1之间的数字 dom.style.opacity = (iCur + iSpeed) / 100; } }, 30); } //多值变化 // var target = { // 'width': 300, // 'opacity': 50 // } function changeMultValue(dom, obj) { clearInterval(dom.timer); var iCur, iSpeed; dom.timer = setInterval(function () { var flag = true; for (var prop in obj) { if (prop == 'opacity') { iCur = parseFloat(getStyle(dom, prop)) * 100; } else { iCur = parseInt(getStyle(dom, prop)); } iSpeed = (obj[prop] - iCur) / 7; iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); if (prop == 'opacity') { dom.style[prop] = (iCur + iSpeed) / 100; } else { dom.style[prop] = iCur + iSpeed + 'px'; } if (iCur != obj[prop]) { flag = false; } } if (flag) { //所有值都已变化完成后,才清除定时器 clearInterval(dom.timer); } }, 30); } //多物体多值链式变化 function changeMult(dom, obj, callback) { clearInterval(dom.timer); var iCur, iSpeed; dom.timer = setInterval(function () { var flag = true; for (var prop in obj) { if (prop == 'opacity') { iCur = parseFloat(getStyle(dom, prop)) * 100; } else { iCur = parseInt(getStyle(dom, prop)); } iSpeed = (obj[prop] - iCur) / 7; iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); if (prop == 'opacity') { dom.style[prop] = (iCur + iSpeed) / 100; } else { dom.style[prop] = iCur + iSpeed + 'px'; } if (iCur != obj[prop]) { flag = false; } } if (flag) { clearInterval(dom.timer); typeof callback == 'function' ? callback() : ''; } }, 30); } //多物体多值链式变化调用方式 // var arr = document.getElementsByTagName('div'); // var obj = { // left: 400, // top: 100, // width: 400, // height: 400, // opacity: 50 // }; // //链式操作 第一个运动完 第二个立马开始 // arr[0].onclick = function () { // changeMult(this, obj, function () { // changeMult(arr[1], obj,''); // }); // } //获取样式 function getStyle(dom, prop) { if (window.getComputedStyle) { return window.getComputedStyle(dom, null)[prop]; } else { return dom.currentStyle[prop]; } }
三、弹性运动
1、匀加(减)速运动
通过每次给速度值加上一个固定的值,每次速度都会增加,使之变成一个匀加速的运动;
//弹性运动1:target左边 速度不断增加 target右边 速度不断减小 function move1(dom, target) { clearInterval(dom.timer); var iSpeed = 20; var a = 3; dom.timer = setInterval(function () { if (dom.offsetLeft > target) { iSpeed -= a; } else { iSpeed += a; } dom.style.left = dom.offsetLeft + iSpeed + 'px'; }, 30); }
2、变加(减)速运动
function move(dom, target) { clearInterval(dom.timer); var iSpeed = 20; var a; var u = 0.9; dom.timer = setInterval(function () { a = (target - dom.offsetLeft) /8; // 这里将目标值减去当前位置,这种情况下,当距离目标值越近,分子越小,速度越慢,所以为减速运动;当超过目标值的情况下,速度变成负数,在原来speed的基础上,speed慢慢减少,直到最后变成0,然后变成负数,一旦变成负数,就会开始往反方向也就是往回运动;我们不难发现,其实当物体面向中心的目标值运动时,离得越远,速度越快。离得越近甚至超过中心点的时候,速度一直在减少;就这样一个速度变化的趋势,刚好满足我们所需要的一个弹性运动 ; iSpeed += a; iSpeed *= u; //给一个相当于摩擦系数u,让其速度值越来越接近于0,运动一定程度时停止 if (Math.abs(iSpeed) < 1 && Math.abs(target - dom.offsetLeft) < 1) { //因为当最后速度在减少到非常小的时候,每次乘0.8,会形成很长位数的小数而不会真正归零,所以我们用绝对值判断,只要小于1px我们就让他停止 clearInterval(dom.timer); } else { dom.style.left = dom.offsetLeft + iSpeed + 'px'; } }, 30); }
四、模拟重力场
var div = document.getElementsByTagName('div')[0]; div.onmousedown = function (e) { clearInterval(div.timer); var event = e || window.event; var disX = event.clientX - this.offsetLeft; var disY = event.clientY - this.offsetTop; var lastX = this.offsetLeft; var lastY = this.offsetTop; document.onmousemove = function (e) { //让方块随着鼠标移动 var event = e || window.event; var nowX = event.clientX - disX; var nowY = event.clientY - disY; iSpeedX = nowX - lastX; iSpeedY = nowY - lastY; div.style.left = nowX + 'px'; div.style.top = nowY + 'px'; lastX = nowX; lastY = nowY; } document.onmouseup = function () { document.onmousemove = null; document.onmouseup = null; //让方块以最后位置时的速度作为初速度继续运动,相当于惯性运动 move(div, iSpeedX, iSpeedY) } } function move(dom, iSpeedX, iSpeedY) { //进入函数先清除定时器;防止多次触发; clearInterval(dom.timer); var clientX = getSize().w, clientY = getSize().h, newLeft, newTop; var a = 6, u = 0.8; dom.timer = setInterval(function () { iSpeedY += a; newLeft = dom.offsetLeft + iSpeedX; newTop = dom.offsetTop + iSpeedY; //运动到四周边界时,变换方向,减小速度 if (newTop > clientY - dom.offsetHeight) { iSpeedY *= -1;//变换方向 iSpeedX *= 0.8; iSpeedY *= 0.8; newTop = clientY - dom.offsetHeight; } if (newTop < 0) { iSpeedY *= -1; iSpeedX *= 0.8; iSpeedY *= 0.8; newTop = 0; } if (newLeft > clientX - dom.offsetWidth) { iSpeedX *= -1; iSpeedX *= 0.8; iSpeedY *= 0.8; newLeft = clientX - dom.offsetWidth; } if (newLeft < 0) { iSpeedX *= -1; iSpeedX *= 0.8; iSpeedY *= 0.8; newLeft = 0; } if (Math.abs(iSpeedX) <= 1) { iSpeedX = 0; } if (Math.abs(iSpeedY) <= a * 0.8) { iSpeedY = 0; } //运动到底部且两个方向上的速度都为0,让其停止, if (iSpeedX == 0 && iSpeedY == 0 && newTop == (clientY - dom.offsetHeight)) { clearInterval(dom.timer); } dom.style.left = newLeft + 'px'; dom.style.top = newTop + 'px'; }, 30); } //获取窗口大小 function getSize() { if (window.innerWidth) { return { w: window.innerWidth, h: window.innerHeight } } else if (document.body.clinetWidth) { return { w: document.body.clinetWidth, h: document.body.clientHeight } } else { return { w: document.documentElement.clientWidth, h: document.documentElement.clientHeight } } }
THE END