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> |