I am struggeling with the foreignObject
in SVG. I want to add text inside a rect
, and to get auto text wrap I have chosen to use HTML. The description of foreignObject
can be found here.
I am working with D3, and this is my data:
var cds = [
{"uid":"U12","sid":"16","statement":"Movies","x":10,"y":10},
{"uid":"U20","sid":"17","statement":"Food","x":10,"y":170},
{"uid":"U22","sid":"15","statement":"Sport","x":10,"y":330}
];
I add a card for each datum and want to display the "statement" from the data.
var cardsize = { width : 150, height : 150 };
var svg = d3.select("body").append("svg:svg")
.attr("width", 170)
.attr("height", 490);
var card = svg.selectAll("rect")
.data(cds)
.enter().append("svg:g")
.attr("class", "card")
.attr("transform", function(d,i) {
d.x = 10;
d.y = 10+i*(10+cardsize.height);
return "translate(" + d.x + "," + d.y + ")";
});
card.append("svg:rect")
.attr('width', cardsize.width)
.attr('height', cardsize.height)
card.append("svg:foreignObject")
.attr('width', cardsize.width)
.attr('height', cardsize.height)
.append('p')
.attr("class","statement")
.text(function(d) { return d.statement; });
The output of a card is this:
<g class="card" transform="translate(10,330)">
<rect width="150" height="150"></rect>
<foreignObject width="150" height="150"><
p class="statement">Sport</p>
</foreignObject>
</g>
I can't see the text in the (mac) browsers I have tested (Safari 6.0.2, Chrome 25.0.1364.99, Firefox 18.0.2). W3's validator doesn't like the output, and give me this error for each card:
Element foreignObject not allowed as child of element g in this context.
So my question is, where is the problem, and why is foreignObject not allowed as a child of a g
element?
I am also wondering why .html(function(d) { return d.statement; });
doesn't work (no output). But .text(function(d) { return d.statement; });
works fine?
Here is a fiddle.
This can be solved by using the <foreignObject> SVG element in which you can add an HTML under a different namespace than the parent SVG and then you can also style the elements using CSS like so.
The SVG format allows for the nesting of SVG graphics. It is possible for an “<svg>” elements, to be placed within another “<svg>” element.
To embed an SVG via an <img> element, you just need to reference it in the src attribute as you'd expect. You will need a height or a width attribute (or both if your SVG has no inherent aspect ratio). If you have not already done so, please read Images in HTML.
It is very similar to HTML's <a> element. SVG's <a> element is a container, which means you can create a link around text (like in HTML) but also around any shape.
Specify the namespace in all tags in a foreignObject: replace .append("p")
by .append("xhtml:p")
and it will work: http://jsfiddle.net/EHzcR/2/
In the context of foreign objects, <p></p>
is not recognized as a xhtml
paragraph. Why? Simply because the namespace xhtml
is not included in the foreignObject
context (a foreignObject
might contain anything (xml
formated data for example) so it doesn't consider the input as html if you don't explicitly say it.).
So the p
tag is considered as a custom tag, not as a xhtml
tag. Thus, as the web browser doesn't recognize the tag p
in the tags it knows, so it just doesn't interpret it and its content, even if it exists, it won't throw an error as well because this content might be totally valid, just not for its direct use.
It is fun to see that you always specify the namespace svg
even if it is not necessary and how we all forget that the p
, div
... also have a very popular namespace.
The selection.html()
function doesn't work because in its implementation it uses the .innerHTML()
function of the element, but here, the foreignObject, not being an html element, doesn't have such a function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With