Получить ширину текстового элемента SVG d3.js после его создания.

Я пытаюсь получить ширину связки элементов text, которые я создал с помощью d3.js

Вот как я их создаю:

var nodesText = svg.selectAll("text")
           .data(dataset)
           .enter()
           .append("text")
           .text(function(d) {
                return d.name;
           })
          .attr("x", function(d, i) {
                return i * (w / dataset.length);
           })
          .attr("y", function(d) {
                return 45;
          });

Затем я использую ширину для создания rectangles того же размера, что и теги text

var nodes = svg.selectAll("rect")
            .data(dataset)
            .enter()
            .append("rect")
            .attr("x", function(d, i) {
                return i * (w / dataset.length);
            })
            .attr("y", function(d) {
                return 25;
            })
            .attr("width", function(d, i) {
              //To Do: find width of each text element, after it has been generated
              var textWidth = svg.selectAll("text")
                  .each(function () {
                      return d3.select(this.getComputedTextLength());
                  });
                console.log(textWidth);
                return textWidth;
            })
            .attr("height", function(d) {
                return 30;
            })

Я попробовал использовать метод Bbox от здесь, но я этого не понимаю. Я думаю, что выбор фактического элемента - это то, где я ошибаюсь.

Ответы

Ответ 1

Я бы сделал длину части исходных данных:

var nodesText = svg.selectAll("text")
       .data(dataset)
       .enter()
       .append("text")
       .text(function(d) {
            return d.name;
       })
      .attr("x", function(d, i) {
            return i * (w / dataset.length);
       })
      .attr("y", function(d) {
            return 45;
      })
      .each(function(d) {
        d.width = this.getBBox().width;
      });

а затем позже

var nodes = svg.selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("width", function(d) { return d.width; });

Ответ 2

Вы можете использовать getBoundingClientRect()

Пример:

.style('top', function (d) {
     var currElemHeight = this.getBoundingClientRect().height;
}

edit: похоже, что он более подходит для элементов HTML. для элементов SVG вы можете использовать getBBbox().

Ответ 3

d3.selectAll возвращает выбор. Вы можете получить каждый из элементов, перемещаясь по массиву в свойстве _groups. Когда вы определяете ширину прямоугольника, вы можете использовать его индекс для получения соответствующего текстового элемента:

.attr('width', function (d, i) {
    var textSelection = d3.selectAll('text');
    return textSelection._groups[0][i].getComputedTextLength();
});

Свойство _groups для выбора d3 имеет список узлов в [0]. Этот список содержит все выбранные элементы, к которым вы можете получить доступ по индексу. Важно, чтобы вы получили элемент SVG, чтобы вы могли использовать метод getComputedTextLength.

Вы также можете сначала рассмотреть элементы rect, затем элементы text, а затем вернуться к прямоугольникам, чтобы отредактировать атрибут width, чтобы элементы text находились поверх прямоугольники (если вы хотите заполнить прямоугольники цветом).

Update:

Обычно предпочитают, чтобы вы не обращались к _groups, поэтому более безопасный способ получить соответствующую ширину текстового элемента:

.attr('width', function (d, i) {
    return d3.selectAll('text').filter(function (d, j) { return i === j; })
        .node().getComputedTextLength(); 
});

Использование node безопасно извлекает элемент, а фильтр найдет текстовый элемент, который соответствует индексу.