(嵌入和)通过 D3 和/或 javascript 引用外部 SVG
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21209549/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
(Embed and) Refer to an external SVG via D3 and/or javascript
提问by Seb Waynee
I have an .svg file and want to embed it in the svg strucure of my d3-graphic.
我有一个 .svg 文件,想将它嵌入到我的 d3-graphic 的 svg 结构中。
I also need to reference all paths/polygons attached to g-elements via an id of certain g elements.
我还需要通过某些 g 元素的 id 引用附加到 g 元素的所有路径/多边形。
I tried different ways to to embed and reference the svg (g's), but it didn't work for some reasons:
我尝试了不同的方法来嵌入和引用 svg (g's),但由于某些原因它不起作用:
(1) first attempt
(1) 第一次尝试
// Firefox displays my svg but when i open it with Chrome the svg
//is not displayed (just default placeholder icon)
// I can't reference the svg-g id's with d3.select functions.
main_chart_svg
.append("svg:image")
.attr("xlink:href", "mySVGpicture.svg")
.attr("x", "50")
.attr("y", "50")
.attr("width", "500")
.attr("height", "500");
main_chart_svg.select("#anIdWhichIsInTheSvgFile").remove(); //// This doesn't work
(2) second attempt
(2) 第二次尝试
// This displays the svg but -not- inside my main-chart-svg. I want to keep the graphic
//things seperate to html-stuff.
d3.xml("mySVGpicture.svg", "image/svg+xml", function(xml) {
document.body.appendChild(xml.documentElement);
});
//----------or----------//
d3.select("body")
.append("object")
.attr("data", "mySVGpicture.svg")
.attr("width", 500)
.attr("height", 500)
.attr("type", "image/svg+xml");
d3.select("#anIdThatIsInTheSvgFile").remove(); //does not work.
(3) The svg-file looks something like that:
(3) svg 文件看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="400px"
height="400px" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
<g id="anIdWhichIsInTheSvgFile">
<g id="DE">
<path fill="#FEDCBD" d="M215.958,160.554c0,0-0.082, ... ,1.145
l0.865,0.656L215.958,160.554z"/>
<path fill="#FEDCBD" d="M208.682,155.88l1.246,1.031c0,0,0.191,0.283, ... ,0.572L208.682,155.88z"/>
<polygon fill="#FEDCBD" points="190.76,153.007 190.678, ... ,153.938
191.427,152.906"/>
<polygon fill="#FEDCBD" points="170.088,151.015 169.888,150.067 169.125,150.075 168.846,150.836 169.521,151.588"/>
<polygon fill="#FEDCBD" points="168.953,152.067 168.188,151.505 168.674,152.639"/>
<polygon fill="#FEDCBD" points="170.105,153.099 170.666,152.052 170.002,152.248"/>
</g>
<g id="anIdThatIsInTheSvgFile">
...
</g>
</svg>
回答by AmeliaBR
There's a better solution.
有一个更好的解决方案。
I hadn't realized that the d3.xml()
function returns a read-in xml file as a document fragment(as opposed to converting it to JSON). In other words, it returns a ready-made DOM tree that can be inserted within you main document's DOM wherever you need it.
我没有意识到该d3.xml()
函数将读入的 xml 文件作为文档片段返回(而不是将其转换为 JSON)。换句话说,它返回一个现成的 DOM 树,可以在您需要的任何地方插入主文档的 DOM 中。
Knowing that (and knowing that stand-alone SVG files are also XML files), this is likely the most reliable approach for adding external SVG content to your webpage:
知道(并且知道独立的 SVG 文件也是 XML 文件),这可能是将外部 SVG 内容添加到网页的最可靠方法:
d3.xml("http://upload.wikimedia.org/wikipedia/commons/a/a0/Circle_-_black_simple.svg",
function(error, documentFragment) {
if (error) {console.log(error); return;}
var svgNode = documentFragment
.getElementsByTagName("svg")[0];
//use plain Javascript to extract the node
main_chart_svg.node().appendChild(svgNode);
//d3's selection.node() returns the DOM node, so we
//can use plain Javascript to append content
var innerSVG = main_chart_svg.select("svg");
innerSVG.transition().duration(1000).delay(1000)
.select("circle")
.attr("r", 100);
});
Fiddle here: http://jsfiddle.net/J8sp3/4/
在这里小提琴:http: //jsfiddle.net/J8sp3/4/
Notice in particular that (a) I am adding the content to an existing SVG, and (b) I am not deleting any of that SVG's current content.
请特别注意 (a) 我将内容添加到现有 SVG,以及 (b) 我没有删除该 SVG 的任何当前内容。
Of course, you can also add the SVG to a <div>
or any other element that can contain it: http://jsfiddle.net/J8sp3/3/
当然,您也可以将 SVG 添加到一个<div>
或任何其他可以包含它的元素中:http: //jsfiddle.net/J8sp3/3/
This method should work in any browser that supports SVG. I even tried it in IE8, and the DOM structure is correct even if IE8 doesn't know how to draw circles and rectangles!
这种方法应该适用于任何支持 SVG 的浏览器。我什至在IE8中尝试过,即使IE8不知道如何绘制圆形和矩形,DOM结构也是正确的!
@Seb, please unselect the previous answer at pick this one as the accepted answer.
@Seb,请在选择此答案时取消选择先前的答案作为已接受的答案。
回答by AmeliaBR
The proper format for embedding SVG content from another file is to use a <use>
element. However, you cannot then access the DOM structure (i.e., individual elements) of the nested SVG -- it's all treated as a single image.
从另一个文件嵌入 SVG 内容的正确格式是使用<use>
元素。但是,您随后无法访问嵌套 SVG 的 DOM 结构(即,单个元素)——它们都被视为单个图像。
If you want to be able to modify the graphic described by the external file, you would be better off reading the external file as a text/XML file (using d3.text
), and then using that XML text to create the SVG graphic in the DOM by writing the content as the inner HTML of a container <div>
如果您希望能够修改外部文件描述的图形,最好将外部文件作为文本/XML 文件读取(使用d3.text
),然后使用该 XML 文本在 DOM 中创建 SVG 图形将内容编写为容器的内部 HTML<div>
d3.text("mySVGpicture.svg", function(error, externalSVGText) {
if (error) {console.log(error); return;}
chart_div.html(externalSVGText);
svg = chart_div.select("svg");
do_stuff();
});
Your DOM should now look like
你的 DOM 现在应该看起来像
body
div.chart
svg
g#anIDWhichIsInTheSVGFile
g#DE
path
/*etc*/
g#anotherIDWhichIsInTheSVGFile
You can now select elements as normal, and set the position or size of the svg you created or remove g elements or whatever -- they are all just normal elements in your DOM. Make sure that your "id" attributes don't conflict -- they have to be unique for the entire page.
您现在可以正常选择元素,并设置您创建的 svg 的位置或大小,或者删除 g 元素或其他任何东西——它们都只是 DOM 中的普通元素。确保您的“id”属性不冲突——它们在整个页面中必须是唯一的。
Example here, showing additional content added to the SVG with d3, and a d3 transition selecting and modifying an element from the external SVG:
http://jsfiddle.net/J8sp3/2/
此处的示例显示了使用 d3 添加到 SVG 的附加内容,以及从外部 SVG 中选择和修改元素的 d3 转换:http:
//jsfiddle.net/J8sp3/2/
WARNING
警告
The original version of this answer suggested adding the external SVG content as a nested SVG inside the SVG that had already been created with D3.
此答案的原始版本建议将外部 SVG 内容添加为已使用 D3 创建的 SVG 内的嵌套 SVG。
As Seb discovered, this method does not workon the latest Safari and Opera browsers, or on Chrome 31 and under.
正如 Seb 发现的那样,此方法不适用于最新的 Safari 和 Opera 浏览器,或 Chrome 31 及以下版本。
The problem is in the way the webkit browsers implement the innerHTML
function, which is called by d3's selection.html()
function. Specifically, the innerHTML
function isn't implemented at all on SVG elements!
问题在于 webkit 浏览器实现该innerHTML
函数的方式,该函数由 d3 的selection.html()
函数调用。具体来说,该innerHTML
功能根本没有在 SVG 元素上实现!
What's most confusing is that the method doesn't return any errors, and some versions of Chrome actually display the SVG content without adding it to the DOM (as if you used <use xlink:href="external.svg"/>
).
最令人困惑的是该方法不会返回任何错误,并且某些版本的 Chrome 实际上显示 SVG 内容而不将其添加到 DOM(就像您使用了<use xlink:href="external.svg"/>
)。