Question

I am attempting to draw a series of vertical lines on a d3 chart. The data source for this is a list of x positions (in the data) which is mapped through the x() scale function to give the correct position.

At present this is implemented as a for loop for each entry in the labels variable. The y origin and endpoint are taken from the data minY and maxY. A text label is attached to the end of the line.

labels = [
 {
  'x':50,
  'label':test'
 }

 var label = svg.append("g")
        .attr("class","ilabel")

// Labels         
for (var i = 0; i < labels.length; i++) {
    labl = labels[i];

    label.append('line')
        .attr('x1', x( labl.x ) )
        .attr('y1', y( maxY ) )
        .attr('x2', x( labl.x ) 
        .attr('y2', y( minY ) )
        .attr("class","ilabel-line");

    label.append("text")
        .attr("transform", "translate(" +  x( labl.x )+"," + y( maxY )+ ") rotate(-60)")
            .style("text-anchor", "start")
            .attr("dx", ".5em")              
            .attr("class","ilabel-label")

      .text(labl.label);

}

How would I re-write this in a data-driven way i.e. passing the labels in as a .data then iterating over this to draw a series of parallel vertical lines.

var label = svg.selectAll(".ilabel")
      .data(labels)
    .enter().append("g")
      .attr("class","ilabel")

The bit I'm having trouble getting my head around is the x() and y() functions. x() should of course return the x position of the line (which is constant for a given line), but how/what should the y function return to draw a line between two defined points (minY & maxY).

line = d3.svg.line()
  .x(function(d) { return x(d.x); })
  .y(function(d) { return y(d.y); });

label.append('path')
  .attr("d", line)

I feel like I'm missing something obvious.

Was it helpful?

Solution 2

I ended up using rect regions instead as shaded areas in preference to lines. However, returning to this I realised that the code is almost the same for drawing a series of rectangles vs. a series of straight lines. The confusion was arising from the d3 function .line() which is used to generate a path. However you can create a series of straight lines by using svg:line and passing data via a generator function (here wrapped in a dictionary):

var line = {
    'x1':(function(d) { return x( labl.x ); }),
    'y1':(function(d) { return y( maxY ); }),
    'x2':(function(d) { return x( labl.x ); }),
    'y2':(function(d) { return y( minY) }),
    }


var label = svg.selectAll(".labels")
      .data(labels)
      .enter();

    label.append("svg:line")
            .attr("x1", line.x1)
            .attr("y1", line.y1)
            .attr("x2", line.x2)
            .attr("y2", line.y2)
        .attr("class","label-line");

OTHER TIPS

You could just use the axis functions in d3. Have a look at this example on Bl.ocks you can easily set the ticks using tickValues and then the length of the ticks using innerTickSize and outerTicksize. You'll also need to set the orientation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top