JavaScript createElementNS and SVG

53

我想使用JavaScript创建内联SVG图形。

但是,似乎createElementNS函数应用了一些规范化并将所有标记转换为小写。这对HTML来说是可以的,但对于XML / SVG来说不是。我使用的名称空间是http://www.w3.org/2000/svg

特别是我在创建<textpath>元素时遇到了问题。因为它将作为<textpath>附加,所以不起作用。

我进行了一些搜索,但还没有找到解决方案。

有人知道解决方案吗?

document.createElementNS("http://www.w3.org/2000/svg","textPath");

导致

<textpath></textpath>

你如何找出这种情况发生了?你如何将创建的元素转储到XML代码中?XML标记名称应该是大小写敏感的:http://ejohn.org/blog/nodename-case-sensitivity/ - Pekka
4个回答

84

我希望以下例子能对你有所帮助:

function CreateSVG() {
    var xmlns = "http://www.w3.org/2000/svg";
    var boxWidth = 300;
    var boxHeight = 300;

    var svgElem = document.createElementNS(xmlns, "svg");
    svgElem.setAttributeNS(null, "viewBox", "0 0 " + boxWidth + " " + boxHeight);
    svgElem.setAttributeNS(null, "width", boxWidth);
    svgElem.setAttributeNS(null, "height", boxHeight);
    svgElem.style.display = "block";

    var g = document.createElementNS(xmlns, "g");
    svgElem.appendChild(g);
    g.setAttributeNS(null, 'transform', 'matrix(1,0,0,-1,0,300)');

    // draw linear gradient
    var defs = document.createElementNS(xmlns, "defs");
    var grad = document.createElementNS(xmlns, "linearGradient");
    grad.setAttributeNS(null, "id", "gradient");
    grad.setAttributeNS(null, "x1", "0%");
    grad.setAttributeNS(null, "x2", "0%");
    grad.setAttributeNS(null, "y1", "100%");
    grad.setAttributeNS(null, "y2", "0%");
    var stopTop = document.createElementNS(xmlns, "stop");
    stopTop.setAttributeNS(null, "offset", "0%");
    stopTop.setAttributeNS(null, "stop-color", "#ff0000");
    grad.appendChild(stopTop);
    var stopBottom = document.createElementNS(xmlns, "stop");
    stopBottom.setAttributeNS(null, "offset", "100%");
    stopBottom.setAttributeNS(null, "stop-color", "#0000ff");
    grad.appendChild(stopBottom);
    defs.appendChild(grad);
    g.appendChild(defs);

    // draw borders
    var coords = "M 0, 0";
    coords += " l 0, 300";
    coords += " l 300, 0";
    coords += " l 0, -300";
    coords += " l -300, 0";

    var path = document.createElementNS(xmlns, "path");
    path.setAttributeNS(null, 'stroke', "#000000");
    path.setAttributeNS(null, 'stroke-width', 10);
    path.setAttributeNS(null, 'stroke-linejoin', "round");
    path.setAttributeNS(null, 'd', coords);
    path.setAttributeNS(null, 'fill', "url(#gradient)");
    path.setAttributeNS(null, 'opacity', 1.0);
    g.appendChild(path);

    var svgContainer = document.getElementById("svgContainer");
    svgContainer.appendChild(svgElem);
}
#svgContainer {
  width: 400px;
  height: 400px;
  background-color: #a0a0a0;
}
<body onload="CreateSVG()">
    <div id="svgContainer"></div>
</body>


感谢您的回复。基于您的答复和 text-to-path svg 的示例:http://pmast.de/svg/textToPath.svg 我创建了以下文档:http://pmast.de/svg/textToPath.html。 尽管生成的源代码似乎是相同的,并且元素的创建遵循了您的示例,但我的文档不起作用。。。 我有什么遗漏吗? - pat
你的例子帮助我开始使用JS创建SVG元素。但仍需阅读W3.org Core DOM规范文档。命名空间相当令人困惑。感谢你的建议。 - CyberFonic
3
这对人们有效吗?我只看到一个灰色的框,没有任何SVG元素。(无论是在Firefox还是Chrome中) - schlingel

