如何将SVG图像动态插入HTML?

我有一些代码可以通过Ajax从服务器检索脚本svg图像。我可以将图像文本返回到浏览器中,但我找不到将其插入到实际显示它的DOM中的方法。有人能帮忙吗?
svg如下所示:

<svg id=“chart”xmlns=”http://www.w3.org/2000/svg“xmlns:xlink=”http://www.w3.org/1999/xlink“onload=“init(evt)”>
<script type=“application/ecmascript”>
<![CDATA[
…大量代码,每个Ajax请求都会发生更改
//]]&燃气轮机;
&lt/脚本>
<script type=“application/ecmascript”xlink:href=”https://stackoverflow.com/questions/7981100/js-on-server-1.js“/>
<script type=“application/ecmascript”xlink:href=”https://stackoverflow.com/questions/7981100/js-on-server-2.js“/>
&lt/svg>

我试过各种各样的东西。如果我这样做:

//xmlhttp.onreadystatechange:
addImage(xmlhttp.responseXML,“某处”);
...
函数addImage(txt,dst_id){
var scr=document.createElement(“div”);
如果(“scr中的文本内容”)
scr.textContent=txt;//其他人
其他的
scr.text=txt;//IE
document.getElementById(dst_id).appendChild(scr);
}

然后Opera和Chrome什么也不做,F/F抱怨“[object XMLDocument]”。如果我将“responseXML”更改为“responseText”,则Opera/Chrome会在正确的位置正确显示整个svg文本(而不是图像),而F/F仍会给出相同的警告。
我还尝试将响应分配给innerHTML,但这没有任何作用。
有什么想法吗?谢谢

编辑

为了回应下面的Phrogz’z回答,我添加了两个简单的svg文件。第一个是一个“标准”的简单svg,显示一个圆圈。第二个是脚本svg,显示一个矩形。除了IE8-,您应该能够在任何浏览器中直接查看两者。
如果我编辑Phrogz’z代码以使用圆形文件(将“stirling4.svg”替换为该文件的名称),那么它可以工作,但是如果我想要脚本化的矩形,它就不能工作。在F/F、Opera、Chromium上测试,但在(我的)Chromium上无论如何都不起作用

文件1,圆圈:

<svg xmlns=”http://www.w3.org/2000/svg“version=“1.1”>
<圆圈cx=“100”cy=“50”r=“40”stroke=“黑色”stroke width=“2”fill=“红色”/>
&lt/svg>

文件2,矩形:

<svg xmlns=”http://www.w3.org/2000/svg“xmlns:xlink=”http://www.w3.org/1999/xlink“onload=“init(evt)”>
<script type=“application/ecmascript”>
<![CDATA[
var-svgDocument;
var svgns=”http://www.w3.org/2000/svg";
函数初始化(evt){
if(window.svgDocument==null)
svgDocument=evt.target.ownerDocument;
var lbox=svgDocument.createElements(svgns,“rect”);
lbox.setAttributeNS(null,“x”,10);
lbox.setAttributeNS(null,“y”,10);
lbox.setAttributeNS(空,“宽度”,30);
lbox.setAttributeNS(空,“高度”,30);
lbox.setAttributeNS(空,“笔划”,“#8080ff”);
lbox.setAttributeNS(空,“笔划宽度”,2);
lbox.setAttributeNS(null,“填充不透明度”,0);
lbox.setAttributeNS(空,“笔划不透明度”,1);
setAttributeNS(null,“stroke dasharray”,0);
svgDocument.documentElement.appendChild(lbox);
}
//]]&燃气轮机;
&lt/脚本>
&lt/svg>

大概答案是将脚本放入标题

一般来说,问题是双重的:

  1. HTML不是XHTML,在撰写本文时,HTML中对SVG的支持是不完善的,而且定义也很差。解决方案是使用真正的XHTML文档,其中SVG名称空间的元素实际上被视为SVG

  2. responseXML位于另一个DOM文档中,通常不能将节点从一个文档移动到另一个文档。您应该使用document.importNode将节点从一个文档导入到另一个文档

  3. 使用onload事件处理程序加载SVG文件不会通过创建节点或将其附加到文档中来调用这些处理程序。但是,script块中的代码将被运行,因此您需要以一种独立工作的方式重写脚本,同时也可以使用动态加载


下面是一个在Chrome、Safari和Firefox中工作的简单示例……但不是IE9:

var xhr=new-XMLHttpRequest;
open('get','stirling4.svg',true);
xhr.onreadystatechange=函数(){
如果(xhr.readyState!=4)返回;
var svg=xhr.responseXML.documentElement;
svg=document.importNode(svg,true);//在这些浏览器中是可选的
document.body.appendChild(svg);
};
xhr.send();

请在此处查看它的实际操作:http://phrogz.net/SVG/import_svg.xhtml


不幸的是,IE9不能正确支持document.importNode。为了解决这个问题,我们编写了自己的cloneToDoc函数,通过递归地对层次结构进行爬网,为任何给定节点创建一个等效结构。下面是一个完整的工作示例:

<html xmlns=”http://www.w3.org/1999/xhtml“xml:lang=“en”&gt&书信电报;头>
<meta-http equiv=“content-type”content=“application/xhtml+xml;charset=utf-8”/>
<标题>在XHTML中获取并包含SVG&lt/标题>
<script type=“text/ecmascript”&gt&书信电报;![CDATA[
setTimeout(函数(){
var xhr=新的XMLHttpRequest;
open('get','stirling4.svg',true);
xhr.onreadystatechange=函数(){
如果(xhr.readyState!=4)返回;
var svg=cloneToDoc(xhr.responseXML.documentElement);
document.body.appendChild(svg);
};
xhr.send();
},1000);
函数cloneToDoc(节点,文档){
如果(!doc)doc=单据;
var clone=doc.createElements(node.namespaceURI,node.nodeName);
对于(变量i=0,len=node.attributes.length;i<len;++i){
var a=节点属性[i];
如果(/^xmlns\b/.test(a.nodeName))继续;//IE无法创建这些
clone.setAttributeNS(a.namespaceURI、a.nodeName、a.nodeValue);
}
对于(变量i=0,len=node.childNodes.length;i<len;++i){
var c=node.childNodes[i];
clone.insertBefore(
c、 nodeType==1?cloneToDoc(c,doc):doc.createTextNode(c.nodeValue),
无效的
); }
返回克隆;
}
]]&燃气轮机&lt/脚本>
&lt/头&gt&书信电报;车身&gt&lt/车身&gt&lt/html>

请在此处查看它的实际操作:http://phrogz.net/SVG/import_svg_ie9.xhtml


编辑2:正如所怀疑的,问题在于动态添加脚本时不会触发onload事件。以下是一个有效的配对解决方案:

  1. 重写脚本以删除onload事件处理程序。相反,请相信文档存在
  2. 重写脚本以请求全局svgRoot;如果它不存在,请使用document.documentElement
  3. 获取SVG时,在将其导入文档后,将全局svgRoot设置为新的SVG元素

以下是正在运行的代码:

  • 独立脚本SVG:http://phrogz.net/SVG/script-created.svg
  • 导入它的IE9友好页面:http://phrogz.net/SVG/import_svg_with_script.xhtml

如果我的网站关闭了,下面是给后代的代码:

脚本已创建。svg

<svg xmlns=”http://www.w3.org/2000/svg“>
<script type=“text/javascript”&gt&书信电报;![CDATA[
函数createOn(根、名称、a){
var el=document.createElements(svgNS,name);
对于(a中的var n)如果(a.hasOwnProperty(n))el.setAttribute(n,a[n]);
返回root.appendChild(el);
}
//相信别人的根,以防我们
//导入到另一个文档中
如果(!window.svgRoot)svgRoot=document.documentElement;
var svgNS=svgRoot.namespaceURI;
createOn(svgRoot,'rect'{
x:10,y:10,宽30,高30,
笔划:'#8080ff',“笔划宽度”:5,
填写:“无”
});
]]&燃气轮机&lt/脚本>
&lt/svg>

使用脚本.xhtml导入svg

<html xmlns=”http://www.w3.org/1999/xhtml“xml:lang=“en”&gt&书信电报;头>
<meta http equiv=“内容类型”
content=“application/xhtml+xml;charset=utf-8”/>
<标题>在XHTML中获取并包含脚本SVG&lt/标题>
<script type=“text/ecmascript”&gt&书信电报;![CDATA[
setTimeout(函数(){
var xhr=新的XMLHttpRequest;
open('get','script-created.svg',true);
xhr.onreadystatechange=函数(){
如果(xhr.readyState!=4)返回;
var svg=xhr.responseXML.documentElement;
svg=cloneToDoc(svg);
window.svgRoot=svg;//供脚本参考
document.body.appendChild(svg);
删除window.svgRoot;
};
xhr.send();
},1000);
函数cloneToDoc(节点,文档){
如果(!doc)doc=单据;
var clone=doc.createElements(node.namespaceURI,node.nodeName);
对于(变量i=0,len=node.attributes.length;i<len;++i){
var a=节点属性[i];
如果(/^xmlns\b/.test(a.nodeName))继续;//IE无法创建这些
clone.setAttributeNS(a.namespaceURI、a.nodeName、a.nodeValue);
}
对于(变量i=0,len=node.childNodes.length;i<len;++i){
var c=node.childNodes[i];
clone.insertBefore(
c、 nodeType==1?cloneToDoc(c,doc):doc.createTextNode(c.nodeValue),
无效的
)
}
返回克隆;
}
]]&燃气轮机&lt/脚本>
&lt/头&gt&书信电报;车身&gt&lt/车身&gt&lt/html>

发表评论