我正在尝试动态修改嵌入在html页面中的SVG文档,因此当某些事件发生(例如,按下按钮)时,我可能会添加装饰器。
为此,我首先在"onload"期间将装饰器图像插入 SVG 的 "defs" 元素中,稍后在事件发生期间将 "use" 元素添加到 SVG 组中。该代码似乎在加载期间(在 Firefox 中)添加了图像元素,并在事件发生时添加了 use 元素,但没有显示装饰器图像。如果我保留相同的 SVG 文档,则所有浏览器都会正确显示它。
让我向您展示一个简化的代码。这是一个jsfiddle,感谢Phrogz:http://jsfiddle.net/ewYkp/3/
想象一下这个html页面:
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Modification of SVG demo</title>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<script language="javascript">
var svgns = "http://www.w3.org/2000/svg";
function setOnLoad()
{
var svg = document.getElementById("SVG_IMAGE").contentDocument;
defs = svg.getElementsByTagName("defs");
def1 = defs[0];
var imageNote = document.SVG_IMAGE.contentDocument.createElementNS(svgns,"image");
imageNote.setAttribute("width","22");
imageNote.setAttribute("height","22");
imageNote.setAttribute("id","noteImage");
imageNote.setAttribute("xlink:href","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAaFJREFUOI2lk79LW1EUxz/vKZ1i4G2BZBI6FeLWdswQEnS3tDgZcFXI3xHFOrh0cElpKbg+EArJIhZBeEo6CU4vkC0Yn6nGvvd18OaZ99IM0guH++Pc7+cezjnXksT/jPn0wa/f59r52efookvg9wDIFHJUi3nqZYf3b5ashEBSbPvusexKQ6u7Lbmer8HNra4Ht3I9X6u7LdmVhvbdY01qEuJsrSnX8xVG0jCUsrWmsrWmhqEURZLr+crWmgkIkjjpeLIrjYQ4DRiGUmggdqWhk44nSViS+PC5LYBvmyVGEzl9ZTG1B/i01wbgx1bJmgc4uujyfbNENHE5t/E1Xve+rD3ly+zXS6/5aCA2QOD3eLvoIGDOlGYsSib8yd4tOnGFEmVUao5GD8iEPQdEKX8cQaaQ4/SqH78wvvD37p7wzz2WEY99p1d9MoXcM6BazHPQvpwKZTQIGA0CIiOU8R20L6kW88+Aetnh0D2j1ekSmdcyy9sxb2FlGwyk1ely6J5RLzvjxEw3UvCgf9rMRprVypPCWa1spX/jSz/TFOCl4xHBR4DBDtGdcgAAAABJRU5ErkJggg==");
def1.appendChild(imageNote);
};
function decorateSVG() {
var svg = document.getElementById("SVG_IMAGE");
var dElement = svg.contentDocument.getElementById("group1");
var useNote = svg.contentDocument.createElementNS(svgns,"use");
useNote.setAttribute("x","150");
useNote.setAttribute("y","150");
useNote.setAttribute("xlink:href","#noteImage");
dElement.appendChild(useNote);
};
</script>
</head>
<body>
<h1>Dynamic Modification of SVG demo - embed svg file with SVG image</h1>
<p> A yellow circle that was embeded using the svg "object" tag</p>
<object id="SVG_IMAGE" preserveAspectRatio="xMidYMid meet" data="basic_shapes_circle1.svg" width="400" y="0" x="0" type="image/svg+xml" onload="setOnLoad()">
</object>
<p>
<button onclick="decorateSVG('circle')">Decorate circle </button>
</p>
<hr>
</body>
</html>
以及以下 SVG 文档:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<!-- A circle of radius 200 -->
<circle id="s1" cx="200" cy="200" r="200" fill="yellow" stroke="black" stroke-width="3"/>
</defs>
<g id="group1">
<use x="0" y="0" xlink:href="#s1"/>
</g>
</svg>
代码(假设)结果是这样的:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<!-- A circle of radius 200 -->
<circle id="s1" cx="200" cy="200" r="200" fill="yellow" stroke="black" stroke-width="3"/>
<image width="22" height="22" id="noteImage" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAaFJREFUOI2lk79LW1EUxz/vKZ1i4G2BZBI6FeLWdswQEnS3tDgZcFXI3xHFOrh0cElpKbg+EArJIhZBeEo6CU4vkC0Yn6nGvvd18OaZ99IM0guH++Pc7+cezjnXksT/jPn0wa/f59r52efookvg9wDIFHJUi3nqZYf3b5ashEBSbPvusexKQ6u7Lbmer8HNra4Ht3I9X6u7LdmVhvbdY01qEuJsrSnX8xVG0jCUsrWmsrWmhqEURZLr+crWmgkIkjjpeLIrjYQ4DRiGUmggdqWhk44nSViS+PC5LYBvmyVGEzl9ZTG1B/i01wbgx1bJmgc4uujyfbNENHE5t/E1Xve+rD3ly+zXS6/5aCA2QOD3eLvoIGDOlGYsSib8yd4tOnGFEmVUao5GD8iEPQdEKX8cQaaQ4/SqH78wvvD37p7wzz2WEY99p1d9MoXcM6BazHPQvpwKZTQIGA0CIiOU8R20L6kW88+Aetnh0D2j1ekSmdcyy9sxb2FlGwyk1ely6J5RLzvjxEw3UvCgf9rMRprVypPCWa1spX/jSz/TFOCl4xHBR4DBDtGdcgAAAABJRU5ErkJggg=="/>
</defs>
<g id="group1">
<use x="0" y="0" xlink:href="#s1"/>
<use x="150" y="150" xlink:href="#noteImage"/>
</g>
</svg>
如果将 SVG 文档保存到文件中,它将在任何浏览器中正确显示。但是,在内存中修改时它似乎不起作用,我不知道为什么。有什么想法吗?
提前感谢您的帮助。
问题是您没有正确设置xlink:href
属性。您正在这样做:
someElement.setAttribute( "xlink:href", "…" );
这样做会创建一个名为"xlink:href"(无效名称)的属性,该属性没有命名空间。相反,您希望使用:
someElement.setAttributeNS( "http://www.w3.org/1999/xlink", "href", "…");
这是一个工作演示,表明无论您是将动态创建的图像直接添加到组中,还是将其放置在<defs>
部分中并通过<use>
引用它,这都有效:
演示:http://jsfiddle.net/ewYkp/4/
顺便说一句,为了方便和节省您的手腕,我推荐这样的小功能:
function createOn( dad, name, attrs, text ){
var svg = dad.ownerSVGElement, doc = dad.ownerDocument;
var ns = createOn.$NAMESPACES;
var defaultNS = svg.namespaceURI;
if (!ns){
ns = createOn.$NAMESPACES = {};
for (var a=svg.attributes,i=a.length;i--;) if (a[i].prefix=='xmlns') ns[a[i].localName] = a[i].nodeValue;
}
var p = name.split(':');
var el = p[1] ? doc.createElementNS(ns[p[0]],p[1]) : doc.createElementNS(defaultNS,name);
for (var a in attrs){
p = a.split(':');
if (p[1]) el.setAttributeNS(ns[p[0]],p[1],attrs[a]);
else el.setAttributeNS(null,a,attrs[a]);
}
if (text) el.appendChild(doc.createTextNode(text));
return dad.appendChild(el);
}
像这样使用它:
var defs = svgDoc.querySelector('defs');
var img = createOn(defs,'image',{
x:100, y:150,
width:22, height:22,
id:'noteImage', 'xlink:href':data
});
它将自动查找元素名称或属性名称的命名空间前缀,只要前缀与拥有文档上声明的命名空间匹配。下面是使用它的更新演示: