Подтвердить что ты не робот

Включая JavaScript в SVG

Я пытаюсь создать интерактивный SVG-код с 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>

Предполагается, что мяч, который движется с wasd, но мяч не двигается. Что я делаю неправильно?

4b9b3361

Ответ 1

Вот рабочая версия, как я ее написал:

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

Некоторые примечания:

  • Не возвращайте ссылку на круг снова и снова. Создание вашего кода DRY делает его более надежным, менее типизированным и (в этом случае) быстрее выполняется.

    Изменить. Если вы не можете понять, как это сделать, учитывая мой код выше, напишите любой код, который не работает для вас.

  • Не полагайтесь на глобальный объект event; эта старая IE ерунда. Используйте объект события, переданный вашему обработчику событий.

    Изменить. Если вы ссылаетесь на event в своем коде без параметра или локальной переменной этим именем, вы предполагаете, что будет глобальный набор объектов event. Вместо этого см. Код, который я написал для вас, который показывает, что обработчик события передается event. Дав это имя, например, я дал ему имя evt, вы получаете объект события, специфичный для вашего обработчика событий.

  • Поскольку вы изменяете переменные x и y, нет необходимости повторно получать атрибуты cx и cy при каждом нажатии клавиши.

    Изменить. В исходном коде и ответе, который вы приняли, вы объявили var x вне вашего обработчика событий, а у вас есть x = ... в начале обработчика событий, а затем x++ в одном из обработчиков событий. Вы можете либо повторно получать текущее значение x каждый раз (как и вы), а затем setAttribute(...,x+1) или (как и я) вы можете только получить значение атрибута один раз до обработчиков событий, а затем предположить, что это значение является правильным каждый раз, когда вы обрабатываете событие ключа.

  • Не помещайте свои обработчики событий JavaScript на свои элементы, программно их прикрепите.

    Изменить. В вашей разметке SVG у вас есть: <svg ... onkeypress="move()">. Смешение вашего поведения с вашей разметкой - очень плохая идея в HTML и плохая идея в SVG. Вместо использования атрибутов onfoo="..." для описания того, что должно произойти при возникновении события в элементе, вместо этого используйте addEventListner() для присоединения обработчиков событий через код без изменения разметки SVG.

  • Нет необходимости принуждать номера к строкам, прежде чем устанавливать их как атрибуты.

  • Используйте keydown и коды событий ASCII, которые я поставил выше, вместо keypress и нечетные числа, которые вы использовали, если хотите, чтобы он работал во всех браузерах.

    Изменить: вы жаловались на другое сообщение, что вы не можете этого сделать, потому что вы хотите, чтобы обработчик события обрабатывался повторно, поскольку ключ удерживается. Обратите внимание, что ваше желаемое поведение достигается с помощью моего образца кода в браузере Chrome, Safari, Firefox и IE (у меня нет тестирования Opera). Другими словами, keydown работает так, как вы хотели, несмотря на то, как вы думали, что он должен себя вести.

Изменить 2. Если вы хотите добавить блок script в начало документа, прежде чем все элементы обязательно будут созданы, вы можете сделать что-то вроде следующего:

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

Внешняя функция запускается только после загрузки страницы, поэтому вы можете быть уверены, что существуют элементы для их ссылки.

Ответ 2

Это работает в 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>

Ответ 3

вы можете добавить script js в svg-код, объявив тег script в тег 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>