D3.js: How to get the computed width and height for an arbitrary element?

Javascriptd3.js

Javascript Problem Overview


I need to know exactly the width and height for an arbitrary g element in my SVG because I need to draw a selection marker around it once the user has clicked it.

What I've seen in the internet is something like: d3.select("myG").style("width"). The problem is that the element will not always have an explicit width attribute set. For instance, when I create a circle inside the g, it will have the radious (r) set instead of the width. Even if I use the window.getComputedStyle method on a circle, it will return "auto".

Is there a way to calculate the width of an arbitrary svg selement in D3?

Thank you.

Javascript Solutions


Solution 1 - Javascript

For SVG elements

Using something like selection.node().getBBox() you get values like

{
    height: 5, 
    width: 5, 
    y: 50, 
    x: 20
} 

For HTML elements

Use selection.node().getBoundingClientRect()

Solution 2 - Javascript

> .getBoundingClientRect() returns the size of an element and its position relative to the viewport.We can easily get following

  • left, right
  • top, bottom
  • height, width

Example :

var element = d3.select('.elementClassName').node();
element.getBoundingClientRect().width;

Solution 3 - Javascript

Once I faced with the issue when I did not know which the element currently stored in my variable (svg or html) but I needed to get it width and height. I created this function and want to share it:

function computeDimensions(selection) {
  var dimensions = null;
  var node = selection.node();

  if (node instanceof SVGGraphicsElement) { // check if node is svg element
   	dimensions = node.getBBox();
  } else { // else is html element
  	dimensions = node.getBoundingClientRect();
  }
  console.log(dimensions);
  return dimensions;
}

Little demo in the hidden snippet below. We handle click on the blue div and on the red svg circle with the same function.

var svg = d3.select('svg')
  .attr('width', 50)
  .attr('height', 50);

function computeDimensions(selection) {
	var dimensions = null;
  var node = selection.node();

  if (node instanceof SVGElement) {
   	dimensions = node.getBBox();
  } else {
  	dimensions = node.getBoundingClientRect();
  }
  console.clear();
  console.log(dimensions);
  return dimensions;
}

var circle = svg
    .append("circle")
    .attr("r", 20)
    .attr("cx", 30)
    .attr("cy", 30)
    .attr("fill", "red")
    .on("click", function() { computeDimensions(circle); });
    
var div = d3.selectAll("div").on("click", function() { computeDimensions(div) });

* {
  margin: 0;
  padding: 0;
  border: 0;
}

body {
  background: #ffd;
}

.div {
  display: inline-block;
  background-color: blue;
  margin-right: 30px;
  width: 30px;
  height: 30px;
}

<h3>
  Click on blue div block or svg circle
</h3>
<svg></svg>
<div class="div"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndre PenaView Question on Stackoverflow
Solution 1 - JavascriptChristopher HackettView Answer on Stackoverflow
Solution 2 - JavascriptMalik KhalilView Answer on Stackoverflow
Solution 3 - JavascriptMikhail ShabrikovView Answer on Stackoverflow