在 SVG 中包含 JavaScript
Posted
技术标签:
【中文标题】在 SVG 中包含 JavaScript【英文标题】:Including JavaScript in SVG 【发布时间】:2011-07-19 17:04:19 【问题描述】:我正在尝试通过将 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 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" style="stroke-width:1; stroke:black; fill:white"></rect>
<circle cx="250" cy="250" r="50" stroke="red" stroke- fill="red"></circle>
</svg>
它应该有一个随wasd移动的球,但球没有移动。我做错了什么?
【问题讨论】:
【参考方案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 = ...
,然后是@ 987654335@ 在其中一个事件处理程序中。您可以每次重新获取 x
的当前值(如您所做的那样)然后 setAttribute(...,x+1)
,或者(如我所做的那样)您之前只能获取属性 once 的值事件处理程序,然后假定每次处理关键事件时此值都是正确的。
不要将 JavaScript 事件处理程序放在元素上,以编程方式附加它们。
编辑:在您的 SVG 标记中,您有:<svg ... onkeypress="move()">
。将你的行为与你的标记混合在一起在 html 中是一个非常糟糕的主意,在 SVG 中也是一个糟糕的主意。不要使用onfoo="..."
属性来描述当事件发生在元素上时应该发生的事情,而是使用addEventListner()
通过代码附加事件处理程序,而无需编辑您的SVG 标记。
在将数字设置为属性之前,无需将其强制转换为字符串。
使用keydown
和我在上面提供的ASCII 事件代码,而不是keypress
和您使用的奇数,如果您希望它在所有浏览器中工作。
编辑:您在another post 中抱怨您不能这样做,因为您希望在按住键时重复处理事件处理程序。请注意,您想要的行为是通过我在 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>
外部函数只会在页面加载后运行,因此您可以确定元素存在以引用它们。
【讨论】:
我建议使用 SVG DOM 方法来设置 cx 和 cy,但这看起来是一个很好的解决方案,除了那个小问题。 @Erik 你能提供更多关于你为什么建议的细节吗?无论是使用circle.setAttribute('cy',y)
还是circle.cy.baseVal.value=y
,我都可以在 Chrome 中获得 250fps,在 FF3.6 中获得 100fps。您认为其中一个更快吗?您是否正在考虑与 SMIL 进行一些互动?【参考方案2】:
您可以通过将脚本标签声明为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"
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>
【讨论】:
【参考方案3】:这适用于 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 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" style="stroke-width:1; stroke:black; fill:white"></rect>
<circle cx="250" cy="250" r="50" stroke="red" stroke- fill="red"></circle>
</svg>
【讨论】:
请注意,除非您将第三个参数明确添加到addEventListener
,否则 Firefox 会哭。那样很挑剔。
@mortalc 这个答案在 Firefox 中不起作用,而我的答案是。它还继续使用您的答案中不必要且不可取的代码。
我以前从未听说过 addEventListener!这就是为什么它不起作用!
@mortalc 无意冒犯,但除此之外还有多种原因导致您的代码无法正常工作。
我不能不同意这一点,因为我不知道更好,但我只是说另一个对我有用。只有两件事让我感到困惑。 1)如果我像你在你的那样为 document.getElementsByTagName("circle")[0] 设置一个变量 circle 并使用它而不是每次都获取元素,它不起作用。并且 2) 如果我使用带有矩形的代码,并将 cx 和 cy 替换为 x 和 y,它就不起作用。但是由于某些奇怪的原因,如果我得到 cx 和 cy 但编辑 x 和 y,它会这样做。以上是关于在 SVG 中包含 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章
为啥我们应该在字体中包含 ttf、eot、woff、svg、...