Using a line generator

D3 line generator is probably one of the most versatile generators. Though it is called a "line" generator, it has little to do with the svg:line element. In contrast, it is implemented using the svg:path element. Like svg:path, D3 line generator is so flexible that you can effectively draw any shape using line alone, however, to make your life easier, D3 also provides other more specialized shape generators, which will be covered in later recipes in this chapter. In this recipe, we will draw multiple data-driven lines using the d3.svg.line generator.

Getting Ready

Open your local copy of the following file in your web browser:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter7/line.html

How to do it...

Now, let's see the line generator in action:

<script type="text/javascript">
    var width = 500,
        height = 500,
        margin = 50,
        x = d3.scale.linear() // <-A
            .domain([0, 10])
            .range([margin, width - margin]),
        y = d3.scale.linear() // <-B
            .domain([0, 10])
            .range([height - margin, margin]);
        
    var data = [ // <-C
        [
            {x: 0, y: 5},{x: 1, y: 9},{x: 2, y: 7},
            {x: 3, y: 5},{x: 4, y: 3},{x: 6, y: 4},
            {x: 7, y: 2},{x: 8, y: 3},{x: 9, y: 2}
        ],
        
        d3.range(10).map(function(i){
            return {x: i, y: Math.sin(i) + 5};
        })
    ];
    
    var line = d3.svg.line() // <-D
            .x(function(d){return x(d.x);})
            .y(function(d){return y(d.y);});
        
    var svg = d3.select("body").append("svg");
    
    svg.attr("height", height)
        .attr("width", width);
        
     svg.selectAll("path.line")
            .data(data)
        .enter()
            .append("path") // <-E
            .attr("class", "line")            
            .attr("d", function(d){return line(d);}); // <-F
            
    // Axes related code omitted
    ...        
</script>

The preceding code draws multiple lines along with the x and y axes:

How to do it...

D3 line generator

How it works...

In this recipe, the data we used to draw the lines are defined in a two-dimensional array:

var data = [ // <-C
        [
            {x: 0, y: 5},{x: 1, y: 9},{x: 2, y: 7},
            {x: 3, y: 5},{x: 4, y: 3},{x: 6, y: 4},
            {x: 7, y: 2},{x: 8, y: 3},{x: 9, y: 2}
        ],
        
        d3.range(10).map(function(i){
            return {x: i, y: Math.sin(i) + 5};
        })
];

The first data series is defined manually and explicitly, while the second series is generated using a mathematical formula. Both of these cases are quite common in data visualization projects. Once the data is defined, then in order to map data points to its visual representation, two scales were created for the x and y coordinates:

x = d3.scale.linear() // <-A
            .domain([0, 10])
            .range([margin, width - margin]),
y = d3.scale.linear() // <-B
            .domain([0, 10])
            .range([height - margin, margin]);

Notice that the domains for these scales were set to be large enough to include all data points in both the series, while the range were set to represent the canvas area without including the margins. The y-axis range is inverted since we want our point of origin at the lower-left corner of the canvas instead of the SVG-standard upper-left corner. Once both data and scales are set, all we need to do is generate the lines to define our generator using the d3.svg.line function:

var line = d3.svg.line() // <-D
            .x(function(d){return x(d.x);})
            .y(function(d){return y(d.y);});

The d3.svg.line function returns a D3 line generator function which you can further customize. In our example, we simply stated for this particular line generator the x coordinate, which will be calculated using the x scale mapping, while the y coordinate will be mapped by the y scale. Using D3 scales, to map coordinates, is not only convenient but also a widely accepted best practice (separation of concerns). Though, technically you can implement these functions using any approach you prefer. Now the only thing left to do is actually create the svg:path elements.

svg.selectAll("path.line")
            .data(data)
        .enter()
            .append("path") // <-E
            .attr("class", "line")            
            .attr("d", function(d){return line(d);}); // <-F

Path creation process was very straightforward. Two svg:path elements are created using the data array we defined (on line E). Then the d attribute for each path element was set using the line generator we created previously by passing in the data d as its input parameter. The following screenshot shows what the generated svg:path elements look like:

How it works...

Generated SVG path elements

Finally two axes are created using the same x and y scales we defined earlier. Due to limited scope in this book, we have omitted the axes-related code in this recipe and in the rest of this chapter, since they don't really change and also are not the focus of this chapter.

See also

  • For detailed information on D3 axes support please visit Chapter 5, Play with Axes
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset