Ответ 1
В общем случае проблема состоит в следующем: twofold:
-
HTML не является XHTML, а поддержка SVG в HTML является дрянной и плохо определенной на момент написания. Решение заключается в использовании реального документа XHTML, где элементы, помеченные SVG-именами, фактически рассматриваются как SVG.
-
responseXML
находится в другом документе DOM, и вы обычно не можете просто перемещать узлы из одного документа в другой. Вы должны использоватьdocument.importNode
для импорта node из одного документа в другой. -
Загрузка SVG файла с обработчиками событий
onload
не будет иметь эти обработчики, вызванные либо созданием node, либо добавлением его в документ. Однако код внутри блокаscript
будет запущен, поэтому вам нужно будет переписать сценарии так, чтобы они работали автономно, а также с динамической загрузкой.
Вот простой пример, который работает в Chrome, Safari и Firefox... но не в IE9:
var xhr = new XMLHttpRequest;
xhr.open('get','stirling4.svg',true);
xhr.onreadystatechange = function(){
if (xhr.readyState != 4) return;
var svg = xhr.responseXML.documentElement;
svg = document.importNode(svg,true); // surprisingly optional in these browsers
document.body.appendChild(svg);
};
xhr.send();
Смотрите здесь: http://phrogz.net/SVG/import_svg.xhtml
К сожалению, IE9 не поддерживает document.importNode
. Чтобы обойти это, мы пишем нашу собственную функцию cloneToDoc
, которая создает эквивалентную структуру для любого заданного node путем рекурсивного обхода иерархии. Вот полный рабочий пример:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
<meta http-equiv="content-type" content="application/xhtml+xml;charset=utf-8"/>
<title>Fetch and Include SVG in XHTML</title>
<script type="text/ecmascript"><![CDATA[
setTimeout(function(){
var xhr = new XMLHttpRequest;
xhr.open('get','stirling4.svg',true);
xhr.onreadystatechange = function(){
if (xhr.readyState != 4) return;
var svg = cloneToDoc(xhr.responseXML.documentElement);
document.body.appendChild(svg);
};
xhr.send();
},1000);
function cloneToDoc(node,doc){
if (!doc) doc=document;
var clone = doc.createElementNS(node.namespaceURI,node.nodeName);
for (var i=0,len=node.attributes.length;i<len;++i){
var a = node.attributes[i];
if (/^xmlns\b/.test(a.nodeName)) continue; // IE can't create these
clone.setAttributeNS(a.namespaceURI,a.nodeName,a.nodeValue);
}
for (var 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),
null
); }
return clone;
}
]]></script>
</head><body></body></html>
Смотрите здесь: http://phrogz.net/SVG/import_svg_ie9.xhtml
Изменить 2: Как подозревается, проблема в том, что событие onload
не срабатывает при динамическом добавлении script. Здесь работает парное решение:
- Перепишите script, чтобы удалить обработчик события
onload
. Вместо этого убедитесь, чтоdocument
существует. - Перепишите script запрос глобального
svgRoot
; если он не существует, используйтеdocument.documentElement
. - При извлечении SVG установите глобальный
svgRoot
в новый элементsvg
после его импорта в документ.
Здесь код в действии:
- Автономный сценарий SVG: http://phrogz.net/SVG/script-created.svg
- IE9-дружественная страница, которая импортирует ее: http://phrogz.net/SVG/import_svg_with_script.xhtml
И, если мой сайт не работает, вот код для потомков:
script -created.svg
<svg xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript"><![CDATA[
function createOn( root, name, a ){
var el = document.createElementNS(svgNS,name);
for (var n in a) if (a.hasOwnProperty(n)) el.setAttribute(n,a[n]);
return root.appendChild(el);
}
// Trust someone else for the root, in case we're being
// imported into another document
if (!window.svgRoot) svgRoot=document.documentElement;
var svgNS = svgRoot.namespaceURI;
createOn(svgRoot,'rect',{
x:10, y:10, width:30, height:30,
stroke:'#8080ff', "stroke-width":5,
fill:"none"
});
]]></script>
</svg>
import_svg_with_script.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
<meta http-equiv="content-type"
content="application/xhtml+xml;charset=utf-8" />
<title>Fetch and Include Scripted SVG in XHTML</title>
<script type="text/ecmascript"><![CDATA[
setTimeout(function(){
var xhr = new XMLHttpRequest;
xhr.open('get','script-created.svg',true);
xhr.onreadystatechange = function(){
if (xhr.readyState != 4) return;
var svg = xhr.responseXML.documentElement;
svg = cloneToDoc(svg);
window.svgRoot = svg; // For reference by scripts
document.body.appendChild(svg);
delete window.svgRoot;
};
xhr.send();
},1000);
function cloneToDoc(node,doc){
if (!doc) doc=document;
var clone = doc.createElementNS(node.namespaceURI,node.nodeName);
for (var i=0,len=node.attributes.length;i<len;++i){
var a = node.attributes[i];
if (/^xmlns\b/.test(a.nodeName)) continue; // IE can't create these
clone.setAttributeNS(a.namespaceURI,a.nodeName,a.nodeValue);
}
for (var 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),
null
)
}
return clone;
}
]]></script>
</head><body></body></html>