forked from mbostock's block: Point-Along-Path Interpolation
forked from kafunk's block: Point Along Stroke-Dash-Interpolated Path
forked from kafunk's block: animated dashed+solid path with gradient
license: gpl-3.0 |
forked from mbostock's block: Point-Along-Path Interpolation
forked from kafunk's block: Point Along Stroke-Dash-Interpolated Path
forked from kafunk's block: animated dashed+solid path with gradient
<!DOCTYPE html> | |
<html> | |
<meta charset="utf-8"> | |
<head> | |
<style> | |
path { | |
fill: none; | |
stroke: #ddd; | |
stroke-width: 2px; | |
stroke-linecap: round; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="https://d3js.org/d3.v5.js"></script> | |
<script> | |
// DATA + CORE VARS | |
var points = [ | |
[480, 40], | |
[480, 400], | |
[160, 320], | |
[360, 340], | |
[480, 440], | |
[600, 340], | |
[800, 320], | |
[480, 400], | |
[480, 40], | |
[480, 440], | |
[360, 100], | |
[480, 400], | |
[600, 100], | |
[480, 440] | |
]; | |
var width = 960, | |
height = 600; | |
var line = d3.line().curve(d3.curveCardinalClosed.tension(0.1)) | |
var origDash = "1 4 4 8"; | |
// duration base | |
var time = 12000; | |
// SET UP SVG | |
var svg = d3.select("body").append("svg") | |
.datum(points) | |
.attr("width", width) | |
.attr("height", height); | |
// APPEND COLOR GRADIENTS | |
// append radial color gradient to new svg <defs> element | |
var radialGradient = svg.append("defs").append("radialGradient") | |
.attr("id", "radial-gradient") | |
.attr("cx", "50%") | |
.attr("cy", "20%") | |
.attr("r", "80%") | |
// define color scales | |
var numColors = 9, | |
gradientScale = d3.scaleLinear() | |
.domain([0,(numColors-1)/2,numColors-1]) | |
.range(["lightcoral","purple","darkslateblue"]); | |
// bind specific color stops to radialGradient | |
radialGradient.selectAll("stop") | |
.data(d3.range(numColors)) | |
.enter().append("stop") | |
.attr("offset", function(d,i) { return i/(numColors-1)*100 + "%"; }) | |
.attr("stop-color", d => { return gradientScale(d) }); | |
// APPEND LINE PATHS | |
// faint outline of path | |
svg.append("path") | |
.style("stroke-dasharray", origDash) | |
.attr("d", line); | |
var path = svg.append("path") | |
.style("stroke", "url(#radial-gradient)") | |
.style("stroke-width", "4") | |
.attr("d", line) | |
// PREPARE FOR PATH TRANSITIONS USING STROKE-DASHARRAY & STROKE-DASHOFFSET | |
var length = path.node().getTotalLength(); | |
// calc sum of each digit of initial dash array | |
var dashSum = origDash.split(" ") | |
.map( x => +x ) | |
.reduce( | |
( accumulator, currentVal ) => | |
accumulator + currentVal, 0 | |
); | |
// calc number of times dashSum must repeat to fill path length | |
var dashTimes = Math.ceil(length/dashSum); | |
// create dash string as origDash repeated dashTimes | |
var dashFill = new Array(dashTimes + 1).join(origDash + ' '); | |
// combine dashFill with total path length for (double) dashed stroke value | |
var dashStr = dashFill + ", " + length | |
// dashed path initially blank | |
path.style("stroke-dasharray", dashStr) | |
.style("stroke-dashoffset", -length) | |
// APPEND CIRCLES/POINTS | |
// little guys | |
svg.selectAll(".point") | |
.data(points) | |
.enter().append("circle") | |
.attr("r", 4) | |
.style("fill", (d,i) => { return gradientScale(i) }) | |
.attr("transform", function(d) { return "translate(" + d + ")"; }); | |
// FUNCTIONS | |
function goPath() { | |
path.transition() | |
.duration(time*2) | |
.styleTween("stroke-dashoffset", drawDashed) | |
.transition() | |
.duration(time*2) | |
.styleTween("stroke-dashoffset", drawSolid) | |
.transition() | |
.duration(time*2) | |
.styleTween("stroke-dashoffset", clearSolid) | |
.transition() | |
.duration(time*2) | |
.styleTween("stroke-dashoffset", clearDashed) | |
.on("end", goPath) | |
} | |
function drawTest() { | |
var i = d3.interpolateString("0,"-length,"0,0"); | |
return function(t) { return i(t); }; | |
} | |
function drawDashed() { | |
var i = d3.interpolateString(-length,"0"); | |
return function(t) { return i(t); }; | |
} | |
function drawSolid() { | |
var i = d3.interpolateString("0",length); | |
return function(t) { return i(t); }; | |
} | |
function clearSolid () { | |
var i = d3.interpolateString(length,"0"); | |
return function(t) { return i(t); }; | |
} | |
function clearDashed() { | |
var i = d3.interpolateString("0", -length); | |
return function(t) { return i(t); }; | |
} | |
// INITIATE ANIMATION | |
goPath() | |
</script> | |
</body> |