javascript运动系列第三篇——曲线运动

Posted 小火柴的蓝色理想

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript运动系列第三篇——曲线运动相关的知识,希望对你有一定的参考价值。

前面的话

  上一篇介绍了变速运动,但只实现了直线运动。如果元素的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">

以上是关于javascript运动系列第三篇——曲线运动的主要内容,如果未能解决你的问题,请参考以下文章

进阶篇python使用tkinter实现透明窗体上绘制运动小球(第三篇)

原生JavaScript运动功能系列:定时定点运动

原生JavaScript运动功能系列:缓冲运动

javascript运动系列第一篇——运动函数

如何使文本以曲线运动在屏幕上向上移动

javascript运动系列第九篇——碰撞运动