Search code examples
javascriptd3.jssvgchartssvg-path

How to connect dots in D3 with a line?


I've pulled out some data and after scaling, I draw a bunch of circles. This works just great.

var gSet = graph1.selectAll("g").data(data).enter().append("g");
gSet.append("circle")
  .attr({ cx: posX, cy: posY, r: dotSize })
  .attr("class", "dataPoint");

Now, I'd like to connect the dots. Most examples I've seen are about bars, not lines so I've googled some more line charts and decided to use path element, like so.

var gSet = graph1.selectAll("g").data(data).enter().append("g");
gSet.append("circle")
  .attr({ cx: posX, cy: posY, r: dotSize })
  .attr("class", "dataPoint");
gSet.append("path")
  .attr("d", d3.svg.line().x(posX).y(posY))
  .attr({ "stroke": "yellow", "stroke-width": "1" });

Nothing new appears on the screen and due to ignorance, I'm not sure where to poke to see what went wrong.

  1. Should I be using path (or is line, polyline etc. a better choice)?
  2. Should I be working with the d attribute or is there a more suited one?
  3. Should I be applying the d3.svg.line() function or is there a smoother way?

Solution

  • I happen to have done something similar to what I think you intend, so I'll just paste it as-is in this jsfiddle, and it will show you one possible way to connect your lines. This one is more of a parent/child graph, but that is just based on the data. you could remove the parent property and just link each node to the previous node instead.

    to answer your questions:

    1. you could use path, but it's a bit overkill if you just want straight lines. if your case is simple, then I recommend line.

    2. if using a path object, the d property will describe the shape of your path. with D3js people often use d as one of two optional parameters into anonymous methods (with d being the data, and i being the incrementing counter).

    3. you could use the d3.svg.line() function to describe the shape and position of your line, but if your data is as simple as it sounds then that might be overkill - consider just appending line objects as shown in my code below. my recommendation would be to go with a path if you need "fancy lines", but that's just my comfort area and there are likely other ways.

    for my approach, the code ends up looking like this

    var items = svg.selectAll("g").data(srcData).enter().append("g");
    items.each(function(d, i){
        d3.select(this).attr("transform","translate("+d.posx+","+d.posy+")");
    
        if(d.parentid > 0)
            d3.select(this).append("line")
                .attr("x",0)
                .attr("y",0)
                .attr("x1",function(d){ return -1*(d.posx - parent(d.parentid).posx); })
                .attr("y1",function(d){ return -1*(d.posy - parent(d.parentid).posy); })
                .style("stroke",d.color)
                .style("stroke-width",2);
    
        d3.select(this).append("circle")
            .attr("r",5)
            .style("fill",d.color);
    });