简体   繁体   中英

Is querySelectorAll a good way to select elements in multiple charts?

I would like to highlight elements from the same dimension (Country in this example) in multiple charts. Assigning a class to each country at the point of generation of rect or circle and then using querySeletorAll to find all matching elements seems to work, but I wonder if there is a better way. This feels a little hack-y.

Please see this block for a working demo.

Both the bar chart and the scatter have classes assigned to their elements ( rect and circle ) in the same way:

var enter = svgContainer.selectAll('rect')
  .data(data)
  .enter().append('rect')
  .attr('class', function(d) { return "mycharts_bars_" + d.Country; })

And then the highlight on hover does this:

  .on("mouseover", function(d) { 

  var hover_value = this.__data__.Country; 
  var hover_elems = document.querySelectorAll(`[class*="${hover_value}"]`);

  for (let item of hover_elems) {
    item.setAttribute('fill', 'hotpink');}
    })

As you can see in the source code , d3.selectAll already uses document.querySelectorAll internally:

export default function(selector) {
  return typeof selector === "string"
      ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
      : new Selection([selector == null ? [] : selector], root);
}

So, you can safely use selectAll , which makes your code more idiomatic for D3 programmers.

However, there are some issues in your code:

First, you don't need that var hover_value = this.__data__.Country; . You already have the datum as the first argument! Therefore, it can be just d.Country .

Secondly, you don't need to deal with classes if you don't want, just select the element. You can use classes if you want, that's not a big problem, but you definitely don't need that for...of loop. As a rule of thumb, do not use loops in a D3 code (there are specific situations where they are needed, but not this one).

All that being said, the function can be simply this:

d3.selectAll("circle, rect").attr("fill", function(e) {
    return e.Country === d.Country ? "pink" : "grey"
});

Or, since only the rectangle hovered over will change colour:

d3.select(this).attr("fill", "pink");
d3.selectAll("circle").attr("fill", function(e) {
    return e.Country === d.Country ? "pink" : "grey"
});

As a side note, this will change all selected elements in the page. I'm doing this only because, in your example, you have very few elements. If in your real chart you have hundreds of elements a better solution is first filtering them and after that applying the changes (both on mouseover and mouseout ), which gives you better performance.

Here is your code with that change: https://blockbuilder.org/GerardoFurtado/e54f2f0cc711b51be4b400627cac6f51

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM