rain

by Ryan

HTML

<script src="https://d3js.org/d3.v3.min.js"></script>
<button id="pause">Pause</button>
<div>fps: <span id="fps"></span></div>
<div id="chart"></div>

CSS

body { font: 10px sans-serif; }
svg { background-color: #000; }

circle {
    fill: #666;
    stroke: #eee;
}

JavaScript

var margin = 10,
    width = 600 - margin*2,
    height = 400 - margin*2;

var config = {
    circle: {
        life: 800,
        r: { min: 3, mean: 15, std: 0 },
        o: { min: 0, max: 1}
    },
    rate: {
        epoch: { min: 0, mean: 100, std: 50 },
        count: { min: 0, mean: 1, std: 0 }
    }
};
var dist = {
    circle: {
        r: d3.random.normal(config.circle.r.mean, config.circle.r.std)
    },
    rate: {
        epoch: d3.random.normal(config.rate.epoch.mean, config.rate.epoch.std),
        count: d3.random.normal(config.rate.count.mean, config.rate.count.std)
    }
};
var fn = {
    circle: {
        x: function(){ return Math.random() * (width - margin*2) + margin; },
        y: function(){ return Math.random() * (height - margin*2) + margin; },
        r: function(){ return Math.max(config.circle.r.min, dist.circle.r()) }
    },
    rate: {
        epoch: function(){ return Math.max(0, dist.rate.epoch()); },
        count: function(){ return Math.max(0, dist.rate.count()); }
    }
};


// The list of circles
var circles = [];
var paused = false;

var g = d3.select("div#chart").append("svg")
    .attr("width", width + margin*2).attr("height", height + margin*2)
    .append("g")
        .attr("transform", "translate(" + margin + "," + margin + ")");


var lastTs = Date.now();
var nowTs = Date.now();
var fps = d3.select('#fps');
d3.timer(function() {
    nowTs = Date.now();
    for(var i=circles.length-1; i>=0; i--){
        var d = circles[i];
        var age = nowTs - d.ts;

        if(!paused){
            if(config.circle.life < age){
                d.c.remove();
                circles.splice(i, 1);
            } else {
                var ageRatio = age/config.circle.life;
                var r = d.r.min + ageRatio * (d.r.max - d.r.min);
                var o = config.circle.o.max - ageRatio * (config.circle.o.max - config.circle.o.min);
                d.c.attr('r', r).attr('opacity', o);
            }
        } else {
            d.ts...