Функция d3.js Insert() добавляет дочерний элемент вместо родственного элемента

Похоже, когда я использую функцию «вставить», новый элемент всегда вставляется как дочерний, а не как родственный.

Я до сих пор не понимаю, почему это так, поскольку функция вставки должна фактически вставлять новый элемент перед указанным элементом, а не в указанный элемент как дочерний.

В основном я пытаюсь создать элемент «прямоугольник» рядом с элементами «текст».

Цель состоит в том, чтобы поместить цвет фона позади моих текстов в моей диаграмме Санки d3.

 // NODE TEXT
this.nodes
  .selectAll('text')
  .data(this.data.nodes)
  .join(
    (enter) =>
      enter
        .append('text')
        .text((d) => `${d.name + ': ' + d.value}`)
        .style('fill', '#000000')
        .attr('text-anchor', 'right')
        .attr('x', (d, i) => {
          return d.x0 + (d.x1 - d.x0) / 0.5;
        })
        .attr('y', (d, i) => {
          return d.y0 + (d.y1 - d.y0) / 2;
        })
        .attr('dy', '0.35em')
        .attr('transform', (d, i) => {
          const x = d.x0 + (d.x1 - d.x0) / 2;
          const y = d.y0 + (d.y1 - d.y0) / 2;
          return `rotate(0, ${x}, ${y})`;
        })
        .call(getTextBox)
        .insert('rect', 'text')
        .attr('width', function (d) {
          return d.bbox.width;
        })
        .attr('height', function (d) {
          return d.bbox.height;
        })
        .attr('x', function (d) {
          return d.bbox.x;
        })
        .attr('y', function (d) {
          return d.bbox.y;
        })
        .style('fill', 'grey'),
    (update) =>
      update
        .transition()
        .duration(1000)
        .ease(d3_easeQuadInOut)
        .attr('x', (d, i) => {
          return d.x0 + (d.x1 - d.x0) / 2;
        })
        .attr('y', (d, i) => {
          return d.y0 + (d.y1 - d.y0) / 2;
        })
        .attr('transform', (d, i) => {
          const x = d.x0 + (d.x1 - d.x0) / 2;
          const y = d.y0 + (d.y1 - d.y0) / 2;
          return `rotate(0, ${x}, ${y})`;
        })
  );


function getTextBox(selection) {
  selection.each(function (d) {
    d.bbox = this.getBBox();
  });
}

Вот изображение отображаемых HTML-элементов из моего браузера.

Обратите внимание, что элемент «rect» является дочерним по отношению к тексту, а не родственным, как хотелось бы.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Перебирать данные и привязывать текст/прямоугольник в родительской оболочке

Надеюсь, это поможет: ссылка

Спасибо за ваш ответ. К сожалению, пример не помогает, потому что мне сначала нужны текстовые элементы, чтобы получить значения (x, y, ширина, высота) для новых прямоугольных элементов. Прямоугольники должны отображаться непосредственно за текстами. Поэтому мне нужно сначала прочитать их.

1zz0 15.05.2023 12:00
Ответ принят как подходящий

Результат в коде, который у вас есть, ожидаемый: это происходит потому, что insert вызывается для выделения текстов, которые действуют как родитель.

Первое, простое решение — разорвать цепочку, поэтому у вас есть selection.append и selection.insert. Например:

const svg = d3.select("svg"),
  data = d3.range(5).map(e => ({
    value: e
  }));

svg.selectAll(null)
  .data(data)
  .join(enter => {
    enter.append("text")
      .attr("x", 20)
      .attr("y", d => 20 + 30 * d.value)
      .text(d => `text #${d.value}`)
      .call(getTextBox);

    enter.insert("rect", "text")
      .attr('width', d => d.bbox.width)
      .attr('height', d => d.bbox.height)
      .attr('x', d => d.bbox.x)
      .attr('y', d => d.bbox.y)
      .style('fill', 'grey')

  })

function getTextBox(selection) {
  selection.each(function(d) {
    d.bbox = this.getBBox();
  });
}
<script src = "https://d3js.org/d3.v7.min.js"></script>
<svg></svg>

Однако этот SVG будет иметь следующую структуру:

<rect></rect>
<rect></rect>
<rect></rect>
...
<text></text>
<text></text>
<text></text>
...

Тем не менее, если вместо этого вам нужна следующая структура...

<rect></rect>
<text></text>
<rect></rect>
<text></text>
<rect></rect>
<text></text>
...

... вам нужно немного больше проработки insert. В этом примере я получаю соответствующие текстовые элементы по их идентификаторам:

const svg = d3.select("svg"),
  data = d3.range(5).map(e => ({
    value: e
  }));

svg.selectAll(null)
  .data(data)
  .join(enter => {
    enter.append("text")
      .attr("id", d => `text${d.value}`)
      .attr("x", 20)
      .attr("y", d => 20 + 30 * d.value)
      .text(d => `text #${d.value}`)
      .call(getTextBox);

    enter.insert("rect", d => d3.select(`#text${d.value}`).node())
      .attr('width', d => d.bbox.width)
      .attr('height', d => d.bbox.height)
      .attr('x', d => d.bbox.x)
      .attr('y', d => d.bbox.y)
      .style('fill', 'grey')

  })

function getTextBox(selection) {
  selection.each(function(d) {
    d.bbox = this.getBBox();
  });
}
<script src = "https://d3js.org/d3.v7.min.js"></script>
<svg></svg>

Большое спасибо! Это точно решение!

1zz0 15.05.2023 13:22

Другие вопросы по теме

Похожие вопросы