centering appended foreignObject

1,289 views
Skip to first unread message

Zephyr Penoyre

unread,
Sep 15, 2016, 5:37:56 PM9/15/16
to d3-js
Hopefully a very simple question.

I'm trying to append a block of html text to nodes (in a force-directed graph). It looks like appending a foreignObject is the best method, as the text has multiple lines, sizes and includes some links/pictures.

But at the moment when I do the obvious...

var text=node.append('foreignObject')
                .attr("width", 480)
                .attr("height",200)
                .append("xhtml:body")
                  .html("why am I over here? </br> I really want to be over there");

... the text is way off center. Seemingly the top left corner of the foreignObject is at the center of the node. Is there an easy way to center the foreignObject (and then center the text in it) over the node?

I've read this (https://groups.google.com/forum/#!searchin/d3-js/foreignobject$20center%7Csort:relevance/d3-js/xPhOUZBj1A0/PuhZDIC1j6oJ) but the line about BBox is failing for me, maybe because I'm in d3.v4? Also it seems like there must be a simpler solution?

Then again, I'm pretty new to this so may be missing something stupid.

Ram Tobolski

unread,
Sep 17, 2016, 9:43:09 AM9/17/16
to d3-js
Hi,is there a link?

Zephyr Penoyre

unread,
Sep 22, 2016, 7:34:59 PM9/22/16
to d3-js
  Here's a codepen to show the problem. Sorry it's a little long, I tried to scale down the problem as much as possible without losing any necessary components. 

  I've made no attempt to center the div here (though I have tried to center the text in the div).

  How would I go about placing the div exactly over the center of each circle (without assuming I know the width and height the div will be).

p.s. If anyone can explain why '.force("center", d3.forceCenter()); ' seems to be causing issues I'd also love to hear that too!

On Saturday, September 17, 2016 at 9:43:09 AM UTC-4, Ram Tobolski wrote:
Hi,is there a link?

Mike Bostock

unread,
Sep 22, 2016, 7:42:41 PM9/22/16
to d3...@googlegroups.com
The foreignObject element is positioned relative to its top-left corner, which you have placed at the node’s center. If the text is then centered within the bounding box of the foreignObject, the text will be offset by [width / 2, height / 2] relative to the node’s center, where width and height represent the dimensions of the foreignObject:

Screen Shot 2016-09-22 at 4.36.37 PM.png
If you want the foreignObject to be centered over the node, you must set the x and y attributes of the foreignObject to be -width / 2 and -height / 2, respectively (or equivalently apply a transform with a translate to the foreignObject).

Zephyr Penoyre

unread,
Sep 22, 2016, 7:56:54 PM9/22/16
to d3-js, mi...@ocks.org
Many thanks, that looks way better now!

I still have a couple of issues though:
 If the text is too big for the box (as in the example now) then the offset is incorrect, is there any way to let the size and offset adjust automatically to whatever text is in the div?

 Also the text in the paragraph seems to go off center when it has to wrap to the next line. I realise this is probably a flexbox issue, not d3, but do you know of a workaround for this?

Zephyr Penoyre

unread,
Sep 22, 2016, 10:31:00 PM9/22/16
to d3-js, mi...@ocks.org
Similarly, it looks like if the div is too tall (boxH = 200 for example) then the box ends up floating well above the node.

Also, it looks like the div is blocking mouse events that pertain to the circle? I'm guessing there's some kind of layering going on here, is there any way to circumvent this?

It seems like everything could be solved if there was an easy way to work out the dimensions the circle needs to be to fit the text in. But I can't think of a good way to do this dynamically?


On Thursday, September 22, 2016 at 7:42:41 PM UTC-4, Mike Bostock wrote:
Reply all
Reply to author
Forward
Message has been deleted
0 new messages