Reputation: 8241
Suppose I have created a svg with d3.js like that:
svg = d3.select('.svgContainer').append("svg")
.attr("width", '100%')
.attr("height", '100%')
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g");
and I now want to add different groups to it (dynamically and from different files). For example that one:
<svg>
<g id="myGroup">
<rect width="100" height="100" fill="blue" />
</g>
</svg>
I know, that I could add the whole svg like that (suppose the file is called test.svg):
d3.xml("test.svg").then(function(xml) {
var svgNode = xml.getElementsByTagName("svg")[0];
svg.node().appendChild(svgNode);
});
However, this procuces the following DOM:
svg
-svg
--myGroup
But because I need to transform my Group with respect to the main svg, I need the following DOM structure:
svg
-myGroup
--(eventually more dynamically added groups)
I have tried the following and got the correct DOM, but the group does not show up inside of my svg:
d3.xml("test.svg").then(function(xml) {
var svgGroup = xml.getElementById("myGroup");
svg.node().append(svgGroup);
});
EDIT: I found out, this should already work, the problem was I had several critical <defs>
inside of my SVG (for example for gradients). I lost them, when I only appended the group. I ended up, wrapping my <g>
around the <defs>
and everything works fine now.
Upvotes: 3
Views: 1178
Reputation: 102174
Just as a complement to the accepted answer: if you want to a pure D3 solution, you can use selection.append
with a function. In your case:
d3.xml(svgfile).then(function(xml) {
var svgNode = d3.select(xml).select("#MyGroup");
svg.append(() => svgNode.node()) ;
});
Or even shorter:
d3.xml(svgfile).then(function(xml) {
svg.append(() => d3.select(xml).select("#MyGroup").node()) ;
});
Here is a demo using the Wikipedia SVG linked in the other answer:
var svgfile = "https://simple.wikipedia.org/static/images/mobile/copyright/wikipedia-wordmark-en.svg";
var svg = d3.select('body').append("svg")
.attr("width", '120')
.attr("height", '20');
d3.xml(svgfile).then(function(xml) {
var svgNode = d3.select(xml).select("#Wikipedia");
svg.append(() => svgNode.node());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Upvotes: 3
Reputation: 2628
You are almost there. I have illustrated both ways to add elements in this codepen. The problem with the first approach is that svgNode
is not a node
, but a nodeList
. You can add each node in the list with a loop, as you can see in the code:
...
var toAdd = svgNode.childNodes;
for (var i = 0; i < svgNode.childElementCount; i++){
svg.node().appendChild(toAdd[i]);
}
...
Regarding the second approach, I cannot say that there is anything wrong. I have imported a path from a different svg file and it is displayed in the lower part. The only detail that I changed is that I set the size of the svg element explicitly, not as 100%
. Is it possible that it was not rendered because it was outside the visible part?
Upvotes: 1