Skip to content

Instantly share code, notes, and snippets.

@bwswedberg
Last active March 13, 2019 21:24
Show Gist options
  • Save bwswedberg/ea8b6aaaa830574fda9359dd2351dcda to your computer and use it in GitHub Desktop.
Save bwswedberg/ea8b6aaaa830574fda9359dd2351dcda to your computer and use it in GitHub Desktop.
Gradient Along Stroke (Naive)

This (naive) example demonstrates how to create a gradient that follows a stroke or path. This method breaks the stroke into segments and uses stroke-linecap: round; to make the segments overlay and appear connected. The naive approach might useful if your stroke or path is relatively simple and you do not need a high level of precision. See Gradient Along Stroke (Naive) Spiral for same logic but spiral layout.

For a more robust solution see Mike Bostock's miter joint method demonstrated in Gradient Along Stroke.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
display: block;
width: 100%;
}
</style>
<svg viewBox="0 0 960 500">
<path fill="none" stroke-width="10" d="
M86,388
L203,330
C320,272,554,156,673.8333333333334,165.83333333333334
C793.6666666666666,175.66666666666666,799.3333333333334,311.3333333333333,683.5,316.6666666666667
C567.6666666666666,322,330.3333333333333,197,211.66666666666666,134.5
L93,72"></path>
</svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var path = d3.select('path').remove();
var segments = d3.pairs(samples(path.node(), 8));
var color = d3.scaleSequential(d3.interpolateRainbow)
.domain([0, segments.length - 1]);
d3.select('svg')
.append('g')
.attr('transform', 'translate(60,25)')
.selectAll('path')
.data(segments)
.enter().append('path')
.style('fill', 'none')
.style('stroke-width', 30)
.style('stroke-linecap', function(d, i) {
return i === 0 || i === segments.length - 1 ? 'square' : 'round';
})
.style('stroke', function(d, i) { return color(i); })
.attr('d', d3.line());
// Sample the SVG path uniformly with the specified precision.
function samples(path, precision) {
var n = path.getTotalLength(), t = [0], i = 0, dt = precision;
while ((i += dt) < n) t.push(i);
t.push(n);
return t.map(function(t) {
var p = path.getPointAtLength(t), a = [p.x, p.y];
a.t = t / n;
return a;
});
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment