Skip to main content
 首页 » 编程设计

javascript之如何正确解释外部 SVG 文件以与two.js 一起使用

2024年02月27日11sky-heaven

如果object标签不太合适,那么是否有更好的方法来抓取SVG文件并直接用two.js操作它?或者我必须进入 SVG 并内联添加它们?

使用this question的代码和我自己的一些编辑我无法让我的对象旋转,Chrome 给我错误:未捕获的类型错误:无法读取未定义的属性“x”

HTML

<object type="image/svg+xml" data="./images/face.svg" id="face"></object> 

JS

    $(function(){   
    var svgObject = document.getElementsByTagName('object')[0]; 
        svgObject.onload = function(){ 
            var mySvg = svgObject.contentDocument.getElementsByTagName('svg')[0]; 
            var two = new Two({ 
                fullscreen:false, 
                autostart: true 
            }).appendTo(document.body); 
            var shape = two.interpret(mySvg); 
            console.log(shape); 
            two.update(); 
            two.bind('update', function() { 
                shape.rotation += 0.01; 
            }); 
        }; 
    }); 

由于所引用问题中的代码似乎适用于个人,因此我认为我只是有一个语法错误。对发生的事情有什么想法吗?

编辑:在弗朗西斯的帮助下,我能够解析自己的 SVG,以便与弗朗西斯提到的 for 循环一起使用,以便访问内部元素,但它似乎正在考虑以下 SVG 中的嵌套 G 标签为空...由于某种原因:

<svg id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="280" width="280" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><g id="layer1" transform="matrix(0.99999301,0,0,1,-400.71477,-954.83987)"><g id="g3836" transform="matrix(-0.08567939,-0.08567939,0.08567939,-0.08567939,574.3717,1199.1604)"><path id="path3801" fill="#3b5998" d="m805.17-1221.6c-902.43,902.43-902.43,2365.6,0.00003,3268l517.13-517.1c-616.83-616.83-616.83-1616.9,0-2233.8z"/><path id="rect3822" fill="#FFF" d="m266.93,336.2c0.15806,60.722,23.582,102.66,103.93,102.66h44.694v62.567h71.844v-62.57h184.55v-73.089h-184.55v-62.849l-71.844-8.5959v71.445h-44.69c-20.309,0-35.863-7.2042-35.863-35.676v-38.658h-64.869c-2.0284,15.729-3.2307,30.752-3.1941,44.765z"/></g></g></svg> 

此外,Chrome 在加载时会引发以下错误:

'Uncaught TypeError: Cannot read property 'nodeName' of null' on line 68, in the handler() function (这就是我假设的嵌套 G 被视为 null):

xmlDocValue.value+=XMLdoc.childNodes.item(1).nodeName +"\n" 

“未捕获的类型错误:无法读取上述 for 循环中未定义的属性“childNodes”,我认为这是因为 null 元素被视为 null:

myGElems = XMLdoc.childNodes.item(0).childNodes 

请您参考如下方法:

父级html无法访问<object>的内容。我假设您想要访问文件中的 svg 元素,并使用它们的 nodeName 和属性来创建两个 .js 元素。如果是这样,最好的方法是使用 XMLHttpRequest将 svg 加载为 XML,然后 DOMParser获取元素的节点名称和属性。响应文本也可以直接加载到 DIV 的innerHTML 中。

试试这个:

创建一个 SVG 文件,名为 mySVG.svg,如下所示:

<svg width="400" height="400" id="mySVG" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><circle id="myCircle"   r="100" cx="150" cy="150" fill="red" /><rect id="myRect" x="200" y="260" width="120" height="100" fill="blue" /></svg> 

然后运行以下 HTML 文件:

   <!DOCTYPE html> 
    <html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
    <title>Parse SVG Elements via XML DOM</title> 
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
    </head> 
    <body style='padding:0px;font-family:arial'> 
    <center><h4>Parse SVG Elements via XML DOM</h4> 
    <div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'> 
    Load svg files as XML via <b>XMLHttpRequest</b>. use <b>DOMParser</b> to parse the XML Document Element to create a client's svg elements. 
    </div> 
    <br />mySVG.svg: 
    <textarea id=svgValue style='width:90%;height:200px;font-size:120%;font-family:lucida console;'></textarea> 
    <center><b>SVG Inline</b></center> 
    <div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;' ></div> 
    <br /><button onClick=loadSVGXML()>load svg as xml</button><br /> 
    <center><b>XML Doc</b></center> 
    <textarea id=xmlDocValue style='width:90%;height:100px;font-size:120%;font-family:lucida console;'></textarea> 
    </center> 
    <script id=myScript> 
    /* 
    mySVG.svg 
    <svg id="mySVG"  version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><circle id="myCircle"   r="100" cx="150" cy="150" fill="red" /><rect id="myRect" x="200" y="260" width="120" height="100" fill="blue" /></svg> 
    */ 
    //--onload--- 
    function loadSVGInline() 
    { 
        var SVGFile="mySVG.svg" 
        var loadXML = new XMLHttpRequest; 
        function handler(){ 
            if(loadXML.readyState == 4 && loadXML.status == 200) 
            { 
                svgDiv.innerHTML=loadXML.responseText 
                svgValue.value=loadXML.responseText 
            } 
        } 
        if (loadXML != null){ 
            loadXML.open("GET", SVGFile, true); 
            loadXML.onreadystatechange = handler; 
            loadXML.send(); 
        } 
    } 
 
 
/* NOTE: 
If you 'hand-craft' an  svg file it may include carriage returns, or extraneous spaces between elements, the xml dom will interpret 
them as #text elements, and may cause errors. Either remove carriage returns and spaces, or filter the elements 
to ignore the #text elements. 
*/ 
 
    var  XMLdoc 
    function loadSVGXML() 
    { 
        var SVGFile="mySVG.svg" 
        var loadXML = new XMLHttpRequest; 
        function handler() 
        { 
            if(loadXML.readyState == 4 && loadXML.status == 200) 
            { 
                //---responseText--- 
                var xmlString=loadXML.responseText 
                //---DOMParser--- 
                var parser = new DOMParser(); 
                XMLdoc=parser.parseFromString(xmlString,"text/xml").documentElement; 
 
                xmlDocValue.value=XMLdoc.childNodes.item(0).nodeName +"\n" 
                xmlDocValue.value+=XMLdoc.childNodes.item(0).getAttribute("fill") +"\n" 
                xmlDocValue.value+=XMLdoc.childNodes.item(1).nodeName +"\n" 
                xmlDocValue.value+=XMLdoc.childNodes.item(1).getAttribute("fill") 
 
                //---to add xml element as svg use element.cloneNode(true)--- 
                var xmlNode1=XMLdoc.childNodes.item(1) 
                var svgNode1=xmlNode1.cloneNode(true) 
                svgNode1.setAttribute("x",20) 
                svgNode1.setAttribute("fill","orange") 
                mySVG.appendChild(svgNode1) 
            } 
        } 
        if (loadXML != null){ 
            loadXML.open("GET", SVGFile, true); 
            loadXML.onreadystatechange = handler; 
            loadXML.send(); 
        } 
    } 
    </script> 
    <script> 
    document.addEventListener("onload",init(),false) 
    function init() 
    { 
        loadSVGInline() 
    } 
    </script> 
    </body> 
    </html>