web-dev-qa-db-ja.com

SVGにJavaScriptを含める

JavaScriptをSVGに埋め込むことにより、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>

無駄に動くボールがあるはずですが、ボールは動きません。私は何を間違えていますか?

27
mortalc

これは、私が書いているように動作するバージョンです。

<!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>

いくつかのメモ:

  1. サークルへの参照を何度も再取得しないでください。コードを作成する [〜#〜] dry [〜#〜] を使用すると、コードの堅牢性が向上し、入力が減り、(この場合)実行が高速になります。

    Edit:上記の私のコードでこれを行う方法がわからない場合は、役に立たないコードを投稿してください。

  2. グローバルeventオブジェクトに依存しないでください。それは古いIEナンセンス。イベントハンドラーに渡されたイベントオブジェクトを使用します。

    Edit:コードでeventをその名前のパラメーターまたはローカル変数なしで参照する場合、グローバルeventオブジェクトセット。代わりに、イベントハンドラーにeventオブジェクトが渡されることを示す、私が作成したコードを参照してください。名前にevtという名前を付けたような名前を付けると、イベントハンドラーに固有のイベントオブジェクトを受け取ります。

  3. xおよびy変数を変更しているので、キーを押すたびにcxおよびcy属性を再取得する必要はありません。

    Edit:元のコードと受け入れた回答で、イベントハンドラーの外部でvar xを宣言しており、イベントハンドラーの先頭にx = ...があります、そしてイベントハンドラーのいずれかでx++。毎回xの現在の値を(取得したように)再取得してからsetAttribute(...,x+1)を取得するか、(私が行ったように)属性の値onceイベントハンドラーの前に、キーイベントを処理するたびにこの値が正しいと仮定します。

  4. JavaScriptイベントハンドラーを要素に配置せず、プログラムでアタッチします。

    Edit:SVGマークアップには<svg ... onkeypress="move()">があります。振る舞いをマークアップと混ぜることは、HTMLでは本当に悪い考えであり、SVGでは悪い考えです。 onfoo="..."属性を使用して要素でイベントが発生したときの動作を記述する代わりに、SVGマークアップを編集せずにaddEventListner()を使用してコード経由でイベントハンドラーをアタッチします。

  5. 数値を属性として設定する前に、数値を文字列に強制する必要はありません。

  6. keydownとすべてのブラウザで動作させたい場合に使用した奇数の代わりに、上記で提供したkeypressとASCIIイベントコード)を使用します。

    Edit別の投稿 で、イベントハンドラをキーとして繰り返し処理する必要があるため、これを実行できないと苦情を述べました。押されています。 Chrome、Safari、Firefox、およびIE(テストするためのOperaはありません)のサンプルコードを使用して、目的の動作を実現します。他の単語keydownは、あなたがどのように振る舞うべきだと思っていたとしても、あなたが望むように働きます。

Edit 2:すべての要素が必ず作成される前に、ドキュメントの上部にスクリプトブロックを含める場合は、以下:

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

外部関数はページが読み込まれた後にのみ実行されるため、それらを参照する要素が存在することを確認できます。

61
Phrogz

scriptタグをsvgタグに宣言することにより、スクリプトjsをsvgコードに追加できます。

<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="40px" height="40px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
     ...
  <script type="text/javascript">
        window.addEventListener('load',function(){
        alert('Hi')
        })
    </script>   

</svg>

これはChromeで機能します。 getElementsByTagNameのインデックスを時々作成するなど、いくつかのエラーが発生しました。さらに大きな問題は、onkeypress属性がバインドされていないことでした。

<?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"
>
<script type="text/javascript">
    <![CDATA[

    var x;
    var y;
    function move()
    {
        x = new Number(document.getElementsByTagName("circle")[0].getAttribute("cx"));
        y = new Number (document.getElementsByTagName("circle")[0].getAttribute("cy"));
        switch (event.keyCode)
        {
            case 119:
            y--;
            y = y.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cy",y);
            break;
            case 115:
            y++;
            y = y.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cy",y);
            break;
            case 97:
            x--;
            x = x.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cx",x);
            break;
            case 100:
            x++;
            x = x.toString();
            document.getElementsByTagName("circle")[0].setAttribute("cx",x);
            break;
            default:
        }
    }
    document.documentElement.addEventListener("keypress", move);
    ]]>
</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>
1
Josh Pearce