Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3 Selection Highlight (efficiency?)

Tags:

d3.js

I have a simple visual of many rects, over 100 I'd say. For aesthetic purposes I want to create a high light effect on mouse click. I also wanted to make this effect somewhat intuitive by removing that effect once the user clicks on a new rect. However I couldn't get this to work without resorting to a d3.selectAll() call, so I'm thinking this approach might not be ideal if this project gets any bigger. Here is the code:

.on('click.highlight', function() {
//set any previously highlighted rects back to normal color/brightness
    d3.selectAll('.highlight').transition().duration(250)
        .style('fill', function(d) { return d3.rgb(d.color)})

    d3.select(this).classed('highlight',true);

//now it's safe to assign the current highlighted rect a brighter hue... i think
    d3.select(this).transition().duration(250)
        .style('fill', function(d) { return d3.rgb(d.color).brighter(.5)})
})

Though this code does what I wanted it to do, but presumably there could only ever be 1 other highlight rect to worry about at any give time. So again, I'm not sure that using d3.selectAll() is warranted here.

So anyway, is there a more efficient way? I'd like to keep it all within one .on('click') function if possible.

like image 246
Arash Howaida Avatar asked May 02 '26 16:05

Arash Howaida


1 Answers

If you are looking to avoid use of .selectAll, you could create a selection of one rect that contains the last clicked rectangle. Each time you click on a rectangle:

  1. unhighlight the previously selected highlighted rect
  2. update that selection to reflect the most recently clicked rectangle
  3. highlight the newly selected rect

I use the variable highlightedRect to hold the selection that will allow the above workflow:

var svg = d3.select("body").append("svg")
  .attr("width",600)
  .attr("height",400);
  
var highlightedRect = d3.select(null);

var rects = svg.selectAll("rect")
  .data(d3.range(1600))
  .enter()
  .append("rect")
  .attr("y",function(d) { return Math.floor(d/50)*12; })
  .attr("x",function(d) { return d%50 * 12 })
  .attr("width",11)
  .attr("height",11)
  .attr("stroke","white")
  .on("click",function(d) {
    // Recolor the last clicked rect.
    highlightedRect.attr("fill","black");
    // Color the new one:
    highlightedRect = d3.select(this);
    highlightedRect.attr("fill","steelblue");
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
like image 85
Andrew Reid Avatar answered May 07 '26 03:05

Andrew Reid



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!