Accessing SVG path length in d3

d3.js

Solution

You could add the total length of the path as another attribute to the data and then use that:

path.each(function(d) { d.totalLength = this.getTotalLength(); })
    .attr("stroke-dasharray", function(d) { return d.totalLength + " " + d.totalLength; })
    .attr("stroke-dashoffset", function(d) { return d.totalLength; })
// etc

Problem

I've put together a multi line chart which has a transition set so the lines are 'drawn' and labels attached one after the other. It works but I can't see how to access the length of each line individually. The code that I have returns the length for the first path only via `.node()`. The result of this is that all paths are given the length of the first which gives incorrect start points for the other paths. The code is below. Any help is much appreciated. ``` var margin = {top: 20, right: 80, bottom: 30, left: 60}, width = 600 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; var x = d3.scale.ordinal() .rangePoints([0, width], 1); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.category20(); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var line = d3.svg.line() .interpolate("linear") .x(function(d) { return x(d.month); }) .y(function(d) { return y(d.rainfall); }); var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.csv("data.csv", function(error, data) { color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Month"; })); var countries = color.domain().map(function(country) { return { country: country, values: data.map(function(d) { return {month: d.Month, rainfall: +d[country]}; }) }; }); x.domain(data.map(function(d) { return d.Month; })); y.domain([ d3.min(countries, function(c) { return d3.min(c.values, function(v) { return v.rainfall - 7; }); }), d3.max(countries, function(c) { return d3.max(c.values, function(v) { return v.rainfall + 7; }); }) ]); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", "1.1em") .style("text-anchor", "end") .text("Rainfall (mm)"); var country = svg.selectAll(".country") .data(countries) .enter().append("g") .attr("class", "country"); var path = country.append("path") .attr("id", function(d, i) { return "line" + i; }) .attr("class", "line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) { return color(d.country); }) var totalLength = path.node().getTotalLength(); path.attr("stroke-dasharray", totalLength + " " + totalLength) .attr("stroke-dashoffset", totalLength) .transition() .delay(function(d, i) { return i * 1000; }) .duration(1000) .ease("linear") .attr("stroke-dashoffset", 0) .each("end", function() { labels.transition() .delay(function(d, i) { return i * 1000; }) .style("opacity", 1); }); var labels = country.append("text") .datum(function(d) { return {country: d.country, value: d.values[d.values.length - 1]}; }) .attr("class", "label") .attr("transform", function(d) { return "translate(" + x(d.value.month) + "," + y(d.value.rainfall) + ")"; }) .attr("x", 3) .attr("dy", ".35em") .style("opacity", 0) .text(function(d) { return d.country; }); ``` });

Original source