SVG元素是一种特殊的DOM元素,可以使用CSS以及一般的JS类库来实现动画控制。但是这些方法都没提供SVG动画样式属性的完整控制,现在介绍一个专门的SVG动画类库Snap.svg,其github地址为: https://github.com/adobe-webplatform/Snap.svg
Snap.svg提供多种安装方式。
HTML直接加载JS方式
<script src="snap.svg-min.js"></script>
// Manual Minified - https://github.com/adobe-webplatform/Snap.svg/raw/master/dist/snap.svg-min.js
// Manual Unminified - https://raw.githubusercontent.com/adobe-webplatform/Snap.svg/master/dist/snap.svg.js
//注意:上面url直接添加到src无法正常下载
//错误信息:Refused to execute script from 'https://.../snap.svg-min.js' because its MIME type ('text/plain') is not executable.
//是服务端返回类型错误,浏览器无法解析。可以手工下载到本地使用。
webpack加载方式
// 支持npm或者bower下载
bower install snap.svg
npm install snapsvg
// webpack配置
module: {
rules: [
test: require.resolve('snapsvg/dist/snap.svg.js'),
use: 'imports-loader?this=>window,fix=>module.exports=0',
resolve: {
alias: {
snapsvg: 'snapsvg/dist/snap.svg.js',
// 引用
import Snap from 'snapsvg';
Snap.svg动画基本实现步骤
// 1、在HTML中添加SVG
<svg id="demo1" width="300" height="300"></svg>
// 2、SVG中图形元素初始化
let svg = Snap('#demo1');
let circle = svg.select('.circle'); //如果SVG中已有实际图形元素,直接选择器初始化
let circle = svg.circle(150, 150, 10);//如果SVG中没有实际图形元素,调用方法创建化
// 3、修改属性和时间参数,实现动画设置。例如一秒钟内,圆半径变为100px
circle.animate({ r: 100 }, 1000, mina.easeout(), () => {
//动画结束,doSomething
Snap.svg常用API介绍
Snap(...)
功能描述: 创建或加载已有的SVG元素。
参数说明:
返回值: 新建的rect元素Element
Snap.animation(attr, duration, [easing], [callback])
功能描述: 在一段时间内匀速变更相关属性到目标值。
参数说明:
返回值: 动画对象
Snap.animate(from, to, setter, duration, [easing], [callback])
功能描述: 根据设置的参数,执行动画操作。
参数说明:
初始化参考上面“基本实现步骤”中的相关描述,后续只描述动画控制部分。
// 圆形半径缩放,在1S内半径从10,放大到100,动画效果是缓出
let circle = svg.circle(150, 150, 10);
circle.animate({ r: 100 }, 1000, mina.easeout(), () => {
//动画结束,doSomething
// 矩形长宽缩放,在2S内宽度100缩小到10,长度200缩小到20,动画效果是缓入
let rect = svg.circle(0, 0, 100, 200);
rect.animate({ width: 10, height:20 }, 2000, mina.easein(), () => {
//动画结束,doSomething
// 圆形填充色渐变,3S内从绿色变成蓝色,动画效果是缓出
let circle = svg.circle(150, 150, 100).attr({
fill: "#bada55",
stroke: "#000",
strokeWidth: 5
circle.animate({ fill: "#0059b3", }, 3000, mina.easeout(), () => {
//动画结束,doSomething
// 1S内线条从起始态变换到终止态,动画效果是缓出
// 起始态:任意形状
let path = svg.paper.path({d: 'M0.500,65.500 C18.680,33.758 45.141,-6.797 72.500,2.500 C99.859,11.797 72.148,59.027 79.500,98.500 C86.852,137.973 117.668,128.914 138.500,59.500 C159.332,-9.914 246.500,59.500 246.500,59.500 C273.181,117.750 137.350,184.417 225.500,173.500 C351.137,157.940 155.369,160.617 162.500,86.500 C165.180,58.645 237.169,-2.418 283.500,2.500 C357.654,10.371 363.758,80.355 364.500,109.500',stroke:'#f00', fill: 'rgba(0,0,0,0)'});
// 终止态:心形
path.animate({d: 'M114.500,58.500 C106.230,58.751 23.907,-37.262 5.500,21.500 C-26.759,124.483 111.761,221.360 119.500,219.500 C154.464,211.096 201.234,149.580 220.500,104.500 C250.260,34.864 220.892,7.159 194.500,1.500 C160.455,-5.800 122.344,58.262 114.500,58.500 Z'}, 1000, mina.easeout(), () => {
//动画结束,doSomething
// 1S内矩形移动100次,从(0,0)移动到(100,200),动画效果是缓出
let rect = svg.paper.rect({x: 0, y: 0, width: 50, height: 30, fill: '#f00'});
Snap.animate(0, 100, (val) => {
let m = new Snap.Matrix();
m.translate(val, val * 2); // translate位移API
rect.transform(m); // 在rect节点应用matrix
}, 1000, mina.easeout(), () => {
//动画结束,doSomething
// 1S内矩形围绕矩形的中心旋转100次,完成旋转一周,动画效果是缓出
let rect = svg.paper.rect({x: 10, y: 10, width: 50, height: 30, fill: '#f00'});
Snap.animate(0, 100, (val) => {
let m = new Snap.Matrix();
m.rotate((val/100)*360, 35, 25); // 注意,旋转中心是矩形的中心
rect.transform(m); // 在rect节点应用matrix
}, 1000, mina.easeout(), () => {
//动画结束,doSomething