文章出處

前面的話

  上一篇介紹了變速運動,但只實現了直線運動。如果元素的left和top同時運動,并遵循不同的曲線公式,則會進行不同形式的曲線運動。本文將詳細介紹圓周運動、鐘擺運動、拋物線運動和流體運動這四種曲線運動形式

 

圓周運動

  圓周運動可能是最好理解的曲線運動了

  若(x0,y0)為圓心,則圓的公式為(x-x0)*(x-x0) + (y-y0)*(y-y0) = r*r

  寫成三角函數的形式為

    x = x0 + cosa*r
    y = y0 + sina*r

  所以,實際上只要知道夾角a和圓心(x0,y0)就可以計算出x和y

  圓周運動可以封裝為函數circleMove.js

function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
} 
function circleMove(json){
    //要操作的元素
    var obj = json.obj;
    //方向(順時針'+'或逆時針'-')
    var dir = json.dir;
    dir = dir || '+';
    //最大圈數
    var max = json.max;
    max = Number(max) || 'all'; 
    //半徑
    var r = json.r;
    r = Number(r) || 100;
    //圓心x軸坐標
    var x0 = json.x0 || parseFloat(getCSS(obj,'left'));
    //圓心y軸坐標
    var y0 = json.y0 ||  parseFloat(getCSS(obj,'top')) - r;
    //初始夾角,以角度為單位
    var a0 = json.a0;
    a0 = Number(a) || 90;
    //當前夾角
    var a = json.a ||a0;
    //當前圈數
    var num = json.num || 0;
    //清除定時器
    if(obj.timer){return;}
    //聲明當前值cur
    var cur = {};
    obj.timer = setInterval(function(){
        //將這些瞬時值儲存在obj對象中的屬性中
        obj.a = a;
        obj.x0 = x0;
        obj.y0 = y0;
        obj.x = x;
        obj.y = y;
        obj.num = num;
        //如果元素運動到指定圈數則停止定時器
        if(num == max){
            clearInterval(obj.timer);
        }
        //順時針
        if(dir == '+'){
            a++;
            if(a == a0 + 360){
                a = a0;
                num++;
            }
        //逆時針
        }else{
            a--;
            if(a == a0 - 360){
                a = a0;
                num++;
            }
        }
        //更新當前值
        cur.left = parseFloat(getCSS(obj,'left'));
        cur.top = parseFloat(getCSS(obj,'top'));    
        //更新left和top值
        var x = x0 + r*Math.cos(a*Math.PI/180);
        var y = y0 + r*Math.sin(a*Math.PI/180)
        test.style.left = x + 'px';
        test.style.top = y + 'px';    
    },20);
}

  下面利用封裝的circleMove.js來實現簡單的圓周運動

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<button id="btn1">順時針旋轉</button>
<button id="btn2">逆時針旋轉</button>
<button id="btn3">暫停</button>
<button id="reset">還原</button>
<div id="result"></div>
<div id="backup" style="height: 298px;width:298px;border:1px solid black;border-radius:50%;position:absolute;top:50px;left:50px;">
    <div id="test" style="height: 40px;width: 40px;background-color:pink;position:relative;left:130px;top:280px;border-radius:50%"></div>
</div>
<script src="http://files.cnblogs.com/files/xiaohuochai/circleMove.js"></script>
<script>
reset.onclick = function(){
    history.go();
}
btn1.onclick = function(){
    circleMove({obj:test,r:150,x0:test.x0,y0:test.y0,a:test.a,num:test.num});
}
btn2.onclick = function(){
    circleMove({obj:test,r:150,dir:'-',x0:test.x0,y0:test.y0,a:test.a,num:test.num});
}
btn3.onclick = function(){
    clearInterval(test.timer);
    test.timer = 0;    
}
</script>
</body>
</html>

