一、效果展示
动画1
<circle cx="22" cy="10" r="4" fill="black">
<animate attributeName="opacity" from="1" to="0" dur="1s" begin="0.33s" repeatCount="indefinite" />
</circle>
这里设置了 opacity 透明度从 1 到 0,时间是1秒。设置三个圆点的开始时间 begin 依次顺延,重复次数 repeatCount 为无限次,实现三个点的加载动画。
动画2
<rect x="0" y="50" width="100" height="100" fill="rgb(227,102,90)">
<animateTransform
attributeName="transform"
type="rotate"
from="0 50 100"
to="360 50 100"
dur="3s"
repeatCount="indefinite" />
</rect>
为方块 rect 添加 animateTransform 动画,这里设置的是 rotate 角度变换,同样是循环无限次数,需要注意的是 rotate 的值需要设置方块的旋转点,from 后两个参数设定以方块的中心做为旋转点。
动画3
<rect x="0" y="50" width="100" height="100" fill="rgb(227,102,90)">
<animateTransform
attributeName="transform"
type="rotate"
from="0 50 100"
to="360 50 100"
dur="3s"
begin="0s;first.begin+9s"
id="first"
/>
</rect>
设置三个方块依次旋转,除了动画次数设置为indefinite 外,还可以不断重置动画的开始时间;给动画标签定义一个 id 比如:first,后面添加 begin="0s;first.begin+9s",这样开始时间不断的被重置,再搭配给不同方块的时间差,实现三个方块依次转动。
动画4
<defs>
<path id="motionPath1" d="M50,50 L150,50 L150,150 L50,150 L50,50" />
<path id="motionPath2" d="M150,150 L50,150 L50,50 L150,50 L150,150" />
</defs>
声明两个方块路径,这里就是简单的起点为对角线,path 一致的两个路径,实现路径动画。
<circle cx="0" cy="0" r="12" fill="rgb(94,191,90)">
<animateMotion
dur="4s"
repeatCount="indefinite"
rotate="auto">
<mpath xlink:href="#motionPath1" />
</animateMotion>
</circle>
通过 mpath xlink:href="#motionPath1" 为圆点规划路径。这里需要注意的是,设置路径需要在最外层 svg 标签里添加 xmlns:xlink 这个命名空间标识
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>
动画5
动画6
动画7
动画8
<defs>
<path id="motionPath1" d="M50,100 m -50,0 a 50 50 0 1 1 100 0"/>
<path id="motionPath2" d="M150,100 m -50,0 a 50 50 0 1 0 100 0"/>
<path id="motionPath3" d="M150,100 m 50,0 a 50 50 0 1 0 -100 0"/>
<path id="motionPath4" d="M50,100 m 50,0 a 50 50 0 1 1 -100 0"/>
</defs>
这里定义四个半圆的路径,这里需要注意下绘制的方向:顺时针、逆时针,配合时间差完成“绕8”的动画行为。
动画9
分解图片平滑过渡
class SmallRect {
allCopies = [];
pathId = "";
duration = 5;
constructor(pathId, duration = 5) {
this.pathId = pathId;
this.duration = duration;
}
parseImage(filePath) {
const svgNS = "http://www.w3.org/2000/svg";
const svg = document.getElementById("svg");
const img = new Image();
img.src = filePath;
img.onload = () => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// 获取图片像素数据
const imageData = ctx.getImageData(0, 0, img.width, img.height);
const data = imageData.data;
// 遍历像素点并生成矩形
const step = 1; // 每隔 1 个像素取一个点
// 横向分段
const copies = img.width / step;
for (let i = 0; i < copies; i++) {
const g = document.createElementNS(svgNS, "g");
g.setAttribute("id", this.pathId + "G" + i);
this.allCopies.push(new SmallRectPosition(g));
svg.appendChild(g);
}
// 操作像素
for (let y = 0; y < img.height; y += step) {
for (let x = 0; x < img.width; x += step) {
const index = (y * img.width + x) * 4;
const r = data[index];
const g = data[index + 1];
const b = data[index + 2];
const a = data[index + 3] / 255;
// 创建矩形
const rect = document.createElementNS(svgNS, "rect");
rect.setAttribute("x", 0);
rect.setAttribute("y", -(img.height / 2.0) + y);
rect.setAttribute("width", step);
rect.setAttribute("height", step);
rect.setAttribute("fill", `rgba(${r},${g},${b},${a})`);
const copiesIndex = x % img.width;
this.allCopies[copiesIndex].g.appendChild(rect);
}
}
// 计算路径长度
const path = document.getElementById(this.pathId);
const pathLength = path.getTotalLength();
// 计算延迟时间
const delay = this.duration / pathLength;
// 添加动画
this.allCopies.forEach((position, index) => {
const lastCopiesG = this.allCopies[this.allCopies.length - 1];
// 创建 animateMotion 元素
const animateMotion = document.createElementNS(
svgNS,
"animateMotion"
);
animateMotion.setAttribute("dur", this.duration);
animateMotion.setAttribute("begin", delay * index + "s");
animateMotion.setAttribute("repeatCount", "indefinite");
animateMotion.setAttribute("rotate", "auto");
animateMotion.setAttributeNS(
"http://www.w3.org/1999/xlink",
"xlink:href",
"#" + this.pathId + "G" + index
);
// 创建 mpath 元素并引用路径
const mpath = document.createElementNS(svgNS, "mpath");
mpath.setAttributeNS(
"http://www.w3.org/1999/xlink",
"xlink:href",
"#" + this.pathId
);
animateMotion.appendChild(mpath);
svg.appendChild(animateMotion);
});
};
}
});
}
}
二、思考与总结
动画都比较简单,但它或许能为开发场景打开一个新的思路。