Fireflies


Fireflies = function( container, width, height )
{
    var _dots;

    function init()
    {
        // ...

        var dot = new Dot();
        dot.reset( _width, _height );

        var d = _dots = dot;

        var n = 96;

        while( --n > -1 )
        {
            dot = new Dot();
            dot.reset( _width, _height );

            d = d.next = dot;
        }

        // ...
    }

    // ...

    function render()
    {
        // ...

        var dot = _dots.next;

        do
        {
            dot.update( _canvas, _context, _width, _height );

            dot = dot.next;
        }
        while( dot );

    }
};

var Dot = function()
{
    this.next = null;

    this.reset = function( width, height )
    {
        var maxRadius = 9;
        this.posX = width * Math.random();
        this.posY = height * Math.random();
        this.dirX = (Math.random() * 3.0) * (Math.random() < .5 ? -1 : 1);
        this.dirY = (Math.random() * 1.5) * (Math.random() < .5 ? -1 : 1);
        this.radius = 1 + ( maxRadius * Math.random() );
        this.bMax = 60 * (this.radius / maxRadius);
        this.bDelta = 3 + Math.random();
        this.b = Math.random() * this.bMax;
    };

    this.update = function( canvas, context, width, height )
    {
        this.b += this.bDelta;

        var bn = (this.b / this.bMax);
        var bni = 1 - bn;

        this.posX += this.dirX * bn;
        this.posY += this.dirY * bn;

        if( 0 > this.posX || this.posX > width )
        {
            this.dirX *= -1;
        }

        if( 0 > this.posY || this.posY > height )
        {
            this.dirY *= -1;
        }

        if( this.b <= 0 || this.b >= this.bMax )
        {
            this.bDelta *= -1;
        }
        else if( this.b > this.bMax )
        {
            this.reset();
        }

        var r = this.radius * bni;

        if( r < 1 )
        {
            r = 1;
        }

        var gradient = context.createRadialGradient( this.posX, this.posY, 0, this.posX, this.posY, r );
        gradient.addColorStop( 0.0, 'rgba(255,255,255,' + bni + ')' );
        gradient.addColorStop( 0.5, 'rgba(255,255,255,' + (bni * .2) + ')' );
        gradient.addColorStop( 1.0, 'rgba(255,255,255,0)' );

        context.beginPath();
        context.arc( this.posX, this.posY, this.radius, 0, Math.PI * 2, true );
        context.closePath();
        context.fillStyle = gradient;
        context.fill();
    };
};