【css3】

  css3新增了transform和animation等新的樣式,也可以用來做圓周運動。transform里面有一個變形函數是rotate,這時就需要使用逆向思維。元素本身并不發生運動,而是軌道自身在旋轉,會實現視覺上的圓周運動效果

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
@keyframes rotate1{
    100%{transform:rotate(360deg);}
}
@keyframes rotate2{
    100%{transform:rotate(-360deg);}
}
#backup{
    height: 298px;width:298px;border:1px solid black;border-radius:50%;position:absolute;top:50px;left:50px;
}
#test{
    height: 40px;width: 40px;background-color:pink;position:relative;left:130px;top:280px;border-radius:50%
}
</style>
</head>
<body>
<button id="btn1">順時針旋轉</button>
<button id="btn2">逆時針旋轉</button>
<button id="btn3">暫停</button>
<button id="reset">還原</button>
<div id="result"></div>
<div id="backup">
    <div id="test"></div>
</div>
<script>
reset.onclick = function(){
    history.go();
}
btn1.onclick = function(){
    backup.style.animation= 'rotate1 4s infinite linear';
}
btn2.onclick = function(){
    backup.style.animation= 'rotate2 4s infinite linear';
}
btn3.onclick = function(){
    backup.style.animationPlayState = 'paused';
}
</script>
</body>
</html>

三維圓周

  前面我們介紹了二維圓周運動,如果是三維圓周運動,則需要考慮x、y、z立體坐標軸

  從示意圖中可知,三維圓周運動的模擬實現實際上是元素的寬高發生了變化,元素的x軸變化依然按照三角函數公式進行,元素的y軸一直保存為0

  假設圓的寬(或高)在z軸正方向最遠處時為100px,當z軸值為0時,寬(或高)為50px,在z軸負方向最遠處時為0px

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<button id="btn1">開始旋轉</button>
<button id="btn2">暫停</button>
<button id="reset">還原</button>
<div id="result"></div>
<div id="test" style="height: 100px;width: 100px;background-color:pink;position:relative;left:200px;top:60px;border-radius:50%"></div>
<script>
reset.onclick = function(){
    history.go();
}
btn1.onclick = function(){
    threeCircleMove({
        obj:test,r:200,x0:test.x0,width:test.width,height:test.height,a:test.a,num:test.num
    })
}
btn2.onclick = function(){
    clearInterval(test.timer);
    test.timer = 0;    
}
function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
} 
function threeCircleMove(json){
    //要操作的元素
    var obj = json.obj;
    //方向(順時針'+'或逆時針'-')
    var dir = json.dir;
    dir = dir || '+';
    //最大圈數
    var max = json.max;
    max = Number(max) || 'all'; 
    //半徑
    var r = json.r;
    r = Number(r) || 100;
    //圓心x軸坐標
    var x0 = json.x0 || parseFloat(getCSS(obj,'left'));
    //元素的初始寬高
    var offsetHeight = obj.offsetHeight;
    var offsetWidth = obj.offsetWidth;
    //元素的寬高
    var height,width;
    //初始夾角,以角度為單位
    var a0 = json.a0;
    a0 = Number(a) || 90;
    //當前夾角
    var a = json.a ||a0;
    //當前圈數
    var num = json.num || 0;
    //清除定時器
    if(obj.timer){return;}
    //聲明當前值cur
    var cur = {};
    obj.timer = setInterval(function(){
        //將這些瞬時值儲存在obj對象中的屬性中
        obj.a = a;
        obj.x0 = x0;
        obj.width = width;
        obj.height = height;
        obj.x = x;
        obj.num = num;
        //如果元素運動到指定圈數則停止定時器
        if(num == max){
            clearInterval(obj.timer);
        }
        //順時針
        if(dir == '+'){
            a++;
            if(a == a0 + 360){
                a = a0;
                num++;
            }
        //逆時針
        }else{
            a--;
            if(a == a0 - 360){
                a = a0;
                num++;
            }
        }
        //更新當前值
        cur.left = parseFloat(getCSS(obj,'left'));   
        //更新left值和寬高值
        var x = x0 + r*Math.cos((90 + a*Math.PI)/180);
        width = (offsetWidth/2) + offsetWidth/2*Math.sin((90 + a*Math.PI)/180);
        height = (offsetHeight/2) + offsetWidth/2*Math.sin((90 + a*Math.PI)/180);
        test.style.left = x + 'px';
        test.style.width = width + 'px'; 
        test.style.height = height + 'px';    
    },20);
}
</script> 
</body>
</html>

