In this example, I try to call getBBox in text node but it never been called due to the text node is not SVGGraphicsElement.
I am confused why text node is not SVGGraphicsElement! how can I call getBBox for this usecase?
test()
function test() {
var data ={
"nodes": [
{id: "A",name:'AAAA'},
{id: "B",name:'BBBB'},
{id: "C",name:'CCCC'},
{id:"D",name:'DDDD'}],
"links": [
{source: "A", target: "B"},
{source: "B", target: "C"},
{source: "C", target: "A"},
{source: "D", target: "A"}]}
var height = 250; var width = 400;
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height)
.style('border','1px solid red')
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(50))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 3, height / 2));
const zagzag = (from, to) => {
let dx = to.x - from.x;
let dy = to.y - from.y;
if (Math.abs(dx) > Math.abs(dy)) {
let mx,my,nx,ny,sx,sy
sx = (dx>0)?1:-1
sy = (dy>0)?1:-1
mx = from.x + from.bbox.width/2*sx
my = from.y
nx = to.x - to.bbox.width/2*sx
ny = to.y
dx = nx - mx;
dy = ny - my;
return `M ${mx},${my} l ${dx/2},0 0,${dy} ${dx/2},0 `;
}else{//vertical
let mx,my,nx,ny,sx,sy
sx = (dx>0)?1:-1
sy = (dy>0)?1:-1
mx = from.x
my = from.y + from.bbox.height/2*sy
nx = to.x
ny = to.y - to.bbox.height/2*sy
dx = nx - mx;
dy = ny - my;
return `M ${mx},${my} l 0,${dy/2} ${dx},0 0,${dy/2}`;
}
};
const linelink = (from, to) => {
const dx = to.x - from.x;
const dy = to.y - from.y;
let fX, fY, tX, tY;
const sx = (dx > 0)?1:-1
const sy = (dy > 0)?1:-1;
if (from.bbox.width / from.bbox.height > Math.abs(dx / dy)) {
fX = from.x + from.bbox.height * dx / dy / 2*sy;
fY = from.y + from.bbox.height / 2 * sy;
}
else {
fX = from.x + from.bbox.width / 2 * sx;
fY = from.y + from.bbox.width * dy / dx / 2 * sx;
}
if (to.bbox.width / to.bbox.height > Math.abs(dx / dy)) {
tX = to.x - to.bbox.height * dx / dy / 2 * sy;
tY = to.y - to.bbox.height / 2 * sy;
}
else {
tX = to.x - to.bbox.width / 2 * sx;
tY = to.y - to.bbox.width * dy / dx / 2 * sx;
}
return ['M',fX,fY,'L',tX,tY].join(' ');
};
var link = svg.append("g")
.selectAll("line")
.data(data.links)
.enter().append("path")
.attr('fill','none')
.attr("stroke","black")
var g = svg.append("g")
.selectAll("text")
.data(data.nodes)
.enter()
var bbox = d3.local()
var node = g.append("text")
.text(d => d.name)
.attr('text-anchor','middle')
.attr("alignment-baseline", "central")
.attr("dominant-baseline", "central")
.each((d,i,n) => {
if (n[i] instanceof SVGGraphicsElement) {
var bbox = n[i].getBBox();
bbox.width += 12
bbox.height += 8
d.bbox = bbox
g.append('rect')
.attr('id','rect_'+d.id)
.attr('x',50*i) //debug code
.attr('y',10) //debug code
.attr('width',bbox.width)
.attr('height',bbox.height)
.attr('stroke','crimson')
.attr('stroke-width',2)
.attr('fill','none')
}
})
.call(d3.drag()
.on("drag", dragged)
.on("end", dragended))
simulation.nodes(data.nodes)
.on("tick", ticked1)
.alphaDecay(0)
.force("link")
.links(data.links);
function ticked1() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; })
.attr('d',d =>{
var path = linelink(d.source,d.target)
return path
})
node
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.each(d => {
var rect = d3.select('#rect_'+d.id)
rect.attr('x',d.x-d.bbox.width/2)
rect.attr('y',d.y-d.bbox.height/2)
})
}
function dragged(event,d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
//d.fx = null;
//d.fy = null;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>