D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
FrissAnalytics
Full window
Github gist
gradient path
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> <style> body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } </style> </head> <body> <svg width="500" height="500"> <path fill="none" stroke-width="10"></path> </svg> <script> var c = [250, 250]; // center var r = 200; // radius var complete = 0.8; // percent var circlePath = ` M ${c[0]} ${c[1]-r} a ${r},${r} 0 1,0 0, ${(r * 2)} a ${r},${r} 0 1,0 0, -${(r * 2)} Z `; var colorInterpolator = d3.interpolateRgbBasis(["rgb(225, 65, 118)", "rgb(108, 125, 255)", "rgb(225, 65, 118)"]); var colorHandler = (d, i, nodes) => { let color = d3.color(colorInterpolator(d.t)); color.opacity = i/nodes.length > 1-complete ? 1 : 0; return color; }; var path = d3.select("path").attr("d", circlePath).remove(); console.time("[gradient stroke performance]"); d3.select("svg").selectAll("path") .data(quads(samples(path.node(), 8))) .enter().append("path") .style("fill", colorHandler) .style("stroke", colorHandler) .style("stroke-width", 30) .style("stroke-linecap", (d, i, all) => i === 0 || i === all.length ? "round" : "round" ) .attr("d", d => lineJoin(d[0], d[1], d[2], d[3], 32) ); console.timeEnd("[gradient stroke performance]"); // 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; }); } // Compute quads of adjacent points [p0, p1, p2, p3]. function quads(points) { return d3.range(points.length - 1).map(function(i) { var a = [points[i - 1], points[i], points[i + 1], points[i + 2]]; a.t = (points[i].t + points[i + 1].t) / 2; return a; }); } // Compute stroke outline for segment p12. function lineJoin(p0, p1, p2, p3, width) { var u12 = perp(p1, p2), r = width / 2, a = [p1[0] + u12[0] * r, p1[1] + u12[1] * r], b = [p2[0] + u12[0] * r, p2[1] + u12[1] * r], c = [p2[0] - u12[0] * r, p2[1] - u12[1] * r], d = [p1[0] - u12[0] * r, p1[1] - u12[1] * r]; if (p0) { // clip ad and dc using average of u01 and u12 var u01 = perp(p0, p1), e = [p1[0] + u01[0] + u12[0], p1[1] + u01[1] + u12[1]]; a = lineIntersect(p1, e, a, b); d = lineIntersect(p1, e, d, c); } if (p3) { // clip ab and dc using average of u12 and u23 var u23 = perp(p2, p3), e = [p2[0] + u23[0] + u12[0], p2[1] + u23[1] + u12[1]]; b = lineIntersect(p2, e, a, b); c = lineIntersect(p2, e, d, c); } return "M" + a + "L" + b + " " + c + " " + d + "Z"; } // Compute intersection of two infinite lines ab and cd. function lineIntersect(a, b, c, d) { var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); return [x1 + ua * x21, y1 + ua * y21]; } // Compute unit vector perpendicular to p01. function perp(p0, p1) { var u01x = p0[1] - p1[1], u01y = p1[0] - p0[0], u01d = Math.sqrt(u01x * u01x + u01y * u01y); return [u01x / u01d, u01y / u01d]; } </script> </body>
https://d3js.org/d3.v4.min.js