Search code examples
d3.jsbrush

d3.js I have multiple brush area. How can I cancel brush region in other area when I brush a new region?


I have a svg, and many gs in this svg.

for (let j = 0; j < 3; j++) {
    let rx = 400 * j, ry = 100, rw = 300, rh = 300;
    let g = svg.append("g")
        .attr("x", rx).attr("y", ry)
        .attr("width", rw).attr("height", rh);
}

And I create a brush for each g:

for (let j = 0; j < 3; j++) {
    let rx = 400 * j, ry = 100, rw = 300, rh = 300;
    let g = svg.append("g")
        .attr("x", rx).attr("y", ry)
        .attr("width", rw).attr("height", rh);

    g.call(d3.brush()
        .extent([[rx,ry], [rx+rw,ry+rh]])
        .on("start brush", function (e){
            svg.selectAll("g").call(d3.brush().clear);
            let extent = e.selection;
            //do something
            })
    );
}

The codes above cause a error because:
Uncaught RangeError: Maximum call stack size exceeded
How can I do this in other way?\

let width = 2000;
let height = 1200;
let svg = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

for (let j = 0; j < 3; j++) {
  let rx = 400 * j,
    ry = 100,
    rw = 300,
    rh = 300;
  let g = svg.append("g")
    .attr("x", rx).attr("y", ry)
    .attr("width", rw).attr("height", rh);

  g.append("rect")
    .attr("x", rx).attr("y", ry)
    .attr("width", rw).attr("height", rh)
    .attr("fill", "white")
    .attr("stroke", "black");

  g.call(d3.brush()
    .extent([
      [rx, ry],
      [rx + rw, ry + rh]
    ])
    .on("start brush", function(e) {
      svg.selectAll("g").call(d3.brush().clear);
      let extent = e.selection;
    })
  );
}
<script src="https://d3js.org/d3.v7.min.js" charset="utf-8"></script>


Solution

  • brush and start are two different events, and there will never be a brush that is not preceded by a start, so you can omit the brush here. That way, the code is not constantly triggering itself and the infinite loop recursion is avoided:

    let width = 2000;
    let height = 1200;
    let svg = d3.select("body")
      .append("svg")
      .attr("width", width)
      .attr("height", height);
    
    for (let j = 0; j < 3; j++) {
      let rx = 400 * j,
        ry = 100,
        rw = 300,
        rh = 300;
      let g = svg.append("g")
        .attr("x", rx).attr("y", ry)
        .attr("width", rw).attr("height", rh);
    
      g.append("rect")
        .attr("x", rx).attr("y", ry)
        .attr("width", rw).attr("height", rh)
        .attr("fill", "white")
        .attr("stroke", "black");
    
      g.call(d3.brush()
        .extent([
          [rx, ry],
          [rx + rw, ry + rh]
        ])
        .on("start", function(e) {
          svg.selectAll("g").call(d3.brush().clear);
          let extent = e.selection;
        })
      );
    }
    <script src="https://d3js.org/d3.v7.min.js" charset="utf-8"></script>