|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<style> |
|
body { |
|
margin: 0; |
|
font-family: "Helvetica Neue", sans-serif; |
|
} |
|
.circle { |
|
stroke: #000; |
|
opacity: .8; |
|
} |
|
.circle:hover { |
|
opacity: 1; |
|
stroke-width: 1.5px; |
|
} |
|
.baseline { |
|
stroke: #000; |
|
shape-rendering: crispEdges; |
|
} |
|
.label { |
|
text-anchor: end; |
|
font-size: .8em; |
|
} |
|
.axis .domain { |
|
display: none; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script src="https://unpkg.com/[email protected]/lib/jeezy.min.js"></script> |
|
<script> |
|
|
|
var alpha = "Annie,Bob,Christina,Dylan,Elizabeth,Fred,Gertrude,Isaiah,Jennifer".split(","); |
|
|
|
var w = window.innerWidth, h = window.innerHeight; |
|
|
|
var margin = {top: h / 6, left: 75, bottom: 10, right: w / 20}, width = w - margin.right - margin.left, height = h - margin.top - margin.bottom; |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + ", " + margin.top + ")"); |
|
|
|
var y_scale = d3.scaleBand() |
|
.rangeRound([0, height]) |
|
.domain(alpha) |
|
|
|
var circle_scale = d3.scaleLinear() |
|
.range([0, y_scale.bandwidth()]) |
|
.domain([0, 100]) |
|
|
|
var x_scale = d3.scaleBand() |
|
.rangeRound([0, width]) |
|
.domain(Array.apply(null, {length: 21}).map(Number.call, Number)); |
|
|
|
// lines and labels |
|
var line = svg.selectAll(".baseline") |
|
.data(alpha) |
|
.enter().append("line") |
|
.attr("class", "baseline") |
|
.attr("x1", 0) |
|
.attr("x2", width) |
|
.attr("y1", function(d){ return y_scale(d); }) |
|
.attr("y2", function(d){ return y_scale(d); }) |
|
|
|
var label = svg.selectAll(".label") |
|
.data(alpha) |
|
.enter().append("text") |
|
.attr("class", "label") |
|
.attr("x", -10) |
|
.attr("y", function(d){ return y_scale(d); }) |
|
.text(function(d){ return d; }); |
|
|
|
var axes = svg.selectAll(".x") |
|
.data(alpha) |
|
.enter().append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", function(d) { return "translate(0, " + y_scale(d) + ")"; }) |
|
.call(d3.axisBottom(x_scale)) |
|
|
|
drawChart(makeData()); |
|
|
|
d3.interval(function(){ drawChart(makeData()); }, 750); |
|
|
|
function drawChart(data){ |
|
|
|
// JOIN |
|
var circle = svg.selectAll(".circle") |
|
.data(data, function(d){ return d.id + d.day; }); |
|
|
|
// EXIT |
|
circle.exit() |
|
.style("fill", "tomato") |
|
.transition().delay(325) |
|
.attr("d", function(d){ return half_circle(x_scale(d.day) + (x_scale.bandwidth() / 2), y_scale(d.id), 0)}) |
|
.remove(); |
|
|
|
// UPDATE |
|
circle |
|
.transition() |
|
.style("fill", "steelblue") |
|
.attr("d", function(d){ return half_circle(x_scale(d.day) + (x_scale.bandwidth() / 2), y_scale(d.id), circle_scale(d.value)); }); |
|
|
|
// ENTER |
|
circle.enter().append("path") |
|
.attr("class", "circle") |
|
.attr("d", function(d){ return half_circle(x_scale(d.day) + (x_scale.bandwidth() / 2), y_scale(d.id), 0)}) |
|
.style("fill", "#47ff63") |
|
.transition() |
|
.attr("d", function(d){ return half_circle(x_scale(d.day) + (x_scale.bandwidth() / 2), y_scale(d.id), circle_scale(d.value)); }); |
|
} |
|
|
|
function makeData(){ |
|
var arr = []; |
|
alpha.map(function(letter){ |
|
for (var i = 0; i <= 20; i++){ |
|
arr.push({id: letter, day: i, value: jz.num.randBetween(10, 90)}) |
|
} |
|
}); |
|
|
|
// don't return the whole thing, so we have exiting and entering |
|
return jz.arr.shuffle(arr).map(function(d, i){ if (i < jz.num.randBetween(70, 90)) return d; }).filter(function(d){ return d != undefined; }); |
|
} |
|
|
|
function half_circle(cx, cy, r){ |
|
return "M" + (cx + r) + "," + cy + " a" + r + "," + r + " 1 1,0 -" + (r * 2) + ",0"; |
|
} |
|
|
|
</script> |
|
|
|
</body> |
|
</html> |