1

While multiple classes can be assigned to one id, but can one assign multiple ids to a class? If yes, then I will save a lot of time / computational resources.

I tried:

d3.select('#id1','#id2').classed('my_class',true);

I also tried js styling in this manner:

d3.select('#id1','#id2').style('display','none');

Only the first id works.

Is there a succinct way to handle such a case? I would be surprised if there wasn't a work-around in some shape or form. I just can't find one in this situation.

Arash Howaida
  • 2,575
  • 2
  • 19
  • 50
  • 2
    If d3 uses css/jquery like selection it's probably just `d3.select('#id1, #id2')` edit they do [D3 Selecting Elements](https://github.com/d3/d3-selection#selecting-elements) – Patrick Barr Mar 23 '17 at 17:48
  • Interesting thought. I tried it just now, no dice. Must be slightly different than jquery – Arash Howaida Mar 23 '17 at 17:51
  • So if I understand correctly, you want to apply some styling to multiple elements whose ids are in the form `id1, id2, id3...`? – sparta93 Mar 23 '17 at 17:52
  • @ArashHowaida If that's not a solution then I'm afraid I can't be of much more help – Patrick Barr Mar 23 '17 at 17:53
  • @sparta93 Actually I just used that since it was easy notation. My real id names are not of any type of pattern. Just names. – Arash Howaida Mar 23 '17 at 17:57
  • Does this help? http://stackoverflow.com/questions/15702724/how-to-select-multiple-selectors-with-selectall – mrsq Mar 23 '17 at 17:58
  • @mrsq Hmm, yea, that's interesting. So I guess I need to use `selectAll` instead of `select`. It works this way. I'm not sure if there is a big trade-off in efficiency or not. – Arash Howaida Mar 23 '17 at 18:03

2 Answers2

5

The comments below the question have all the information to fix the problem. However, for future readers, I'd like to write some points here.

First of all: always read the documentation. With few exceptions, it has all information you need. For instance, let's see what it says about select:

Selects the first element that matches the specified selector string. (emphases mine)

Now let's see your code:

d3.select('#id1','#id2')
//              ^--------- two strings, separated by a comma

That's not a string. This is a string:

d3.select('#id1, #id2')
//              ^--------- just one string here!

Second problem: select selects the first element that matches the string. So, you want selectAll, not select.

Solution: it has to be:

d3.selectAll("#id1, #id")

Here is a demo, click the button:

d3.select("button").on("click", function() {
  d3.selectAll("#c2, #c5").attr("fill", "brown");
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<button>Click me</button>
<svg>
  <circle id="c1" cx="20" cy="30" r="10" fill="teal"></circle>
  <circle id="c2" cx="60" cy="30" r="10" fill="teal"></circle>
  <circle id="c3" cx="100" cy="30" r="10" fill="teal"></circle>
  <circle id="c4" cx="140" cy="30" r="10" fill="teal"></circle>
  <circle id="c5" cx="180" cy="30" r="10" fill="teal"></circle>
</svg>
Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
  • 3
    Since OP is particularly concerned about performance issues, it is worth noting, that this approach is by far outperformed by the solution brought forward by Nobita's [answer](http://stackoverflow.com/a/42986738/4235784). Although, admittedly, this looks much cleaner and more intuitive and—as usual—comes with a nice explanation. – altocumulus Mar 24 '17 at 00:31
  • 1
    @altocumulus thanks for the appreciation but - surprisingly? - I would argue that Gerardo's approach is probably more performant. Instead of selecting multiple times it's always better to select once, and that's what selectAll does as it uses querySelectorAll under the hood (see [here](https://github.com/d3/d3-selection/blob/master/src/selection/selectAll.js) and [here](https://github.com/d3/d3-selection/blob/master/src/selectorAll.js#L7) in the source). Also, it's more idiomatic for D3, Hence I upvoted his answer. – Aurelio Mar 24 '17 at 08:36
  • 2
    @Nobita Although this might intuitively seem logical, your approach is in fact *way* faster than Gerardo's. Executing my [performance test](https://jsperf.com/d3-multi-select-by-id) on Chrome the test case #2, which implements your answer, is more than ten times faster then this answer's approach. Substituting the inner selection with the native `document.getElementById()` will further double that speed. The results vary across browers, with the browser*esque* IE 11 being the slowest, but are all faster than using a complex selector string. – altocumulus Mar 24 '17 at 10:06
  • @altocumulus I am a bit surprised but won't argue with that! Can't beat perf tests :D – Aurelio Mar 24 '17 at 10:51
  • 1
    Wow very interesting, thanks for explaining the efficiency dimension so well. On a side note, I don't mean to upsell or anything, but your circle example reminded me that I have an unanswered d3 post [here](http://stackoverflow.com/questions/42958915/d3-geo-circle-in-miles), if there is political will to look it over :) – Arash Howaida Mar 25 '17 at 04:11
  • @ArashHowaida if a question has not received attention, you can always set a bounty. Normally, the question itself is so upvoted (I just did it) that you end up receiving your bounty back. – Gerardo Furtado Mar 25 '17 at 04:22
4

You can store your IDs in an array and map over it

var ids = ['#g1', '#g2']

ids.map(el => d3.select(el).classed('red', true))

See here or here below:

var ids = ['#g1', '#g2']

ids.map(el => d3.select(el).classed('red', true));
div {
  display: inline-block;
  height: 20px;
  width: 300px;
  background: teal;
}

.red {
  background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="g1"></div>
<div id="g2"></div>
<div id="g3"></div>
<div id="g4"></div>
Aurelio
  • 24,702
  • 9
  • 60
  • 63