【css3】

  同樣地,使用強大的css3屬性可以實現三維圓周效果

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
@keyframes rotate1{
    100%{transform:rotateX(60deg) rotate(360deg);}
}
@keyframes rotate2{
    100%{transform:rotateX(60deg) rotate(-360deg);}
}
body{
    perspective: 700px;
}
#backup{
    height: 298px;width:298px;border:1px solid black;border-radius:50%;position:absolute;top:100px;left:100px;transform:rotateX(60deg) rotate(0);
}
#test{
    height: 40px;width: 40px;background-color:pink;position:relative;left:130px;top:280px;border-radius:50%
}
</style>
</head>
<body>
<button id="btn1">順時針旋轉</button>
<button id="btn2">逆時針旋轉</button>
<button id="btn3">暫停</button>
<button id="reset">還原</button>
<div id="result"></div>
<div id="backup">
    <div id="test"></div>
</div>
<script>
reset.onclick = function(){
    history.go();
}
btn1.onclick = function(){
    backup.style.animation= 'rotate1 4s infinite linear';
}
btn2.onclick = function(){
    backup.style.animation= 'rotate2 4s infinite linear';
}
btn3.onclick = function(){
    backup.style.animationPlayState = 'paused';
}
</script>
</body>
</html>

鐘擺運動

  一個鐘擺,一會兒朝左,一會兒朝右,周而復始,來回擺動。鐘擺總是圍繞著一個中心值在一定范圍內作有規律的擺動,這種運動稱為鐘擺運動,可以把鐘擺運動看做圓周運動的一部分,進而比較簡單的實現鐘擺運動

  假設,元素初始時處于鐘擺的最底點。當鐘擺與豎直線夾角為60度時,為最高點

  若鐘擺運動的圓心為(x0,y0),則圓的公式為(x-x0)*(x-x0) + (y-y0)*(y-y0) = r*r

  若夾角a為鐘擺與豎直線夾角,寫成三角函數的形式為

    x = x0 + sina*r
    y = y0 + cosa*r

  當夾角a從0增加到60或減小到-60時,元素開始做反向運動

  將鐘擺運動寫成pendulMove.js的形式

function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
} 
function pendulMove(json){
    //要操作的元素
    var obj = json.obj;
    //起始方向(順時針'+'或逆時針'-')
    var dir = json.dir;
    dir = dir || '+';
    //最大次數(再次經過最低點為一次)
    var max = json.max;
    max = Number(max) || 'all'; 
    //半徑
    var r = json.r;
    r = Number(r) || 100;
    //圓心x軸坐標
    var x0 = json.x0 || parseFloat(getCSS(obj,'left'));
    //圓心y軸坐標
    var y0 = json.y0 ||  parseFloat(getCSS(obj,'top')) - r;
    //初始夾角,以角度為單位
    var a0 = json.a0;
    a0 = Number(a) || 0;
    //當前夾角
    var a = json.a ||0;
    //當前次數
    var num = 0;
    //清除定時器
    if(obj.timer){return;}
    //聲明當前值cur
    var cur = {};
    obj.timer = setInterval(function(){
        //將這些瞬時值儲存在obj對象中的屬性中
        obj.a = a;
        obj.x0 = x0;
        obj.y0 = y0;
        obj.x = x;
        obj.y = y;
        obj.num = num;
        //如果元素運動到指定圈數則停止定時器
        if(num == max){
            clearInterval(obj.timer);
        }
        //起始向右運動
        if(dir == '+'){
            a++;
            if(a == 60){
                //方向變成向左
                dir = '-';
            }
        }else{
            a--;
            if(a == -60){
                //方向變成向右
                dir = '+';
            }
        }
        //更新當前值
        cur.left = parseFloat(getCSS(obj,'left'));
        cur.top = parseFloat(getCSS(obj,'top'));    
        //更新left和top值
        var x = x0 + r*Math.sin(a*Math.PI/180);
        var y = y0 + r*Math.cos(a*Math.PI/180)
        test.style.left = x + 'px';
        test.style.top = y + 'px';    
    },20);
}

  下面利用封裝的pendulMove.js來實現簡單的鐘擺運動

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<button id="btn1">起始正向運動</button>
<button id="btn2">起始逆向運動</button>
<button id="btn3">暫停</button>
<button id="reset">還原</button>
<div id="result"></div>
<div id="backup" style="height: 298px;width:298px;border-bottom:1px solid black;border-radius:50%;position:absolute;top:50px;left:50px;">
    <div id="test" style="height: 40px;width: 40px;background-color:pink;position:relative;left:130px;top:280px;border-radius:50%"></div>
