更多的 ECMAScript 操纵
有时候,无论控制独立的 SVG 或者 XHTML 中的 SVG,仅仅操纵类值还不够。幸运的是,通过脚本基本上能实现任何需要的功能。这一节介绍用于 SVG 的更棘手的脚本操作。
直接修改样式细节
利用 CSS 属性操作的 CSS DOM 绑定,可以根据需要调整对象的外观。清单 9(tutorial-files.zip 中的 eg_3_1.svg)中的 SVG 文件画了一个圆,每点击它一次颜色都会变得更深:
清单 9. 点击变红的 SVG 圆
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" baseProfile="full"
xmlns="http://www./2000/svg">
<title>SVG circle that responds to clicks
by turning redder</title>
<defs>
<style type="text/css"><![CDATA[
#target { fill: black; }
]]></style>
<script type="application/javascript"><![CDATA[
var redness = 0;
function redden()
{
var target;
target = document.getElementById('target');
if ( ( redness <= 255 ) ) {
redness += 32;
target.style.setProperty("fill",
"rgb(" + redness + ",0,0)", "important");
}
}
]]></script>
</defs>
<circle id="target" onclick="redden()" cx="3cm"
cy="3cm" r="2cm"/>
</svg>
|
使用 setProperty
方法设置 CSS 样式属性的值。在这里,fill
属性被设置成 RBG 颜色值,标准 CSS/DOM 形式的字符串 —— rgb(255,255,255)
对应白色,改变数字就能改变颜色。清单 9 中绿色和蓝色分量总是 0,因为我们只想改变圆的红色分量。第三个参数决定了样式表修改的优先级。基本上使用的总是 important
。
在浏览器中加载 清单 9。初始显示结果如图 7 所示。反复单击圆可以看到它的颜色从黑慢慢变红。在这个事件处理程序中尝试修改其他样式属性。
图 7. 清单 9 在浏览器中的输出结果
回页首
操纵其他 SVG 属性
上一期教程(请参阅 参考资料)中提到,SVG 使用 XML 属性作为图形的基本属性,比如位置和大小。清单 10(tutorial-files.zip 中的 eg_3_2.svg)中的 SVG 文件画了两个圆,点击的时候会不断变大:
清单 10. 点击变大的 SVG 圆
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" baseProfile="full"
xmlns="http://www./2000/svg">
<title>SVG circle that gets larger when clicked</title>
<defs>
<style type="text/css"><![CDATA[
#touchable circle.left { fill: orange; }
#touchable circle.right { fill: lime; }
]]></style>
<script type="application/javascript"><![CDATA[
var size = 2;
function grow(evt)
{
var target;
target = evt.target;
size += 0.25;
target.setAttribute('r', size+'cm');
}
]]></script>
</defs>
<g id="touchable">
<circle class="left" onclick="grow(evt)"
cx="3cm" cy="3cm" r="2cm"/>
<circle class="right" onclick="grow(evt)"
cx="3cm" cy="3cm" r="2cm" transform="translate(200,0)"/>
</g>
</svg>
|
脚本维护一个全局变量 size
。但是两个圆不是独立变大的。如果点击其中一个圆几次,然后再单击另一个,后者将直接跳到和前者相同的大小。这是因为两个圆共享脚本中的 size
变量。在事件处理程序中,size 增加了,直接操纵 r
属性改变圆的半径。在浏览器中加载 清单 10。初始显示结果如图 8 所示。反复单击两个圆可以看到它们不断变大。
图 8. 清单 10 在浏览器中的显示结果
回页首
动态变换
SVG 变换是精确控制对象外观和位置的关键,在通过脚本操纵对象时同样有用。清单 11(tutorial-files.zip 中的 eg_3_3.svg)中的 SVG 文件画了一个圆,单击的时候会移动到右侧。
清单 11. 点击滑动的 SVG 圆
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" baseProfile="full"
xmlns="http://www./2000/svg">
<title>SVG circle that slides to the right when clicked</title>
<defs>
<style type="text/css"><![CDATA[
circle { fill: orange; }
]]></style>
<script type="application/javascript"><![CDATA[
var x = 0;
function move(evt)
{
var target;
target = evt.target;
x += 25;
target.setAttribute('transform', 'translate(' + x + ',0)');
}
]]></script>
</defs>
<circle onclick="move(evt)" cx="3cm" cy="3cm" r="2cm"/>
</svg>
|
这与前面看到的 DOM 属性操作非常类似。可以在 transform
属性中使用专门的类似函数的符号来表示变换,如旋转、移位、缩放和扭曲。还可以指定完整的变换矩阵。在浏览器中加载 清单 11。最初看到的只有一个橙色的圆。反复单击这个圆可以看到它会滑动到右侧。
回页首
创建对象
除了操纵已有的对象外,还可以使用脚本创建新的对象。我们可以在独立 SVG 中用脚本创建对象,但是稍加阐述后即回到 XHTML 中内嵌的 SVG。清单 12(tutorial-files.zip 中的 eg_3_4.xhtml)中的 XHTML 文件有一个按钮,单击它可以创建圆:
清单 12. 单击按钮在 XHTML 中动态创建圆
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www./TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en"
xmlns="http://www./1999/xhtml"
xmlns:svg="http://www./2000/svg">
<head>
<title>XHTML example for creating circles dynamically
by clicking a button</title>
<style type="text/css"><![CDATA[
circle {
fill: lime;
stroke: black;
stroke-width: 0.2cm;
}
]]></style>
<script type="application/javascript"><![CDATA[
function create_circle()
{
var svg = document.getElementById('diagram');
var cx = Math.random()*10;
var cy = Math.random()*4;
var r = Math.round(Math.random()*4);
circle = document.createElementNS('http://www./2000/svg', 'circle')
circle.setAttribute('cx', cx+'cm')
circle.setAttribute('cy', cy+'cm')
circle.setAttribute('r', r+'cm')
svg.appendChild(circle)
}
]]></script>
</head>
<body>
<svg:svg id='diagram' version="1.1" width="600" height="220">
<svg:title>Create circles dynamically</svg:title>
</svg:svg>
<button onclick="create_circle();">Create circle</button>
</body>
</html>
|
用户单击按钮时会调用 create_circle
函数。该函数首先选择内嵌的 SVG 元素作为要创建的圆形的父元素。该元素包含 id
属性,很容易检索。然后代码使用 ECMAScript 数学库创建圆形的位置和半径。random
函数生成介于 0 和 1 之间的一个随机浮点数,用它乘上最大值。对于半径,还对结果进行舍入以保证圆的大小只能取四个数。然后加上 cm
单位指示符。如果省略,则与通常一样使用默认单位 —— 像素。使用名称空间感知方法 createElementNS
创建圆对象,为新元素指定必要的 SVG 名称空间。剩下的就是设置这些属性了。再回到不支持名称空间的 setAttribute
方法,因为需要的属性不在任何名称空间中。最后,使用前面检索的 svg
父元素将 SVG 对象添加到文档中。
在浏览器中加载 清单 12。最初看到的窗口只有一个按钮,但是如果单击该按钮,就会看到绿色的大小不定的圆出现。要注意,浏览器会根据内嵌 SVG 指定的高和宽剪裁圆。
回页首
创建具有动态行为的对象
按照上一节的方法创建 SVG 对象的时候,没有理由不能创建这些对象自己的动态行为。清单 13(tutorial-files.zip 中的 eg_3_5.xhtml)中的 XHTML 文件有一个按钮,单击它可以创建圆形,而这些圆在单击的时候又会改变自己的边界:
清单 13. 清单 12 的改进版,创建的圆能够响应点击
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www./TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en"
xmlns="http://www./1999/xhtml"
xmlns:svg="http://www./2000/svg">
<head>
<title>Creating SVG objects with event handlers</title>
<style type="text/css"><![CDATA[
circle { fill: orange; }
circle.open {
stroke: none;
}
circle.closed {
stroke: black;
stroke-width: 0.2cm;
}
]]></style>
<script type="application/javascript"><![CDATA[
function create_circle()
{
var svg = document.getElementById('diagram');
var cx = Math.random()*10;
var cy = Math.random()*4;
var r = Math.round(Math.random()*4);
circle = document.createElementNS('http://www./2000/svg', 'circle')
circle.setAttribute('cx', cx+'cm')
circle.setAttribute('cy', cy+'cm')
circle.setAttribute('r', r+'cm')
circle.setAttribute('class', 'open')
svg.appendChild(circle)
//The added line to set up the event handler
circle.addEventListener("click", toggle, false)
}
function toggle(evt)
{
var target;
target = evt.target;
if (target.getAttributeNS('', 'class') == 'closed')
target.setAttributeNS('', 'class', 'open');
else
target.setAttributeNS('', 'class', 'closed');
}
]]></script>
</head>
<body>
<svg:svg id='diagram' version="1.1" width="600" height="220">
<svg:title>Create circles dynamically</svg:title>
</svg:svg>
<button onclick="create_circle();">Create circle</button>
</body>
</html>
|
其中的脚本和样式表大部分前面已经遇到过。其中有一行是新增加的,即使用 addEventListener
为鼠标单击事件建立处理程序 toggle
。在浏览器中加载 清单 13。可以看到与 清单 12 类似的结果,只不过创建的圆形没有边框,用鼠标点击可以增加和消除边界线。
删除对象
自己创建的东西可能还希望自己删除。这一节结尾的清单 14(tutorial-files.zip 中的 eg_3_6.xhtml)类似于 清单 13,但是通过点击可以删除所创建的圆形:
清单 14. 清单 12 的改进版,用户可以删除创建的圆形
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www./TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en"
xmlns="http://www./1999/xhtml"
xmlns:svg="http://www./2000/svg">
<head>
<title>Creating SVG objects with event handlers to trigger removal</title>
<style type="text/css"><![CDATA[
circle {
fill: orange;
stroke: black;
stroke-width: 0.2cm;
}
]]></style>
<script type="application/javascript"><![CDATA[
function create_circle()
{
var svg = document.getElementById('diagram');
var cx = Math.random()*10;
var cy = Math.random()*4;
var r = Math.round(Math.random()*4);
circle = document.createElementNS('http://www./2000/svg', 'circle')
circle.setAttribute('cx', cx+'cm')
circle.setAttribute('cy', cy+'cm')
circle.setAttribute('r', r+'cm')
circle.setAttribute('class', 'open')
svg.appendChild(circle)
circle.addEventListener("click", pop, false)
}
function pop(evt)
{
var target;
target = evt.target;
//The new circle click response: delete the circle element
target.parentNode.removeChild(target);
}
]]></script>
</head>
<body>
<svg:svg id='diagram' version="1.1" width="600" height="220">
<svg:title>Create and pop balloons</svg:title>
</svg:svg>
<button onclick="create_circle();">Make a balloon</button>
<p>(Click a balloon to pop it)</p>
</body>
</html>
|
大部分代码都是熟悉的。主要的变化是为单击事件增加了一个事件处理程序,它使用 parentNode
获得父元素,然后用 removeChild
删除单击的圆。