Skip to content

Instantly share code, notes, and snippets.

@headwinds
Created June 23, 2020 00:28
Show Gist options
  • Save headwinds/73bcdf347a775b99d66a6f7460110592 to your computer and use it in GitHub Desktop.
Save headwinds/73bcdf347a775b99d66a6f7460110592 to your computer and use it in GitHub Desktop.
animated dashed+solid path with gradient
license: gpl-3.0
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment