当前位置: 首页 > 面试题库 >

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

牛华皓
2023-03-14
问题内容

我有一些代码可以通过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[
...lots of code, changes on each Ajax request
//]]>
</script>
<script type="application/ecmascript" xlink:href="js-on-server-1.js"/>
<script type="application/ecmascript" xlink:href="js-on-server-2.js"/>
</svg>

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

// xmlhttp.onreadystatechange:
addImage(xmlhttp.responseXML, "somewhere");
...
function addImage(txt, dst_id) {
   var scr = document.createElement("div");

   if("textContent" in scr)
      scr.textContent = txt;  // everybody else
   else
      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上进行了测试,但在(my)Chromium上仍然无法正常工作。

文件1,圈出:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</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";
function init(evt) {
  if(window.svgDocument == null)
    svgDocument = evt.target.ownerDocument;
   var lbox = svgDocument.createElementNS(svgns, "rect");
   lbox.setAttributeNS(null, "x",                10);
   lbox.setAttributeNS(null, "y",                10);
   lbox.setAttributeNS(null, "width",            30);
   lbox.setAttributeNS(null, "height",           30);
   lbox.setAttributeNS(null, "stroke",           "#8080ff");
   lbox.setAttributeNS(null, "stroke-width",     2);
   lbox.setAttributeNS(null, "fill-opacity",     0);
   lbox.setAttributeNS(null, "stroke-opacity",   1);
   lbox.setAttributeNS(null, "stroke-dasharray", 0);
   svgDocument.documentElement.appendChild(lbox);
}
//]]>
</script>
</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;
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函数,该函数通过递归爬网层次结构为任何给定节点创建等效结构。这是一个完整的工作示例:

<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动态添加脚本时事件不会触发。这是一个有效的配对解决方案:

  1. 重写脚本以删除onload事件处理程序。相反,document存在的信任。
  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"><![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>


 类似资料:
  • 问题内容: 我正在使用python 3.5.2,我想制作一个嵌入了png图像的饼图。我有一些我想插入切片的散装产品的图片。例如,一片草莓,另一片覆盆子。就像http://www.python- course.eu/images/pie_chart_with_raspberries.png 显示的图片一样。 我可以生成图像,甚至可以绘制图像而不是点,如此处所示Matplotlib:如何绘制图像而不是

  • 本文向大家介绍C#下listview如何插入图片,包括了C#下listview如何插入图片的使用技巧和注意事项,需要的朋友参考一下 如何在listview中插入图片,相信大家很想知道,下面就为大家分享具体步骤: 第一步:在窗体中拖入ListView控件和imageList控件; 第二步:设置imageList控件的Images属性,添加你想要的图片; 第三步:设置ListView控件的SmallI

  • 问题内容: 我正在尝试创建字符串到字符串的映射。以下是我尝试过的方法,但两种方法均无效。它出什么问题了? 问题答案: 这里有两个问题。 首先,您不能像其他语言那样使用语法。方括号仅适用于Java中的数组,因此只能与整数索引一起使用。 是正确的,但这是一条语句,因此必须存在于方法块中。在类级别只能存在字段声明。这是一个示例,其中所有内容都在方法的本地范围内: 如果要将映射初始化为类的静态字段,则可以

  • 上一篇尝试了变换颜色,这一篇来尝试一下动态图片,前面的两步都一致,这里直接说回调吧, 绘制时间 首先要确定在哪里添加回调, viewer.entities.add({ name: 'Rotating rectangle with rotating texture coordinate', rectangle: { coordinates: Cesium.Rectan

  • 问题内容: 我的Postgres版本是: “PostgreSQL 9.4.4, compiled by Visual C++ build 1800, 32-bit” 假设我有两个表Table1和Table2,分别具有columncol1和col2。 还有另一个表,Table3用于存储将数据从迁移Table1到的公式Table2: 如何在动态查询中编译此公式并将其插入目标表? 问题答案: 动态构建命

  • insertImage(int $row, int $column, string $localImagePath[, double $widthScale, double $heightScale]) int $row $excel = new \Vtiful\Kernel\Excel($config); ​ $freeFile = $excel->fileName("free.xlsx");