Canvas

Start

"Hidden" Buffer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
(function() {
    // For description of this technique, see justindonato.com
    var canvas = document.getElementById('canvas');
    var buffer = document.getElementById('buffer');

    var canvasCtx = canvas.getContext('2d');
    var bufferCtx = buffer.getContext('2d');


    // This object holds our clickable items. It's keys wil be hex color values.
    var clickables = {};

    // A quick ball class that can render itself on a canvas context
    var Ball = function(x, y, radius, color, idColor) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.origRadius = radius;
        this.color = color;
        this.idColor = idColor;
        this.stroke = 0;
        this.velX = .5 + (Math.random());
        this.velY = .5 + (Math.random());
    };

    Ball.prototype.move = function() {
        this.x += this.velX;
        this.y += this.velY;
    };

    Ball.prototype.render = function(ctx, color) {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0 , 2 * Math.PI, false);
        ctx.fillStyle = color;
        ctx.fill();

        if (this.radius > this.origRadius) this.radius -= .1;
    };

    Ball.prototype.bounce = function bounce() {
        if (this.x > 300 - (this.radius)) this.velX = this.velX * -1;
        if (this.x < (this.radius)) this.velX = this.velX * -1;
        if (this.y > 100 - (this.radius)) this.velY = this.velY * -1;
        if (this.y < (this.radius)) this.velY = this.velY * -1;        
    }

    // Create two balls.

    // Make up an id (a Number) and convert it to a color.            
    var id1 = Math.floor(Math.random() * 200000);
    var idColor1 = colorFromInt(id1);
    var ball = new Ball(20, 20, 20, '#B1CBCC', idColor1);

    var id2 = Math.floor(Math.random() * 200000);
    var idColor2 = colorFromInt(id2);
    var ball2 = new Ball(105, 25, 20, '#7ABAD6', idColor2);

    // Add the balls to our set of clickables
    clickables[idColor1] = ball;
    clickables[idColor2] = ball2;

    // Define some helper functions

    // Given an int, convert to hex and append hash for css-style color
    function colorFromInt(i) {
        var hex = i.toString(16);
        return \"#\" + zeroPadLeft(hex, 6);
    }
        
    function zeroPadLeft(str, len) {
        while(str.length < len) {
            str = '0' + str;
        }
        return str;
    }
    
    // When the mouse is clicked, draw each of the clickables on the
    // hidden buffer whereever they happen to be. Then grab the color from the
    // pixel under the mouse and see if we have a clickable for that 
    function checkHit(e) {
        var ball;
        for (id in clickables) {
            ball = clickables[id];
            ball.render(bufferCtx, ball.idColor);
        }
        var pixel = bufferCtx.getImageData(e.offsetX, e.offsetY, 1, 1);
        // Convert the pixel color to a hex string
        var color = \"#\";
        for (var i = 0; i < pixel.data.length - 1; i++) {
            color += zeroPadLeft(pixel.data[i].toString(16), 2);
        }

        var hit = clickables[color];
        if (hit) hit.radius += 7;
    }

    // The main loop, move and render balls
    function run() {
        canvasCtx.clearRect(0, 0, 300, 100);
        bufferCtx.clearRect(0, 0, 300, 100);

        var ball;
        for (id in clickables) {
            ball = clickables[id];
            ball.move();
            ball.render(canvasCtx, ball.color);
            ball.bounce();
        }
    }

    var startBtn = document.getElementById('start');
    startBtn.addEventListener('click', function() {
        startBtn.style.display = 'none';
        // Listen for mouse up events to check hits
        canvas.addEventListener('mouseup', checkHit);
        // Start a loop at 60fps
        setInterval(run, 1000 / 60);
    });
    // Run once just to show some circles
    run();
})()