Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

draw a line from one circle to another in d3.js

I will explain the problem that I have in my real project. I am consuming a web service and this returns me n points x, y. I'm simulating the web service with a settimeout. I want to put a circle in those coordinates and for each circle I want to draw a line that connects them. like this:

enter image description here

I would like to add a line between the circles but showing an animation. like this:

http://bl.ocks.org/duopixel/4063326

for example this animation, but point by point

when I run my application I want the line to have an animation from the initial circle to the end. and if I add a new circle I want a line to be created and have an animation to the circle. How can I do it?

http://jsfiddle.net/2rv0o8da/

  var svg = d3.select('svg');

  var dataSet = [10, 20, 30, 40];
  function display(data){
  var circle = svg.selectAll('circle')
      .data(data)
      .enter()
      .append('circle')
      .attr({
          r:function(d){ return d },
          cx:function(d, i){ return i * 100 + 50 },
          cy:50,
          fill: 'red'
      });
  } 
  display(dataSet);


  setTimeout(function(){
    display([5]);
  },2000)
like image 316
yavg Avatar asked Sep 24 '17 04:09

yavg


1 Answers

Answering how to connect the dots:

For creating the path that connect your circles, you just have to create a line generator which uses the same data.

For instance, this will create an array with 10 objects, each one having a x and a y position:

var dataSet = d3.range(10).map(function(d) {
    return {x: someValue, y: someValue}
});

So, since we use those properties to position the circles, we just use the same properties in the line generator:

var lineGenerator = d3.svg.line()
    .x(function(d) {return d.x})
    .y(function(d) {return d.y})
    .interpolate("monotone")

Then, use the function in the bl.ocks you linked:

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

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

Here is the demo:

var svg = d3.select('svg');

var backLayer = svg.append("g");
var frontLayer = svg.append("g");

var dataSet = d3.range(10).map(function(d) {
  return {
    x: d * 30 + 10,
    y: Math.random() * 130 + 10
  }
});

var lineGenerator = d3.svg.line()
  .x(function(d) {
    return d.x
  })
  .y(function(d) {
    return d.y
  })
  .interpolate("monotone")

function displayCircles(data) {
  var circle = frontLayer.selectAll(null)
    .data(data)
    .enter()
    .append('circle')
    .attr({
      r: 6,
      cx: function(d) {
        return d.x
      },
      cy: function(d) {
        return d.y
      },
      fill: 'white',
      stroke: "black",
      "stroke-width": "3px"
    });
};

function displayLine(data) {
  var line = backLayer.append("path")
    .datum(data)
    .attr({
      d: lineGenerator(data),
      fill: 'none',
      stroke: "red",
      "stroke-width": "3px",
      "shape-rendering": "geometricPrecision"
    });

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

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

displayCircles(dataSet);

setTimeout(function() {
  displayLine(dataSet)
}, 1000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg></svg>
like image 74
Gerardo Furtado Avatar answered Oct 17 '22 12:10

Gerardo Furtado