How d3 can get the transform attribute of the dataset

I am working with a svg element which has few g elements.
The basic markup is following

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
   </head>
   <script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
   <body>
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
         <g class="smGrp0" opacity="0" transform="translate(0.5,0)">
         </g>
         <g class="smGrp1" opacity="1" transform="translate(101.33333333333333,0)">
         </g>
         <g class="smGrp2" opacity="1" transform="translate(202.16666666666666,0)">
         </g>
         <g class="smGrp3" opacity="1" transform="translate(303,0)">
         </g>
      </svg>
      <script src="jsx3.js"></script>
   </body>
</html>

I want to create a rect forEach g element with fixed x,y,height,width but want to grab the transform property from each g element and pass on to each rect . If I use vanilla javascript, I can achieve the task as follows

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
         <g class="smGrp0" opacity="0" transform="translate(0.5,0)">
         </g>
         <g class="smGrp1" opacity="1" transform="translate(101.33333333333333,0)">
         </g>
         <g class="smGrp2" opacity="1" transform="translate(202.16666666666666,0)">
         </g>
         <g class="smGrp3" opacity="1" transform="translate(303,0)">
         </g>
      </svg>
<script type="text/javascript">
const data = document.querySelectorAll("[class^=smGrp]");
const svgns = 'http://www.w3.org/2000/svg';
data.forEach(
    (a, i) => {
        const rect = document.createElementNS(svgns, 'rect');
        rect.setAttribute('x', '0');
        rect.setAttribute('y', '0');
        rect.setAttribute('height', `670`)
        rect.setAttribute('width', `110`)
        rect.style.setProperty('fill', 'none');
        rect.style.setProperty('stroke', 'black')
        rect.setAttribute('transform', `${a.getAttribute('transform')}`)
        document.querySelector('svg').appendChild(rect);
    }
);
</script>
</body>

</html>

It generates this
image

How can I achieve the same using d3?
So far, I tried this which did not work.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
         <g class="smGrp0" opacity="0" transform="translate(0.5,0)">
         </g>
         <g class="smGrp1" opacity="1" transform="translate(101.33333333333333,0)">
         </g>
         <g class="smGrp2" opacity="1" transform="translate(202.16666666666666,0)">
         </g>
         <g class="smGrp3" opacity="1" transform="translate(303,0)">
         </g>
      </svg>
<script type="text/javascript">
const dataset = d3.selectAll("[class^=smGrp]");
d3.select('svg').selectAll('smGrp').data(dataset).enter()
.append('rect')
.attr('x', '0')
.attr('y', '0')
.attr('height', `670`)
.attr('width', `110`)
.style('fill', 'none')
.style('stroke', 'black')
.attr('transform', (d, i) => { return `${d.attr('transform')}` });
</script>
</body>

</html>

Thank you in advance.

I put that into an Observable notebook. question https://talk.observablehq.com/t/how-d3-can-get-the-transform-attribute-of-the-dataset/6516 / Brett Cooper / Observable

The line of code,
attr('transform', (d, i) => { return ${d.attr(‘transform’)} });
is looking at the wrong data. d is not a selection and it also doesn’t need to be inside a template literal.

.attr('transform', (d, i) => d.getAttribute('transform') )

d is an html object, so you only need to request the attribute you need.

1 Like

@hellonearthis thanks for looking into this.

I got away with

.attr(‘transform’, (d, i) => { const dataset = d3.selectAll(“[class^=smGrp]”); const transform = dataset[‘_groups’][0][i].getAttribute(‘transform’); return transform })

But your’s is definitely better. I got tripped with attr which is equivalent to setAttribute and getAttribute probably has no d3 equivalent.

1 Like

You could read the attribute with D3 but it would require a select
d3.select('svg > g.smGrp0').attr('transform')

You can access the current element via this, or via the entire collection:

// this
.attr('transform', function(d) {
  return d3.select(this).attr('transform');
  // or
  return this.getAttribute('transform');
})
// collection
.attr('transform', (d, i, nodes) => d3.select(nodes[i]).attr('transform'))

Read more in the d3-selection documentation. While you’re there, be sure to also take a look at the docs for selection.each().

1 Like