d3.js的Insert()函数会添加子元素,而不是同级元素。

huangapple go评论60阅读模式
英文:

d3.js Insert() function adds child element - instead of a sibling element

问题

看起来当我使用“insert”函数时,新元素总是作为子元素插入 - 而不是作为同级元素插入。

我仍然不明白为什么会这样,因为插入函数实际上应该在指定的元素之前插入一个新元素 - 而不是指定的元素内部作为子元素。

基本上,我正在尝试在“text”元素旁边创建一个“rect”元素。

目标是在我的d3 sankey图中的文本背后放置一个背景颜色。

// 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})`;
        })
  );
英文:

It looks like when I use the “insert” function, the new element is always inserted as a child – Not as a sibling.

I still don't understand why this is, since the insert function should actually insert a new element before the specified element - and not in the specified element as a child.

Basically I am trying to create a "rect" element next to the "text" elements

The goal is to put a background color behind my texts in my d3 sankey diagram.

 // 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();
});
}

Here is a picture of the rendered HTML elements from my browser.

Notice that the “rect” element is a child of the text and not a sibling as desired.

d3.js的Insert()函数会添加子元素,而不是同级元素。

答案1

得分: 2

以下是您要翻译的部分:

在您的代码中,结果是预期的:这是因为在一组文本的选择上调用了insert,它充当父元素。

第一个简单的解决方案是打破链条,这样您就有了selection.appendselection.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();
  });
}

然而,这个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。在这个示例中,我通过它们的ID获取了相应的文本元素:

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();
  });
}

希望这些翻译对您有所帮助。

英文:

The result in the code you have is expected: it happens because the insert is called on a selection of texts, which acts as a parent.

The first, simple solution, is breaking the chain, so you have a selection.append and a selection.insert. For instance:

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

const svg = d3.select(&quot;svg&quot;),
data = d3.range(5).map(e =&gt; ({
value: e
}));
svg.selectAll(null)
.data(data)
.join(enter =&gt; {
enter.append(&quot;text&quot;)
.attr(&quot;x&quot;, 20)
.attr(&quot;y&quot;, d =&gt; 20 + 30 * d.value)
.text(d =&gt; `text #${d.value}`)
.call(getTextBox);
enter.insert(&quot;rect&quot;, &quot;text&quot;)
.attr(&#39;width&#39;, d =&gt; d.bbox.width)
.attr(&#39;height&#39;, d =&gt; d.bbox.height)
.attr(&#39;x&#39;, d =&gt; d.bbox.x)
.attr(&#39;y&#39;, d =&gt; d.bbox.y)
.style(&#39;fill&#39;, &#39;grey&#39;)
})
function getTextBox(selection) {
selection.each(function(d) {
d.bbox = this.getBBox();
});
}

<!-- language: lang-html -->

&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;
&lt;svg&gt;&lt;/svg&gt;

<!-- end snippet -->

However, this SVG will have this structure:

&lt;rect&gt;&lt;/rect&gt;
&lt;rect&gt;&lt;/rect&gt;
&lt;rect&gt;&lt;/rect&gt;
...
&lt;text&gt;&lt;/text&gt;
&lt;text&gt;&lt;/text&gt;
&lt;text&gt;&lt;/text&gt;
...

That said, if you want the following structure instead...

&lt;rect&gt;&lt;/rect&gt;
&lt;text&gt;&lt;/text&gt;
&lt;rect&gt;&lt;/rect&gt;
&lt;text&gt;&lt;/text&gt;
&lt;rect&gt;&lt;/rect&gt;
&lt;text&gt;&lt;/text&gt;
...

... you'll need a bit more elaborated insert. In this example I'm getting the respective text elements by their IDs:

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

const svg = d3.select(&quot;svg&quot;),
data = d3.range(5).map(e =&gt; ({
value: e
}));
svg.selectAll(null)
.data(data)
.join(enter =&gt; {
enter.append(&quot;text&quot;)
.attr(&quot;id&quot;, d =&gt; `text${d.value}`)
.attr(&quot;x&quot;, 20)
.attr(&quot;y&quot;, d =&gt; 20 + 30 * d.value)
.text(d =&gt; `text #${d.value}`)
.call(getTextBox);
enter.insert(&quot;rect&quot;, d =&gt; d3.select(`#text${d.value}`).node())
.attr(&#39;width&#39;, d =&gt; d.bbox.width)
.attr(&#39;height&#39;, d =&gt; d.bbox.height)
.attr(&#39;x&#39;, d =&gt; d.bbox.x)
.attr(&#39;y&#39;, d =&gt; d.bbox.y)
.style(&#39;fill&#39;, &#39;grey&#39;)
})
function getTextBox(selection) {
selection.each(function(d) {
d.bbox = this.getBBox();
});
}

<!-- language: lang-html -->

&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;
&lt;svg&gt;&lt;/svg&gt;

<!-- end snippet -->

答案2

得分: 0

在数据上进行迭代,并将文本/矩形绑定在父包装器中。

希望对你有所帮助:链接

英文:

Iterate over data & bind both text/rect in parent wrapper

Hope this helps : link

huangapple
  • 本文由 发表于 2023年5月15日 06:00:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76249856.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定