Включение JavaScript в SVG - PullRequest
       46

Включение JavaScript в SVG

27 голосов
/ 21 марта 2011

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

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

Ответы [ 3 ]

60 голосов
/ 21 марта 2011

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

<!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 делает его более надежным, менее печатным и (в данном случае) более быстрым.

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

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

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

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

    Редактировать : в своем исходном коде и принятом ответе вы объявили 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>

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

1 голос
/ 31 января 2017

Вы можете добавить скрипт js в код SVG, объявив тег скрипта в тег 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>
1 голос
/ 21 марта 2011

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