作者 · 2009年1月15日
本文翻译自
当我在2000-2001年{dy}次见到 SVG 时,我被其简单的语法和强大的功能所折服。但当我知道因为浏览器不支持 SVG 而无法使用时非常失望。现在所有的主流浏览器都在一定程度上支持 SVG (微软 IE 除外)。我们现在可以在网站中使用 SVG ,但是 Flash 仍是{zlx}的矢量图格式。为什么?因为很少的开发者会使用 SVG ,大部分开发者都更熟悉 JavaScript (或 ActionScript)。
为了解决兼容性问题和减轻开发者学习负担,我创建了Raphaël。这个 JavaScript 库提供了操作 SVG 的 API ,并提供了 SVG 的 Internet Explorer 支持。后者通过在 IE 中使用 VML 模拟 SVG 实现。使用此库不需要你懂 SVG 语言,尽管了解 SVG 肯定有所帮助。我建议你在有空时不妨了解一下 SVG 基本知识。
让我们从一个简单的例子开始——让我们创建一个典型的")",其{dy}次出现在 Apple 用户界面中,许多其他软件也模仿使用。其通常和 Ajax 配合使用,或和服务器端复杂计算逻辑配合使用。活动指示器效果如图1所示:
图 1:典型的活动指示器
让我们不使用任何图像而只通过 Raphaël 使用 SVG 创建一个活动指示器。
HTML 代码
本例子的 HTML 代码非常简单(中的 spinner.html 文件):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Spinner</title>
<script src="raphael.js" type="text/javascript" charset="utf-8"></script>
<script src="spinner.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="holder"></div>
</body>
</html>
body
中的 div
包含我们的指示器。通过 head
部分中的 script
元素引用了外部脚本文件 raphael.js
和 spinner.js
。raphael.js
是库文件,spinner.js
是自定义脚本,下面会详细介绍 spinner.js
。
我喜欢在 HTML 中为图形创建容器元素,因为这便于 CSS 控制。读者可以自行设置 CSS 属性以美化界面。
代码
下面来看看 spinner.js
文件:
window.onload = function () {
var r = Raphael("holder", 600, 600),
sectorsCount = 12, // number of dashes in spinner
color = "#000", // throbber colour
width = 15, // width of the dashes
r1 = 35, // inner radius of the spinner
r2 = 60, // outer radius of the spinner
cx = 300, // x and y of the centre of the spinner
cy = 300,
本脚本函数被放置在 window.onload
事件处理器中。首先创建了几个变量,大部分的变量用处显而易见 (或见注释);r
是 Raphaël 类的实例,位于 "holder" div
中,且其大小为 600 x 600像素。
接下来的 spinner.js
:
sectors = [], // array for dashes
opacity = [], // array for the opacity of the dashes
beta = 2 * Math.PI / sectorsCount, // angle between dashes
这里我们定义了两个数组以帮助管理短线和保存短线的角度,这样就避免了重复计算。
pathParams = {stroke: color, "stroke-width": width, "stroke-linecap": "round"};
上一个变量保存每根短线的属性:线条颜色、线条宽度和线条端点。下面让我们来看看最核心的代码:
for (var i = 0; i < sectorsCount; i++) {
var alpha = beta * i - Math.PI / 2, // angle between current dash and initial state
cos = Math.cos(alpha),
sin = Math.sin(alpha);
opacity[i] = 1 / sectorsCount * i; // initial opacity for current dash
sectors[i] = r.path(pathParams) // new path in Raphaël
.moveTo(cx + r1 * cos, cy + r1 * sin) // move to point on inner radius
.lineTo(cx + r2 * cos, cy + r2 * sin); // line to point on outer radius
}
在循环内部计算了所有将要显示的短线。根据设置的短线数目计算每根短线的角度和不透明度——不透明度从1至0逐渐降低。{zh1}在 sectors
数组中添加新建的路径( path)。此例中这很简单——路径即为从内圆到外圆的一段线段。上面代码效果如图 2所示。
图 2:创建了短线,下面需要添加动画和透明度
不透明度被保存在数组中,但尚未用于短线。下面让我们来给指示器添加动画:
(function ticker() {
opacity.unshift(opacity.pop());
for (var i = 0; i < sectorsCount; i++) {
sectors[i].attr("opacity", opacity[i]); // set new opacity attribute
}
r.safari(); // temporary (hopefully) fix for Safari
setTimeout(ticker, 1000 / sectorsCount);
})();
上面的代码中创建了一个 ticker
名为的函数。{dy}行代码移动 opacity 数组中的值。然后遍历 sectors
数组中的短线为每一根设置 opacity
属性。不停的重复上述步骤即创建了动画。r.safari();
修正了 Safari 中的部分 bug。
在上面函数{zh1}我们设置了timeout
以使函数在间隔一段时间后重新运行,产生指示器连续转动的效果。此指示器将永远不停的转动。
剩下的就是结束此函数定义:
};
完整代码如下所示:
window.onload = function () {
var r = Raphael("holder", 600, 600),
sectorsCount = 12,
color = "#000",
width = 15,
r1 = 35,
r2 = 60,
cx = 300,
cy = 300,
sectors = [],
opacity = [],
beta = 2 * Math.PI / sectorsCount,
pathParams = {stroke: color, "stroke-width": width, "stroke-linecap": "round"};
for (var i = 0; i < sectorsCount; i++) {
var alpha = beta * i - Math.PI / 2,
cos = Math.cos(alpha),
sin = Math.sin(alpha);
opacity[i] = 1 / sectorsCount * i;
sectors[i] = r.path(pathParams)//.attr("stroke", Raphael.getColor())
.moveTo(cx + r1 * cos, cy + r1 * sin)
.lineTo(cx + r2 * cos, cy + r2 * sin);
}
(function ticker() {
opacity.unshift(opacity.pop());
for (var i = 0; i < sectorsCount; i++) {
sectors[i].attr("opacity", opacity[i]);
}
r.safari();
setTimeout(ticker, 1000 / sectorsCount);
})();
};
上面的代码很简洁。上面代码的一个优点是可以随意修改前景和背景颜色 (可以通过更改 color
变量修改前景颜色;直接修改 HTML 代码即可修改背景颜色);活动指示器是透明的,你可以把它置于任何其他内容之上。作为额外惊喜可以放开被注释的代码看看效果。。
产生相同的效果的 SVG 代码如下:
<?xml version="1.0" encoding="utf-8"?>
<!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" xmlns:xlink"http://www.w3.org/1999/xlink">
<g stroke-width="15" stroke-linecap="round" stroke="#000" transform="translate(100, 100)">
<animateTransform attributeName="transform" attributeType="XML" calcMode="discrete"
additive="sum" type="rotate" values="30;60;90;120;150;180;210;240;270;300;330;360"
dur="1s" repeatCount="indefinite"/>
<line x1="0" y1="-35" x2="0" y2="-60"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(30, 0, 0)" opacity=".08"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(60, 0, 0)" opacity=".16"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(90, 0, 0)" opacity=".25"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(120, 0, 0)" opacity=".33"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(150, 0, 0)" opacity=".42"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(180, 0, 0)" opacity=".5"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(210, 0, 0)" opacity=".58"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(240, 0, 0)" opacity=".67"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(270, 0, 0)" opacity=".75"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(300, 0, 0)" opacity=".83"/>
<line x1="0" y1="-35" x2="0" y2="-60" transform="rotate(330, 0, 0)" opacity=".9"/>
</g>
</svg>
所有的参数值都直接写进了 SVG 标记,这将导致无法灵活改变短线数目。上面的 SVG 代码要比 Raphaël JS 版本简单(假设你了解 SVG 语法)。但 SVG 代码的问题是无法在 Internet Explorer 和 Firefox (在写此文时 Firefox 还不支持 SVG 动画)中运行。而 Raphaël 代码可以在所有浏览器中运行。
本文通过例子介绍了如何使用 Raphaël ——我也希望通过本文你能认识到 Raphaël 是个很有用的项目。可以去 查看更多的例子——请随意修改这些例子。