Nasir
Nasir

Reputation: 2122

How to draw a path smoothly from start point to end point in D3.js

I have the following code which plots a line path based on sine function:

var data = d3.range(40).map(function(i) {
  return {x: i / 39, y: (Math.sin(i / 3) + 2) / 4};
});

var margin = {top: 10, right: 10, bottom: 20, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var x = d3.scale.linear()
    .domain([0, 1])
    .range([0, width]);

var y = d3.scale.linear()
    .domain([0, 1])
    .range([height, 0]);


var line = d3.svg.line()
          .interpolate('linear')
          .x(function(d){ return x(d.x) })
          .y(function(d){ return y(d.y) });

var svg = d3.select("body").append("svg")
    .datum(data)
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append("path")
    .attr("class", "line")
    .attr("d", line);

svg.selectAll('.point')
   .data(data)
   .enter().append("svg:circle")
   .attr("cx", function(d, i){ return x(d.x)})
   .attr("cy", function(d, i){ return y(d.y)})
   .attr('r', 4);

What I want to do is to plot it smoothly from the first node to last node. I also want to have a smooth transition between two consecutive nodes and not just putting the whole line at once. Simply like connecting the dots using a pencil.

Any help would be really appreciated.

Upvotes: 18

Views: 22375

Answers (2)

Jakub Šebök
Jakub Šebök

Reputation: 31

For those as me using actual SVG tags in JSX with CSS: You can re-write the solution from @methodofaction like this:

@keyframes animate-line {
    0% {
        stroke-dashoffset: 100;
        stroke-dasharray: 100;
    }
    100% {
        stroke-dashoffset: 0;
    }
}
.animate {
    animation-delay: 0.5s;
    animation-duration: 2s;
    animation-timing-function: linear;
    animation-name: animate-line;
}

then add .animate class to your JSX:


<path
    ...
    /* Has to be the same value as in CSS for stroke-dashoffset */
    pathLength={100} 
    className={styles.animate}
/>

I wasn't able to make it work with transition property on mount, but I guess animation is good as well here. I hope that helps someone...

Upvotes: 0

methodofaction
methodofaction

Reputation: 72385

You can animate paths quite easily with stroke-dashoffset and and path.getTotalLength()

var totalLength = path.node().getTotalLength();

path
  .attr("stroke-dasharray", totalLength + " " + totalLength)
  .attr("stroke-dashoffset", totalLength)
  .transition()
    .duration(2000)
    .ease("linear")
    .attr("stroke-dashoffset", 0);

http://bl.ocks.org/4063326

Upvotes: 40

Related Questions