Ответ 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>
Внешняя функция запускается только после загрузки страницы, поэтому вы можете быть уверены, что существуют элементы для их ссылки.