Built with blockbuilder.org
forked from tomshanley's block: Animate line and points
license: mit |
Built with blockbuilder.org
forked from tomshanley's block: Animate line and points
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> | |
<style> | |
path { | |
stroke-width: 2px; | |
fill: none; | |
} | |
</style> | |
</head> | |
<body> | |
<p>Click the chart to start the animation.</p> | |
<div id="line"></div> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script type="text/javascript"> | |
console.clear() | |
var w = 700; | |
var h = 300; | |
var m = 40; | |
var max = 100 | |
var show = false | |
var svg = d3.select("#line") | |
.append("svg") | |
.attr("width", w + m + m) | |
.attr("height", h + m + m) | |
.on('click', transitionLine) | |
var chart = svg.append("g") | |
.attr("transform", "translate(" + m + "," + m + ")") | |
var data = d3.range(max+1) | |
.map(function(){ | |
return Math.random() * max | |
}) | |
var x = d3.scaleLinear() | |
.domain([0, max]) | |
.range([0, w]); | |
var y = d3.scaleLinear() | |
.domain([0, max]) | |
.range([h, 0]); | |
var line = d3.line() | |
.x(function(d,i) {return x(i);}) | |
.y(function(d) {return y(d);}) | |
var clipPath = chart.append("clipPath") | |
.attr("id", "clip") | |
.append("rect") | |
.attr("id", "clip-rect") | |
.attr("width", 0) | |
.attr("height", h) | |
var bkdPath = chart.append("path") | |
.attr("d", line(data)) | |
.style("stroke", "lightgrey") | |
var path = chart.append("path") | |
.attr("d", line(data)) | |
.style("stroke", "orange") | |
.attr("clip-path", "url(#clip)") | |
var bkdCircle = chart.selectAll(".bkd-circle") | |
.data(data) | |
.enter() | |
.append("g") | |
.attr("transform", function(d, i){ | |
return "translate(" + x(i) + "," + y(d) + ")" | |
}) | |
.attr("class", "bkd-circle") | |
.append("circle") | |
.attr("r", 5) | |
.style("stroke", "lightgrey") | |
.style("fill", "white") | |
var dataPoint = chart.selectAll('.data-point') | |
.data(data) | |
.enter() | |
.append("g") | |
.attr("transform", function(d, i){ | |
return "translate(" + x(i) + "," + y(d) + ")" | |
}) | |
.attr("class", "data-point") | |
.attr("id", (d, i) => "data-point-" + i) | |
.style("opacity", 0) | |
dataPoint.append("circle") | |
.attr("r", 5) | |
dataPoint.append("text") | |
.text((d, i) => i + ", " + round2dp(d) ) | |
.attr("dy", 18) | |
function transitionLine() { | |
svg.on('click', null) | |
d3.select('#clip-rect') | |
.transition() | |
.duration(10000) | |
.ease(d3.easeLinear) | |
.attr("width", function(d){ | |
let n = w | |
if (show) { | |
show = false | |
n = 0 | |
} else { | |
show = true | |
} | |
return n | |
}) | |
.tween("attr.fill", function() { | |
return function(t) { | |
let kx = show ? | |
Math.floor(t * max) : | |
Math.ceil((1-t) * max) | |
let id = "#data-point-" + kx | |
d3.selectAll(".data-point") | |
.style("opacity", 0) | |
d3.select(id) | |
.style("opacity", 1) | |
}; | |
}) | |
.on('end', function(){ | |
svg.on('click', transitionLine) | |
}) | |
} | |
function round2dp(n) { | |
return Number.parseFloat(n).toFixed(2); | |
} | |
</script> | |
</body> | |
</html> |