如何使用d3.js将外部组添加到现有svg?

时间:2019-08-30 10:52:56

标签: javascript d3.js svg

假设我已经用d3.js创建了一个svg:

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");

,我现在想向其添加不同的组(动态地并来自不同的文件)。例如一个:

<svg>
    <g id="myGroup">
        <rect width="100" height="100" fill="blue" />
    </g>
</svg>

我知道,我可以像这样添加整个svg(假设文件名为test.svg):

d3.xml("test.svg").then(function(xml) { 
    var svgNode = xml.getElementsByTagName("svg")[0];
    svg.node().appendChild(svgNode);
  });

但是,这会产生以下DOM:

svg
 -svg
 --myGroup

但是由于我需要相对于主要svg转换组,因此我需要以下DOM结构:

 svg
 -myGroup
 --(eventually more dynamically added groups)

我尝试了以下操作并获得了正确的DOM,但是该组未显示在我的svg中:

d3.xml("test.svg").then(function(xml) { 
    var svgGroup = xml.getElementById("myGroup");
    svg.node().append(svgGroup);
  });

编辑:我发现这应该已经可以了,问题是我的SVG内部有几个关键的<defs>(例如,渐变)。当我仅添加组时,我丢失了它们。最后,我将<g>包裹在<defs>周围,现在一切正常。

2 个答案:

答案 0 :(得分:3)

只是对accepted answer的补充:如果您想使用纯D3解决方案,则可以将selection.append与一个函数一起使用。就您而言:

d3.xml(svgfile).then(function(xml) { 
    var svgNode = d3.select(xml).select("#MyGroup");
    svg.append(() => svgNode.node()) ;       
});

或更短:

d3.xml(svgfile).then(function(xml) { 
    svg.append(() => d3.select(xml).select("#MyGroup").node()) ;       
});

以下是使用另一个答案中链接的Wikipedia SVG的演示:

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>

答案 1 :(得分:1)

您快到了。我已经说明了添加元素in this codepen的两种方法。第一种方法的问题在于svgNode不是node,而是nodeList。您可以在循环中添加列表中的每个节点,如代码所示:

...
var toAdd = svgNode.childNodes;
for (var i = 0; i < svgNode.childElementCount; i++){     
  svg.node().appendChild(toAdd[i]);
}
...

关于第二种方法,我不能说有什么问题。我已经从其他svg文件导入了路径,该路径显示在下部。我更改的唯一细节是我显式设置了svg元素的大小,而不是设置为100%。是否有可能因为它不在可见部分之外而未渲染?