Area chart with brushing and zoom in d3.js

This post describes how to build an area chart with d3.js. It is also possible to selection a section of the X axis (brushing) to zoom on it. This is a great use of interactivity since it allows to explore more in details the content of your data.

Area chart section


  • Brush the chart to zoom. Double click to re-initialize.

  • Start by understanding how to build a basic area chart, and how brushing works in d3.js.

  • A class myArea is added to the line. It allows to select this class later on to update the line position.

  • It is possible to react to double click thanks to the on("dblclick",...) function.
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src=""></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - - margin.bottom;

// append the svg object to the body of the page
var svg ="#my_dataviz")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + + margin.bottom)
          "translate(" + margin.left + "," + + ")");

//Read the data

  // When reading the csv, I must format variables:
    return { date : d3.timeParse("%Y-%m-%d")(, value : d.value }

  // Now I can use this dataset:
  function(data) {

    // Add X axis --> it is a date format
    var x = d3.scaleTime()
      .domain(d3.extent(data, function(d) { return; }))
      .range([ 0, width ]);
    xAxis = svg.append("g")
      .attr("transform", "translate(0," + height + ")")

    // Add Y axis
    var y = d3.scaleLinear()
      .domain([0, d3.max(data, function(d) { return +d.value; })])
      .range([ height, 0 ]);
    yAxis = svg.append("g")

    // Add a clipPath: everything out of this area won't be drawn.
    var clip = svg.append("defs").append("svg:clipPath")
        .attr("id", "clip")
        .attr("width", width )
        .attr("height", height )
        .attr("x", 0)
        .attr("y", 0);

    // Add brushing
    var brush = d3.brushX()                   // Add the brush feature using the d3.brush function
        .extent( [ [0,0], [width,height] ] )  // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
        .on("end", updateChart)               // Each time the brush selection changes, trigger the 'updateChart' function

    // Create the area variable: where both the area and the brush take place
    var area = svg.append('g')
      .attr("clip-path", "url(#clip)")

    // Create an area generator
    var areaGenerator = d3.area()
      .x(function(d) { return x( })
      .y1(function(d) { return y(d.value) })

    // Add the area
      .attr("class", "myArea")  // I add the class myArea to be able to modify it later on.
      .attr("fill", "#69b3a2")
      .attr("fill-opacity", .3)
      .attr("stroke", "black")
      .attr("stroke-width", 1)
      .attr("d", areaGenerator )

    // Add the brushing
        .attr("class", "brush")

    // A function that set idleTimeOut to null
    var idleTimeout
    function idled() { idleTimeout = null; }

    // A function that update the chart for given boundaries
    function updateChart() {

      // What are the selected boundaries?
      extent = d3.event.selection

      // If no selection, back to initial coordinate. Otherwise, update X axis domain
        if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
        x.domain([ 4,8])
        x.domain([ x.invert(extent[0]), x.invert(extent[1]) ])".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done

      // Update axis and area position
          .attr("d", areaGenerator)

    // If user double click, reinitialize the chart
      x.domain(d3.extent(data, function(d) { return; }))
        .attr("d", areaGenerator)



Related blocks →