The behavior you witnessed is expected and it is well documented:
# selection.merge(other) · Source
This method is not intended for concatenating arbitrary selections, however: if both this selection and the specified other selection have (non-null) elements at the same index, this selection’s element is returned in the merge and the other selection’s element is ignored.
This explains why only the #g1
element is selected after the merge operation.
Although there are multiple ways doing this, my preferred and, maybe the most elegant way, was made possible with the release of D3 v6. Selections now implement an iterator and are thus iterable themselves making them accessible for many language feature introduced by ES6! In general, concatenating arrays can easily be implemented using spread syntax:
const concatArray = [...array1, array2];
Since selection are now iterable you can concatenate their respective nodes the same way:
const concatNodes = [...selection1, ...selection2];
Apart from being iterable, selections can also be created by passing in an iterable object which results in the following code for merging two selections:
const mergedSelection = d3.selectAll([...selection1, ...selection2]);
Given your example this can be implemented as follows:
const s0 = d3.selectAll("g");
s0.style("fill", "red"); // works, all are red;
const s1 = d3.select("g#g1");
const s2 = d3.select("g#g2");
const s3 = d3.selectAll([...s1, ...s2]);
s3.style("fill", "blue"); // works, all are blue
<script src="https://d3js.org/d3.v6.js"></script>
<svg>
<g id="g1" class="testg"><text x="20" y="20">bla1</text></g>
</svg>
<svg>
<g id="g2" class="testg"><text x="20" y="20">bla2</text></g>
</svg>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…