4
\$\begingroup\$

I have made this little program for fun, to add on my personal webpage. I remember seeing something like it some time ago, don't remember exactly where, and I tried to reproduce it myself.

As it turns out, I figured out that it isn't quite fun to have your CPU stressed out by 25% because of a funny single homepage, so I won't be using it anymore, but I thought it'd be a good chance to put my efforts to test here on Code Review.

Any thoughts are welcome. I'm specially curious if the way I'm creating the dots looks good or if it is of good performance or not. I profiled the code a few days ago and realized that the main source of processing tasks were related to canvas drawing.

Working example here

var canvas,
    ctx,
    colors = ['#FF6600', '#0099FF', '#BCBCBC', '#3D3D3D'],
    dots = [],
    maxDots = 35;

function Dot() {
    this.alive = true;
    this.x = Math.round(Math.random() * canvas.width);
    this.y = Math.round(Math.random() * canvas.height);
    this.size = Math.round(Math.random() * 7);
    this.velocity = {
        x: (Math.random() < 0.5 ? -1 : 1) * Math.random() * 0.7,
        y: (Math.random() < 0.5 ? -1 : 1) * Math.random() * 0.7
    }
    this.alpha = 0.01;
    this.hexColor = colors[Math.round(Math.random() * (colors.length - 1))];
    this.rgbaStringColor = getRGBA(this.hexColor, this.alpha);
}

Dot.prototype.draw = function () {
    ctx.beginPath();
    ctx.fillStyle = this.rgbaStringColor;
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx.fill();
}

function getRGBA(hex, alpha) {
    var r = parseInt(hex.substring(1, 3), 16),
        g = parseInt(hex.substring(3, 5), 16),
        b = parseInt(hex.substring(6, 8), 16),
        a = alpha;
    return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
}

/*updates both colors and position of the dot*/
Dot.prototype.update = function () {
    if (this.alpha < 0.7) {
        this.alpha += 0.01;
        this.rgbaStringColor = getRGBA(this.hexColor, this.alpha);
    }

    this.x += this.velocity.x;
    this.y += this.velocity.y;

    if (this.x > (canvas.width) + 5 || this.x < -5) {
        this.alive = false;
    }
    if (this.y > (canvas.height) - 15 || this.y < -5) {
        this.alpha -= 0.05;
        if (this.alpha <= 0.1) {
            this.alive = false;
        }
    }
}

function createDots() {
    dots = dots.filter(function (dot) {
        return dot.alive;
    });
    for (var length = dots.length; length < maxDots; length++) {
        dots.push(new Dot());
    }
}

function update() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for (var i = 0; i < dots.length; i++) {
        dots[i].draw();
        dots[i].update();
    }
    createDots();
    window.requestAnimationFrame(update);
}

function init() {
    createDots();
    update();
}


function setCanvasSize() {
    canvas.width = window.innerWidth;
    canvas.height = 300;
}

document.addEventListener('DOMContentLoaded', function () {
    canvas = document.getElementById('universe');
    ctx = canvas.getContext('2d');
    setCanvasSize();
    init();
});
\$\endgroup\$
  • 1
    \$\begingroup\$ i did three improvements here jsbin.com/muriviqamo/2/edit (caching canvas size / modifying the alpha, not the color string / working on-place on the array). But i couldn't see any effect on the profile... \$\endgroup\$ – GameAlchemist Jan 4 '15 at 16:55
2
\$\begingroup\$

The CPU load doesn't look so bad. On my 2011 MBP the linked example runs easily at 60fps, taking between 0.4 and 0.85ms (of the 16.6ms available for that framerate) to run the animation frame callback. No sweat.

As for code style; it's generally pretty clear and easy to follow, though I would suggest name-spacing your state variables and methods instead of using global variables. This is generally considered better practice, it's safer, can in theory improve performance and make the code easier to read. For example, you could do something like:

FlyingBalls = {
    colors: [...],
    dots: [],
    maxDots: [],
    init: function initDots(canvasId) { this.canvas = ... }
    create: function createDots() { ... },
    update: function updateDots() { ... }
}

Or use a constructor like:

function FlyingBalls(canvasId) {
    var canvas, 
        ctx,
        ...;

    function createDots() { ... }

    function updateDots() { ... }

    // init code here
    canvas = document.getElementById(canvasId);
    ...
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.