D3.js: Как получить вычисленную ширину и высоту для произвольного элемента?

Мне нужно точно знать ширину и высоту для произвольного элемента g в моем SVG, потому что мне нужно нарисовать маркер выделения, когда пользователь щелкнул его.

То, что я видел в Интернете, это что-то вроде: d3.select("myG").style("width"). Проблема в том, что элемент не всегда будет иметь атрибут ширины явной ширины. Например, когда я создаю круг внутри g, он будет иметь вместо него ширину (r). Даже если я использую метод window.getComputedStyle на circle, он вернет "авто".

Есть ли способ вычислить ширину произвольного сегмента SVG в D3?

Спасибо.

Ответ 1

Для элементов SVG

Используя что-то вроде selection.node().getBBox(), вы получаете такие значения, как

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

Для элементов HTML

Используйте selection.node().getBoundingClientRect()

Ответ 2

.getBoundingClientRect() возвращает размер элемента и его позицию относительно окна просмотра. Мы можем легко получить следующий

  • влево, вправо
  • верх, внизу
  • высота, ширина

Пример:

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

Ответ 3

Как только я столкнулся с проблемой, когда я не знал, какой элемент хранится в моей переменной (svg или html), но мне нужно было получить ее ширину и высоту. Я создал эту функцию и хочу поделиться ею:

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

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

Маленькая демонстрация в скрытом фрагменте ниже. Мы обрабатываем щелчок на синем div и на круге красного SVG с той же функцией.

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>