使用 SVG 创建动画加载图像
创建一个动画 SVG 作为加载图像。
引言
多年来,当应用程序或程序执行需要几毫秒以上时间的操作时,为用户提供动画“加载中”或“正在处理”图像已成为标准做法。
例如

或
对于我们 Web 环境来说,这种做法带来了一点挑战,因为我们只能通过制作动画 GIF 图像来实现。如果你是一名程序员而不是图形设计师,这可能会非常困难。由于我们最喜欢的图形软件(Photoshop)不支持制作动画 GIF,这项任务也变得更加复杂。事实上,找到合适的 GIF 动画制作工具本身就是一个挑战。此外,GIF 支持的颜色数量非常有限,因此制作一个美观的加载图像几乎是不可能的。幸运的是,HTML5 的发明消除了所有这些担忧。
HTML5 引入了多种无需花费数小时制作大量 GIF 图像即可向用户呈现动画加载图像的方法。特别是,HTML5 提供了 canvas 和 SVG。在花费几个小时研究动画 GIF、Canvas 和 SVG 之间的区别后,我决定使用 SVG 为我所有的网页创建可按需使用的加载图像。
为什么选择 SVG
在动画 GIF、Canvas 和 SVG 之间,GIF 的性能最差。它需要最多的 CPU 使用量。此外,你受到颜色限制,并且缺乏合适的软件。Canvas 和 SVG 之间的性能差异很小。然而,Canvas 需要更多的代码来完成动画。例如,对于动画的每一帧,Canvas 必须被清除,然后整个图像必须被重新绘制。另一方面,SVG 只需要根据每一帧的需要更改其内部元素。这可以用更少的代码完成。最后,正如我们所知,SVG 是可缩放的,这意味着可以轻松地调整现有动画 SVG 的大小,以适应不同的应用程序。这就是我选择 SVG 的原因。
加载图像
为了简化操作,我首先创建了我的 SVG 图像
<svg id="loadingImg1" width="100" height="100">Loading...
<circle cx="80" cy="50" r="5" fill="#000080"/>
<circle cx="74" cy="32" r="5" fill="rgba(0,0,180,0.8)"/>
<circle cx="59" cy="21" r="5" fill="rgba(0,0,180,0.6)"/>
<circle cx="40" cy="21" r="5" fill="rgba(0,0,180,0.4)"/>
<circle cx="26" cy="32" r="5" fill="rgba(0,0,180,0.2)"/>
</svg>
通过将图像元素放置在标记内,而不是动态添加它们,可以提高代码的速度并使其更具可重用性。
然后,为了保持可重用性,我为我的 SVG 编写了一个包装器,该包装器将在加载下一帧时引发一个事件。
//svg: the object reference to the svg element
//frames: the number of frames in the animated image
//delay: the time (in milliseconds) between each frame
function AnimatedImg(svg, frames, delay) {
/****some code omitted for brevity****/
//if onnextframe is assigned to a function it will be called periodically as determined by the frames variable
this.onnextframe = null;
//the elements of that make up the SVG
this.elements = new Array(0);
//currentFrame ranges from 1 to the number given by frames
this.currentFrame = 1;
this.isAnimated = function (){}
this.startAnimation = function () {}
this.stopAnimation = function () {}
}
//frames not given because AnimatedImg assigns default 10
//delay not given because AnimatedImg assigns default 100
var loadingImg1 = new AnimatedImg(document.getElementById("loadingImg1"));
有关 AnimatedImg
函数的完整定义,请参阅 源代码。 如源代码所示,AnimatedImg
可用于在单个页面上动画化多个 SVG,并且可用于任何 SVG,无论其内部结构如何。要在你自己的项目中将其用于,请通过 NuGet 下载它(关键是 AnimatedImg
)。
下一步是定义所有魔术发生的地方的函数,并将其分配给 AnimatedImg
的 onnextframe
事件。然后,每 100 毫秒将调用此函数。它使用 AnimatedImg
的 currentFrame
属性来确定要显示的帧,以及 SVG 的每个元素的位置。
loadingImg1.onnextframe = animateLoadingImg;
function animateLoadingImg(){
for(var l_1 = 0;l_1<this.elements.length;l_1++)
{
this.elements[l_1].setAttribute("cx",
getX(30,(Math.PI/5*this.currentFrame)-(Math.PI/5)*l_1)+50);
this.elements[l_1].setAttribute("cy",
getY(30,Math.PI/5*this.currentFrame)-(Math.PI/5)*l_1)+50);
}
}
function getX(radius,angle){
return Math.cos(angle)*radius;
}
function getY(radius,angle){
return Math.sin(angle)*radius;
}
最后一步是调用 startAnimation
方法来动画化 SVG,并调用 stopAnimation
方法来停止动画。
//start animation and display svg loadingImg1.startAnimation(); //stop animation and hide svg loadingImg1.stopAnimation();