A less-sophisticated alternative to Mike Bostock's Gradient Along Stroke.
Note that this version does not compute mitre joints, so sharp bends reveal the segmented nature of the "path."
A less-sophisticated alternative to Mike Bostock's Gradient Along Stroke.
Note that this version does not compute mitre joints, so sharp bends reveal the segmented nature of the "path."
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <meta charset="utf-8"> | |
| </head> | |
| <body> | |
| <script src="script.js"></script> | |
| </body> | |
| </html> |
| var margin = { top: 50, left: 50, bottom: 50, right: 50 }, | |
| width = window.innerWidth - margin.left - margin.right, | |
| height = window.innerHeight - margin.top - margin.bottom, | |
| vbWidth = width + margin.left + margin.right, | |
| vbHeight = height + margin.top + margin.bottom; | |
| var main = d3.select("body").append("main") | |
| .style({ width: "90%", margin: "0 auto 0 auto" }) | |
| .append("svg") | |
| .attr({ viewBox: "0 0 " + vbWidth + " " + vbHeight }) | |
| .append("g") | |
| .attr({ | |
| transform: "translate(" + [margin.left, margin.top] + ")" | |
| }); | |
| main.append("rect").attr({ | |
| width: width, height: height, fill: "none" | |
| }); | |
| var random = d3.random.normal(); | |
| var data = d3.range(10).map(function(d) { | |
| return { x: random(), y: random() }; | |
| }); | |
| var x = d3.scale.linear() | |
| .domain(d3.extent(data, function(d) { return d.x; })) | |
| .range([0, width]); | |
| var y = d3.scale.linear() | |
| .domain(d3.extent(data, function(d) { return d.y; })) | |
| .range([0, height]); | |
| var dots = main.selectAll(".dot").data(data); | |
| dots.enter().append("circle").classed("dot", true) | |
| .attr({ r: 5 }) | |
| .style({ opacity: 0.2 }) | |
| dots.attr({ | |
| cx: function(d) { return x(d.x); }, | |
| cy: function(d) { return y(d.y); } | |
| }); | |
| var line = d3.svg.line().interpolate("basis") | |
| .x(function(d) { return x(d.x); }) | |
| .y(function(d) { return y(d.y); }); | |
| var points = getPoints(line(data), 2); | |
| var segs = []; | |
| points.reduce(function(prev, curr) { | |
| segs.push({ | |
| x1: prev.x, y1: prev.y, x2: curr.x, y2: curr.y, t: curr.t | |
| }); | |
| return curr; | |
| }); | |
| var segmentContainer = main.selectAll(".segments").data([segs]); | |
| segmentContainer.enter().append("g").classed("segments", true); | |
| var segments = segmentContainer.selectAll(".segment").data(Object); | |
| segments.enter().append("line"); | |
| var i = d3.interpolateRgb("green", "red"); | |
| segments | |
| .attr({ | |
| x1: function(d) { return d.x1; }, y1: function(d) { return d.y1; }, | |
| x2: function(d) { return d.x2; }, y2: function(d) { return d.y2; }, | |
| stroke: function(d) { return i(d.t); }, | |
| "stroke-width": 10, "stroke-opacity": 0.1 | |
| }) | |
| .transition() | |
| .delay(function(d, i) { return i; }) | |
| .attr("stroke-opacity", 1); | |
| segments.exit().remove(); | |
| // Based on: //gist.github.com/mbostock/4163057 | |
| // Sample the SVG path string "d" uniformly with the specified precision. | |
| function getPoints(d, step) { | |
| var path = document.createElementNS(d3.ns.prefix.svg, "path"); | |
| path.setAttribute("d", d); | |
| var length = path.getTotalLength(); | |
| return d3.range(0, length, step) | |
| .map(function(t) { | |
| var point = path.getPointAtLength(t); | |
| return { x: point.x, y: point.y, t: t/length }; | |
| }); | |
| } |