3

I have to select SVG elements with a specific transform attribute, knowing just a part of it. Let me better explain with an example. These are the elements I'd like to select:

<g transform='matrix(96, 0, 0, -96, 217.04, 43.052)'></g>
<g transform='matrix(96, 0, 0, -96, 317.04  53.052)'></g>
<g transform='matrix(96, 0, 0, -96, 417.04, 63.052)'></g>
<g transform='matrix(96, 0, 0, -96, 517.04, 73.052)'></g>
<g transform='matrix(96, 0, 0, -96, 617.04, 83.052)'></g>

I want to select them all and (initially) using something like the code below did sound like a good idea:

d3.selectAll("g").filter("[transform='matrix(96, 0, 0, -96)]'");

The problem is that, obliviously, the selection is returned as empty and I am wondering how can I tell to d3 to select just those <g> elements with a match on the first 4 parameters of the transform attribute.

altocumulus
  • 21,179
  • 13
  • 61
  • 84
Lc0rE
  • 2,236
  • 8
  • 26
  • 34

1 Answers1

4

You can combine the initial selection of the gs and the filtering in one selector:

d3.selectAll("g[transform^='matrix(96, 0, 0, -96']");

Note the use of the ^= in the attribute selector:

[attr^=value]
Represents an element with an attribute name of attr the value of which is prefixed by "value".

Working demo:

var filtered = d3.selectAll("g[transform^='matrix(96, 0, 0, -96']");
console.log(filtered.size());  // 3: The first three groups
<script src="https://d3js.org/d3.v4.js"></script>

<svg>
  <g transform="matrix(96, 0, 0, -96, 217.04, 43.052)"></g>
  <g transform="matrix(96, 0, 0, -96, 317.04  53.052)"></g>
  <g transform="matrix(96, 0, 0, -96, 417.04, 63.052)"></g>
  <g transform="matrix(10, 0, 0, -96, 517.04, 73.052)"></g> <!--different transform-->
  <g transform="matrix(20, 0, 0, -96, 617.04, 83.052)"></g> <!--different transform-->
</svg>

Of course, you can also split the filtering from the groups' selection:

d3.selectAll("g").filter("[transform^='matrix(96, 0, 0, -96']");

Or, for even more control of the filtering, you can supply a filter function to selection.filter() whereby getting access to the selected elements as well as the data bound to them.

d3.selectAll("g")
  .filter(function(d, i, nodes) {   // Most versatile approach
    return d3.select(this)
      .attr("transform")
        .startsWith("matrix(96, 0, 0, -96");
        // .lastIndexOf("matrix(96, 0, 0, -96", 0);  // For those on IE
  });

Although all of these solutions will yield the same result, the right one for your problem will likely be a trade-off between performance, simplicity and versatility.

altocumulus
  • 21,179
  • 13
  • 61
  • 84