在SVG中包含JavaScript

mor*_*alc 29 javascript svg interactive

我试图通过在JavaScript中嵌入JavaScript来使用JavaScript创建交互式SVG代码.我不知道这是否是正确的方法:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg"
onkeypress="move()">
<script type="text/javascript">
    <![CDATA[
    var x;
    var y;
    function move()
    {
        x = new Number(svg.getElementsByTagName("circle")[0].getAttribute("cx"));
        y = new Number (svg.getElementsByTagName("circle")[0].getAttribute("cy"));
        switch (event.keyCode)
        {
            case 119:
            y--;
            y = y.toString();
            svg.getElementsByTagName("circle").setAttribute("cy",y);
            break;
            case 115:
            y++;
            y = y.toString();
            svg.getElementsByTagName("circle").setAttribute("cy",y);
            break;
            case 97:
            x--;
            x = x.toString();
            svg.getElementsByTagName("circle").setAttribute("cx",x);
            break;
            case 100:
            x++;
            x = x.toString();
            svg.getElementsByTagName("circle").setAttribute("cx",x);
            break;
            default:
        }
    }
    ]]>
</script>
<rect x="0" y="0" height="500" width="500" style="stroke-width:1; stroke:black; fill:white"></rect>
<circle cx="250" cy="250" r="50" stroke="red" stroke-width="1" fill="red"></circle>
</svg>
Run Code Online (Sandbox Code Playgroud)

它应该有一个与wasd一起移动的球,但球不会移动.我究竟做错了什么?

Phr*_*ogz 61

这是我写的一个工作版本:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <circle cx="250" cy="250" r="50" fill="red" />
  <script type="text/javascript"><![CDATA[
    var KEY = { w:87, a:65, s:83, d:68 };
    var moveSpeed = 5;
    var circle = document.getElementsByTagName("circle")[0];
    var x = circle.getAttribute('cx')*1,
        y = circle.getAttribute('cy')*1;
    document.documentElement.addEventListener('keydown',function(evt){
      switch (evt.keyCode){
        case KEY.w:
          circle.setAttribute('cy',y-=moveSpeed);
          // Alternatively:
          // circle.cy.baseVal.value = (y-=moveSpeed);
        break;
        case KEY.s:
          circle.setAttribute('cy',y+=moveSpeed);
        break;
        case KEY.a:
          circle.setAttribute('cx',x-=moveSpeed);
        break;
        case KEY.d:
          circle.setAttribute('cx',x+=moveSpeed);
        break;
      }
    },false);
  ]]></script>
</svg>
Run Code Online (Sandbox Code Playgroud)

一些说明:

  1. 不要一次又一次地重新获得对圆圈的引用.使代码DRY使其更加健壮,减少键入,并且(在这种情况下)执行速度更快.

    编辑:如果根据上面的代码你无法弄清楚如何做到这一点,发布任何不适合你的代码.

  2. 不要依赖于全球event对象; 这是旧的IE废话.使用传递给事件处理程序的事件对象.

    编辑:如果您event在代码中引用没有参数或本地变量的名称,则假设将存在全局event对象集.相反,请参阅我为您编写的代码,该代码显示事件处理程序是传递给event对象的.通过给出一个名称,例如我给它命名evt,您将收到一个特定于您的事件处理程序的事件对象.

  3. 既然你正在修改xy变量,就没有必要重新获得cxcy属性,每按一次键.

    编辑:在您的原始代码和您接受的答案中,您已var x在事件处理程序之外声明,并且您x = ...在事件处理程序的开头,然后x++在其中一个事件处理程序中.您可以重新获取x每次的当前值(正如您所做的那样)然后setAttribute(...,x+1),或者(就像我一样)您只能在事件处理程序之前获取属性的值一次,然后假设每次都是正确的值你处理关键事件.

  4. 不要将JavaScript事件处理程序放在元素上,以编程方式附加它们.

    编辑:在您的SVG标记中,您有:<svg ... onkeypress="move()">.将您的行为与标记混合在HTML中是一个非常糟糕的主意,而SVG中的一个坏主意.而不是使用onfoo="..."属性来描述在元素上发生事件时应该发生什么,而是使用addEventListner()通过代码附加事件处理程序,而不编辑SVG标记.

  5. 在将数字设置为属性之前,无需将数字强制转换为字符串.

  6. keydown我上面,而不是提供的ASCII事件代码keypress你正在使用和奇数,如果你希望它在所有的浏览器.

    编辑:您在另一篇帖子中抱怨您无法执行此操作,因为您希望在按住键时重复处理事件处理程序.请注意,我在Chrome,Safari,Firefox和IE中的示例代码可以实现您想要的行为(我没有要测试的Opera).换句话说keydown,尽管你认为应该按照你的想法行事.

编辑2:如果要在文档顶部包含脚本块,则必须先创建所有元素,然后执行以下操作:

<svg ...>
  <script type="text/javascript">
    window.addEventListener('load',function(){
      var circle = ...;
      document.rootElement.addEventListener('keydown',function(evt){
        ...
      },false);
    },false);
  </script>
  ...
</svg>
Run Code Online (Sandbox Code Playgroud)

外部函数仅在页面加载后才会运行,因此您可以确保存在元素以引用它们.