SVGにJavaScriptを含める 質問する

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>

ボールは WAS で動くはずですが、ボールが動きません。何が間違っているのでしょうか?

ベストアンサー1

以下は私が書いた実際のバージョンです:

svg {
  height: 178px;
  width: 600px;
  border: solid 1px;
}
<!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="100" 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. 円への参照を何度も再取得しないでください。コードを作成するドライより堅牢になり、入力が少なくなり、(この場合は) 実行が速くなります。

編集: 上記のコードでこれを行う方法がわからない場合は、機能しないコードを投稿してください。

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

編集:eventコード内でパラメータやローカル変数を指定せずにその名前で参照する場合、グローバルeventオブジェクトが設定されているものと想定しています。代わりに、イベント ハンドラにオブジェクトが渡されることを示す、私が作成したコードを参照してくださいevent。それに名前を付けると (たとえば、私が という名前を付けるとevt)、イベント ハンドラに固有のイベント オブジェクトを受け取ることになります。

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

編集: 元のコードとあなたが受け入れた回答では、var xイベントハンドラの外で宣言し、x = ...イベントハンドラの先頭で宣言し、x++イベントハンドラの1つで宣言しています。毎回の現在の値を再取得するかx(あなたが行ったように)、setAttribute(...,x+1)または(私が行ったように)属性の値のみを取得できます。一度イベント ハンドラーの前にこの値を設定し、キー イベントを処理するたびにこの値が正しいと想定します。

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

編集: SVG マークアップには次の内容が含まれます。<svg ... onkeypress="move()">動作とマークアップを混在させることは、HTML でも SVG でもよくありません。onfoo="..."要素でイベントが発生したときに何が起こるかを記述するために属性を使用する代わりに、addEventListner()SVG マークアップを編集せずに、コードを介してイベント ハンドラーをアタッチするために を使用します。

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

  2. すべてのブラウザで動作させたい場合は、使用していた と奇数の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>

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

おすすめ記事