JavaScript正弦波

时间:2011-08-26 20:53:40

标签: javascript algorithm math trigonometry

track : function(x, y, top, ampl) {
        return {
            top : top + 2,
            x   : x + ampl * Math.sin(top / 20),
            y   : (top / this.screenHeight < 0.65) ? y + 2 : 1 + y + ampl * Math.cos(top / 25)
        };
    }

这个程序发送雪花以正弦波方式飞行。

但它是如何做到的?请解释一下。

Math.sin使用x;和Math.cos y,但我见过的其他片段以相反的方式使用它们。为什么?为什么要top/20top/25

整个代码:

<script type="text/javascript">
var snowflakes = { // Namespace
    /* Settings */

    pics : [

        ['snow.gif' , 24, 24],
        ['snow2.gif', 24, 24],
        ['snow3.gif', 24, 24]
    ],

    track : function(x, y, top, ampl) {
        return {
            top : top + 2,
            x   : x + ampl * Math.sin(top / 20),
            y   : (top / this.screenHeight < 0.65) ? y + 2 : 1 + y + ampl * Math.cos(top / 25)
        };
    },

    quantity : 30,

    minSpeed : 20, // 1 - 100, minSpeed <= maxSpeed

    maxSpeed : 40, // 1 - 100, maxSpeed >= minSpeed

    isMelt : true, // true OR false
    /* Properties */
    screenWidth : 0,
    screenHeight : 0,
    archive : [],
    timer : null,
    /* Methods */
    addHandler : function(object, event, handler, useCapture) {
        if (object.addEventListener) object.addEventListener(event, handler, useCapture);
        else if (object.attachEvent)object.attachEvent('on' + event, handler);
        else object['on' + event] = handler;
    },
    create : function(o, index) {
        var rand = Math.random();
        this.timer = null;
        this.o = o;
        this.index = index;
        this.ampl = 3 + 7*rand;
        this.type =  Math.round((o.pics.length - 1) * rand);
        this.width = o.pics[this.type][1];
        this.height = o.pics[this.type][2];
        this.speed = o.minSpeed + (o.maxSpeed - o.minSpeed) * rand;
        this.speed = 1000 / this.speed;
        this.deviation = o.maxDeviation * rand;
        this.x = o.screenWidth * rand - this.width;
        this.y = 0 - this.height;
        this.top = this.y;
        this.img = document.createElement('img');
        this.img.src = o.pics[this.type][0];
        this.img.style.top = this.y + 'px';
        this.img.style.position = 'absolute';
        this.img.style.zIndex = 10000;
        this.img.style.left = this.x + 'px';
        this.img.obj = this;
        if (o.isMelt) this.img.onmouseover = function() {
            clearTimeout(this.obj.timer);
            this.obj.timer = null;
            this.parentNode.removeChild(this);
        }
        document.body.appendChild(this.img);
        this.move();
    },
    init : function() {
        this.screenWidth = window.innerWidth ? window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.offsetWidth);
        this.screenWidth = navigator.userAgent.toLowerCase().indexOf('gecko') == -1 ? this.screenWidth : document.body.offsetWidth;
        this.screenHeight = window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.offsetHeight);
        this.screenScroll = (window.scrollY) ? window.scrollY : document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
        this.archive[this.archive.length] = new this.create(this, this.archive.length);
        clearTimeout(this.timer);
        this.timer = null
        this.timer = setTimeout(function(){snowflakes.init()}, 60000 / this.quantity);
    }
};
snowflakes.create.prototype = {
    move : function() {
        var newXY = this.o.track(this.x, this.y, this.top, this.ampl);
        this.x   = newXY.x;
        this.y   = newXY.y;
        this.top = newXY.top;
        if (this.y < this.o.screenHeight + this.o.screenScroll - this.height) {
            this.img.style.top  = this.y + 'px';
            this.x = this.x < this.o.screenWidth - this.width ? this.x : this.o.screenWidth - this.width;
            this.img.style.left = this.x + 'px';
            var index = this.index;
            this.timer = setTimeout(function(){snowflakes.archive[index].move()}, this.speed);
        } else {
            delete(this.o.archive[this.index]);
            this.img.parentNode.removeChild(this.img);
        }
    }
};
snowflakes.addHandler(window, 'load', function() {snowflakes.init();});
snowflakes.addHandler(window, 'resize', function() {snowflakes.init();});
    </script>

2 个答案:

答案 0 :(得分:10)

基本正弦函数定义为:

f(x) = A sin(wt + p)

其中

  • A是振幅
  • w是频率
  • p是阶段

这些因素决定了f的图形如何。

幅度可以被认为是比例因子,A越大,f的峰值和低点越大(绝对值)。

频率决定正弦函数在其重新开始之前运行所有值的速度 - 正弦是一个周期函数。 k越大,f越快就会经历一个周期。

p是阶段,将其视为“移动”函数的起点向右(正p)或左(负)。很难用文字解释,看看here的图表。

您在示例中提供的功能是

的通用版本
f: R->R², f(t)=(sin(t), cos(t))

parametrizations of the unit circle 中的哪一个({1}}。如果你单调地增加t并绘制x(sin(t))和y(cos(t)),你将在一个半径为1的圆上飞行一个点。

您的广义功能

f: R->R², f(t) = (A sin(1/wt), A cos(1/wt)), w > 1

在你的情况下,对于x坐标,A = ampl,t = top,w = 20,对于y坐标,w = 25。 w的这些轻微偏差使得运动变得紧张,因此它不再是一个完美的圆形,而是一些“扭曲的”椭圆形 - 我想,雪花片不会落入完美的圆形中。此外,这使得片状物的路径看起来比直线完美的圆圈更随机。虽然这是一种幻觉,但这也是非常确定的并且仍然是周期性的 - 只是x和y运动是“不同步的”所以它需要更长的时间才能完成一个周期。

w被选择&gt; 1“减慢”圆周运动。你选择w越大,频率越低,你的移动点就会慢得多。

您选择的A越大,您的圆圈就越大。

答案 1 :(得分:5)

它只会使正弦波更大,因此可以更容易地观察到曲线。

这是我尝试制作的小提琴。如果我将20和25更改为1,则运动变得不那么有趣。 http://jsfiddle.net/AbM9z/1/

了解调用函数的值将会有所帮助。