</div>
<script src="http://files.cnblogs.com/files/xiaohuochai/pendulMove.js"></script>
<script>
reset.onclick = function(){
    history.go();
}
btn1.onclick = function(){
    pendulMove({obj:test,r:150,x0:test.x0,y0:test.y0,a:test.a,num:test.num});
}
btn2.onclick = function(){
    pendulMove({obj:test,r:150,dir:'-',x0:test.x0,y0:test.y0,a:test.a,num:test.num});
}
btn3.onclick = function(){
    clearInterval(test.timer);
    test.timer = 0;    
}
</script>
</body>
</html>

【彈性運動】

  實際情況下,鐘擺運動并不是勻速運動,而是一個重復的加減速運動,正好彈性運動可以輕松的實現類似效果

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button id="btn1">開始運動</button>
<button id="btn2">暫停</button>
<button id="reset">還原</button>
<div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;top: 30px;border-radius:50%"></div>
<script>
function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
}  
reset.onclick = function(){history.go();}
btn2.onclick = function(){
    clearInterval(test.timer);
}
//聲明步長值stepY、stepX
var stepY = 30;
var stepX = 10;
btn1.onclick = function(){
    //聲明當前值curY、curX
    var curY,curX;
    //聲明目標值
    var targetY = parseFloat('400px');
    clearInterval(test.timer);
    test.timer = setInterval(function(){   
        //更新當前值
        curY = parseFloat(getCSS(test,'top'));
        curX = parseFloat(getCSS(test,'left'));
        //更新步長值
        stepY -= 1;
        //當元素返回到初始高度時
        if(stepY == -30){
            stepY = 29;
            stepX = -stepX;
        }        
        //更新top、left值
        test.style.top = curY + stepY + 'px';
        test.style.left = curX + stepX + 'px';

    },20);
}
</script>    
</body>
</html>

拋物線運動

  平面內到定點與定直線的距離相等的點的軌跡叫做拋物線。其中定點叫拋物線的焦點,定直線叫拋物線的準線。拋物線實際上就是一段特殊形式的曲線

  拋物線方程為y=a*x*x+b*x+c

  其中a、b、c為參數,以x為參照的話,當x以固定值遞增的方式進行變化時,y也會有相應變化

  若a>0時,拋物線的開口向下;否則,開口向上

  拋物線的準線的x軸坐標為(-2*a/b)。如果target目標設置為100,則(-2*a/b)盡量設置為50

  若a = 0.01,則b=-1

  將拋物線運動寫成parabolMove.js的形式

