Built with blockbuilder.org
forked from tomshanley's block: Animate line and points
forked from tomshanley's block: Animate line and points
license: mit |
Built with blockbuilder.org
forked from tomshanley's block: Animate line and points
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> | |
<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 = 10 | |
var numberOfSeries = 3 | |
var svg = d3.select("#line") | |
.append("svg") | |
.attr("width", w + m + m) | |
.attr("height", h + m + m) | |
var chart = svg.append("g") | |
.attr("transform", "translate(" + m + "," + m + ")") | |
var data = [] | |
for (var a = 0; a < numberOfSeries; a++) { | |
data.push([]) | |
for (var i = 0; i <= max; i++) { | |
data[a].push(Math.random() * max) | |
} | |
} | |
console.log(data) | |
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);}) | |
.curve(d3.curveCardinal) | |
var series = chart.selectAll(".series") | |
.data(data) | |
.enter() | |
.append("g") | |
var bkdPath = series.append("path") | |
.attr("d", d => line(d)) | |
.style("stroke", "lightgrey") | |
var path = series.append("path") | |
.attr("d", d => line(d)) | |
.attr("id", (d, i) => "path-" + i) | |
.style("stroke", "orange") | |
.style("stroke-width", "5px") | |
var bkdCircle = series.selectAll(".bkd-circle") | |
.data(d => d) | |
.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 = series.selectAll('.data-point') | |
.data(d => d) | |
.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) | |
let pointArray = [] | |
let sampleRate = 100 | |
let sampleWidth = w / sampleRate | |
for (var p = 0; p < numberOfSeries; p++) { | |
pointArray.push([]) | |
let currentLength = 0 | |
let pathID = "#path-" + p | |
let thisPath = d3.select(pathID) | |
let node = thisPath.node() | |
let pathLength = node.getTotalLength() | |
let s = 0 | |
thisPath.attr("stroke-dasharray", pathLength + " " + pathLength) | |
.attr("stroke-dashoffset", pathLength) | |
for (var j = 0; j<pathLength; j++){ | |
let point = node.getPointAtLength(j) | |
//console.log(point) | |
if (point.x >= (sampleWidth * s)) { | |
pointArray[p].push({"x": point.x, "y": point.y, "len": j}) | |
s = s + 1 | |
} | |
} | |
pointArray[p].push({"x": w, "y": y(data[p][data[p].length-1]), "len": pathLength}) | |
} | |
//console.log(pointArray) | |
let transitionElements = chart.selectAll(".t-elements") | |
.data(pointArray) | |
.enter() | |
.append("g") | |
transitionElements.selectAll(".markers") | |
.data(d => d) | |
.enter() | |
.append("circle") | |
.attr("cx", d => d.x) | |
.attr("cy", d => d.y) | |
.attr("r", 2) | |
.style("fill", "red") | |
let head = transitionElements.append("circle") | |
.datum(d => d) | |
.attr("cx", d => d[0].x) | |
.attr("cy", d => d[0].y) | |
.attr("r", 15) | |
.style("fill", "green") | |
.attr("id", "head") | |
let tIndex = 0 | |
let dur = 50000 | |
function transitionChart(){ | |
tIndex = tIndex + 1 | |
if (tIndex >= (sampleRate+1)) { | |
} else { | |
path.transition() | |
.duration(dur / (sampleRate + 1)) | |
.ease(d3.easeLinear) | |
.attr("stroke-dashoffset", function(d,i){ | |
let len = d3.select(this).node().getTotalLength() | |
return len -pointArray[i][tIndex].len | |
}) | |
head.transition() | |
.duration(dur / (sampleRate + 1)) | |
.ease(d3.easeLinear) | |
.attr("cx", (d,i) => pointArray[i][tIndex].x) | |
.attr("cy", (d,i) => pointArray[i][tIndex].y) | |
.on("end", transitionChart) | |
} | |
} | |
transitionChart() | |
function round2dp(n) { | |
return Number.parseFloat(n).toFixed(2); | |
} | |
</script> | |
</body> | |
</html> |