Day 18: D3 Brush

Today I worked on adding brush to the line chart (the one we created on Day 11). The brush functionality can allow users to zoom in on the data in the main chart while keeping the context of the timeline.

Layout

What we need to do first is to set up the focus and context area. Then we will need to create two sets of xScale and yScale to use for focus group elements and context group elements.

Brush Event

Below is how we set up the brush event. We call the brush event on the context.

const brush = d3.brushX()
    .handleSize(10)
     .extent([[0,0],[chartWidth,chartHeight]])
    .on("brush", brushed)
    
context.append("g")
    .attr("class", "brush")
    .call(brush)

What we need to do in the brushed function is as follows.

  1. Get the domain of the area being brushed in the context group
  2. Update the x-axis of the focus area using the domain obtained in Step 1
  3. Redraw the line in the focus area
function brushed(event) {
        xScale.domain(event.selection.map(xScale2.invert))
      
        focus.select(".x-axis")
        .call(d3.axisBottom().scale(xScale))
    
        line.attr("d", endLineGenerator(dataset))
    
      }

Here is what we got. Hmm, it works fine, but there is some line going over the y-axis in the focus area. The reason is that the line element in the focus area is still drawing using the whole dataset, but with the new domain on the x-axis. The solution is to add a Clip Path to our line. It’s like cropping out the parts we don’t want in our pictures.

focus.append("clipPath")
        .attr("id", "clip")
        .append("rect")
        .attr("width", chartWidth)
        .attr("height", chartHeight)

const line = focus.append("path")
        .attr("class","line")
        .attr("d", endLineGenerator(dataset))
        .attr("fill","none")
        .attr("stroke","gray")
        .attr("stroke-width",1.5)
        .attr("clip-path","url(#clip)")

Codes.

Leave a comment