function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
} 
function parabolMove(json){
    //設置要操作的元素
    var obj = json.obj;
    //設置x軸上的目標值
    var target = json.target;
    target = Number(target) || 300;
    //設置x軸的步長值
    var stepValue = json.step || 2;
    //設置x軸的步長
    var step = 0;
    //設置回調函數
    var fn = json.fn;
    //參數a、b、c
    var a = json.a;
    a = Number(a) || 0.01;
    var b = json.b;
    b = Number(b) || -1*target/100;
    var c = json.c;
    c = Number(c) || 0;
    //初始值
    var left = parseFloat(getCSS(obj,'left'));
    if(left >= target){return;}
    var top = parseFloat(getCSS(obj,'top')); 
    //清除定時器
    if(obj.timer){return;}
    //聲明當前值cur
    var cur = {};
    obj.timer = setInterval(function(){
        //更新步長值
        step += stepValue; 
        //更新left和top值
        var x = left + step;
        var y = top + a*step*step + b*step + c;
        if(x > target){
            x = target;
        }
        test.style.left = x + 'px';
        test.style.top = y + 'px';  
        //如果到達目標點,清除定時器
        if(x == target){
            clearInterval(obj.timer);
            obj.timer = 0;
            fn && fn.call(obj);    
        }  
    },20);
} 

  下面利用封裝的parabolMove.js來實現簡單的拋物線運動

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<button id="btn1">開始運動</button>
<button id="reset">還原</button>
<div id="test" style="height: 40px;width: 40px;background-color:pink;position:absolute;left:0px;top:100px;"></div>

<script src="http://files.cnblogs.com/files/xiaohuochai/parabolMove.js"></script>
<script>
reset.onclick = function(){
    history.go();
}
btn1.onclick = function(){
    parabolMove({obj:test,target:200});
}

</script>
</body>
</html>

流體運動

  流體運動實際上就是三角函數曲線運動,以sin為例,y = asin(b*x),當a和b取不同的值時,就可以得到不同的曲線形式

  在這里要注意的是,sin里面的參數一定要寫成弧度的形式

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.track{width: 2px;height: 2px;background-color:#000;position:absolute;}
</style>
</head>
<body>
<label for="a" id="labelA">參數a:100</label>
<input id="a" type="range"  min="50" max="100" step="10" value="100" />
<label for="b" id="labelB">參數b:1</label>
<input id="b" type="range" min="1" max="5" step="1"  value="1" />
<button id="reset">還原</button>
<span>三角函數的公式為: y = a*sin(b*x)</span>
<span id="result">所以,實際公式為:y = 100*sin(1*x)</span>
<div id="test" style="height: 50px;width: 50px;background-color: pink;border-radius:50%;position: absolute;left: 30px;top:50px;"></div>
<script>
reset.onclick = function(){
    history.go();
}
function createTracks(x,y){
    var ele = document.createElement('div');
    ele.className = 'track';
    ele.style.left = x + 'px';
    ele.style.top = y + 'px';
    document.body.appendChild(ele);
}
function deleteTracks(){
    var eles = document.getElementsByTagName('div');
    for(var i = 0 ;i < eles.length; i++){
        if(eles[i].className == 'track'){
            document.body.removeChild(eles[i]);
            i--;
        }
    }
}
function getResult(){
    result.innerHTML = '所以,實際公式為: y=' + a.value + '*sin(' + b.value + '*x)';
}
show();
function show(){
    clearInterval(test.timer);
    //重置left、top值
    test.style.left = 30 + 'px';
    test.style.top = 50 + 'px';
    //聲明定時器運行次數
    var n = 0;
    //聲明拓展倍數
    var value = 100;
    //清除軌跡
    deleteTracks();
    test.timer = setInterval(function(){
        var A = Number(a.value);
        var B = Number(b.value);
        n++;
        var x = (B*n)*Math.PI/180;
        var y = A*Math.sin(x);
        test.style.left = x*value + 'px';
        test.style.top = 2*A+y + 'px';
        createTracks(x*value,2*A+y);
        if(x*value >= document.documentElement.clientWidth - 2*test.offsetWidth){
            clearInterval(test.timer)
        }
    },20)
}
a.oninput = function(){
    labelA.innerHTML = '參數a:' + this.value;
    getResult();
    show();
}
b.oninput = function(){
    labelB.innerHTML = '參數b:' + this.value;
    getResult();
    show();
}
</script>
</body>
</html>


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()