viewof viz = {
var width = 960,
height = 500,
then = Date.now(),
velocity = 0.005,
sphere_radius = .4 * height,
sphere_center = {"x": width/2, "y": height/2},
color_scale = d3.scaleSequential(d3.interpolateRainbow);
var svg = d3.select(DOM.svg(width, height));
svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "#222");
function get_random_number(start, end) {
return ((Math.random() * (end - start)) + start);
}
function x_proj(r, theta, phi) {
return sphere_center.x + r * Math.sin(theta) * Math.cos(phi);
}
function y_proj(r, theta) {
return sphere_center.y + r * Math.cos(theta);
}
function depth_proj(theta, phi) {
return 1 + 0.2 * Math.sin(theta) * Math.sin(phi);
}
function generate_blobs(num_blobs) {
var blobs = [];
for (var i = 0; i < num_blobs; i++) {
var v_latent = get_random_number(0, 2 * Math.PI),
force_radius = get_random_number(0.01, 0.1),
force_angle = get_random_number(0.001, 0.002),
blob = {"size" : get_random_number(1, 3),
"opacity" : get_random_number(0.5, 1),
"theta" : Math.acos(get_random_number(-1, 1)),
"phi" : get_random_number(0, 2 * Math.PI),
"r": sphere_radius,
"v_latent": v_latent,
"force": force_radius,
"force_angle": force_angle,
"v_r": Math.sin(v_latent) * force_radius,
"v_theta": Math.sin(v_latent) * force_angle,
"v_phi": Math.cos(v_latent) * force_angle,
"wander": get_random_number(1, 1.5),
"drag": get_random_number(0.2, 0.5),
"color": color_scale(Math.random())};
blobs.push(blob);
}
return blobs;
}
function move(d) {
d.r += d.v_r;
d.theta += d.v_theta;
d.phi += d.v_phi + velocity;
d.v_r *= d.drag;
d.v_theta *= d.drag;
d.v_phi *= d.drag;
d.v_latent += get_random_number(-0.2, 0.2) * d.wander;
d.v_r += Math.sin(d.v_latent) * d.force;
d.v_theta += Math.sin(d.v_latent) * d.force_angle;
d.v_phi += Math.cos(d.v_latent) * d.force_angle;
}
var blobs_data = generate_blobs(500);
var sphere = svg.selectAll("circle")
.data(blobs_data)
.enter()
.append("circle")
.attr("cx", function(d) { return x_proj(d.r, d.theta, d.phi); })
.attr("cy", function(d) { return y_proj(d.r, d.theta); })
.attr("r", function(d) { return d.size * depth_proj(d.theta, d.phi); })
.attr("opacity", function(d) { return d.opacity; })
.attr("fill", function(d) { return d.color; });
function redraw() {
sphere.each(move)
.attr("cx", function(d) { return x_proj(d.r, d.theta, d.phi); })
.attr("cy", function(d) { return y_proj(d.r, d.theta) })
.attr("r", function(d) { return d.size * depth_proj(d.theta, d.phi); });
}
d3.timer(function() {
redraw();
})
return svg.node();
}