17

首先,像你正在做的那样使用createElementNS。根据 Mozilla文档,createElement(没有NS)会自动将HTML文档中的元素名称转换为小写。

其次,在这里不要相信Google Chrome的“检查元素”功能。它似乎显示每个元素都是小写的,无论实际的nodeName是什么。尝试这个:

document.createElementNS("http://www.w3.org/2000/svg", "textPath").nodeName
// Output: "textPath"

document.createElement("textPath").nodeName
// Output: "TEXTPATH"

您的问题可能与其他问题无关。例如,此代码在Firefox中运行良好,但在Chrome(12.0.742.112)中出现故障:

function animateSVG() {
  var svgNS = "http://www.w3.org/2000/svg";
  var textElement = document.getElementById("TextElement");
  var amElement = document.createElementNS(svgNS, "animateMotion");
  console.log(textElement);
  console.log(amElement);
  console.log(amElement.nodeName);
  amElement.setAttribute("path", "M 0 0 L 100 100");
  amElement.setAttribute("dur", "5s");
  amElement.setAttribute("fill", "freeze");
  textElement.appendChild(amElement);
  //amElement.beginElement();
};
<body onload="animateSVG()">
  <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <g transform="translate(100,100)">
      <text id="TextElement" x="0" y="0" style="font-family:Verdana;font-size:24">
        It's SVG!
        <!-- <animateMotion path="M 0 0 L 100 100" dur="5s" fill="freeze"/> -->
      </text>
    </g>
  </svg>
</body>

我的问题可能与Chrome中animateMotion的处理有关(Issue 13585)。

你的问题可能相同,也可能是其他问题,但请确保你没有被元素检查器欺骗。


4
你关于Chrome的"检查元素"功能的评论救了我的一天,谢谢。 - ZPiDER

2

我刚解决了一个类似的问题。当在HTML页面中调用document.createElement(我假设document.createElementNS也是如此)时,会创建一个HTML节点(大小写不敏感),而不是XML节点。

以下方法适用于Chrome:

doc = document.implementation.createDocument(null, null, null); doc.createElementNS("http://www.w3.org/2000/svg","textPath");

这样你就可以得到大小写混合的节点了。


1
document.createElementNS() 不仅可以创建 HTML 元素。这个回答怎么会有 5 个赞? - zoran404

-3

这个答案过于详细,对我并不是非常有用,而且我发现它太麻烦了,或者简单地说就是虚假的。如果我是你,我会在HTML中只使用一个元素和标签:

<b id="myElement"></b>

当我需要创建元素或添加信息时,我只需执行以下操作:

document.getElementById('myElement').innerHTML = 'your stuff here'; 

希望这对你有所帮助。


2
这个问题是关于SVG而不是HTML的。 - gilly3
3
他说得有道理 -- 所接受的答案基本上是从头开始构建一个SVG DOM元素,虽然知道如何做这个很好,而且技术上来说也是更正确的答案,但不完全实用。由于SVG文件中的SVG语法与DOM中的SVG定义语法(从“<svg”子字符串开始)大部分相同,因此将像span或b这样的容器元素的innerHTML属性设置为原始SVG数据更加实用 -- 这样浏览器就会为您处理艰难的解析和构造工作。我认为这是一个有效的“快速修复”答案。 - CCJ
3
这是一个非常特定的使用案例 - 将整个SVG绘图标记作为一个字符串,并将其原样附加到HTML元素。问题特别询问如何向现有的绘图添加SVG元素。现在,您可以在某些浏览器中编写SVG元素的innerHTML,但是该功能是新的,仅自今年早些时候开始提供。今天,在IE中向现有绘图添加元素的唯一方法,以及在提出这个问题时所有浏览器中都是通过使用createElementNS() - gilly3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接