1. 程式人生 > >Javascript中的運動

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
                }
            }
        }