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.
2
Answers
Iterate over data & bind both text/rect in parent wrapper
Hope this helps : link
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 aselection.insert
. For instance:However, this SVG will have this structure:
That said, if you want the following structure instead…
… you’ll need a bit more elaborated
insert
. In this example I’m getting the respective text elements by their IDs: