我正在尝试使用SVG和CSS动画制作一些不断增长的线条动画。由于这些行的长度分别不同,因此我使用pathLength
为它们分配虚拟长度。因此,我只能对它们全部使用一个@keyframe
。
这是示例代码
<svg width="1000px" height="100px">
<g stroke="#FAB" stroke-width="3">
<line id="Line1" x1="20", y1="20", x2="520", y2="20" pathLength="1000"/>
<line id="Line2" x1="20", y1="50", x2="780", y2="50" pathLength="1000"/>
</g>
</svg>
<style>
line {
animation-name: line-grow;
animation-duration: 3s;
animation-iteration-count: infinite;
}
@keyframes line-grow {
from {
stroke-dasharray: 0, 1000;
}
to {
stroke-dasharray: 1000, 1000;
}
}
</style>
此技巧适用于Chrome和Firefox,但不适用于Safari。 在所有这些浏览器上还有其他技巧可以使用吗?还是我可以在Safari上应用此技巧?
我console.log
和pathLength
使用JS,但确实在Safari中返回了一些内容。
答案 0 :(得分:0)
我暂时使用了一种解决方法。这不是一个漂亮的方法,但我认为至少它仍然是一种干净的方法。这是面对同样问题的人的参考。
我使用JavaScript动态计算行的每个长度,生成一些CSS消息,然后插入window.stylesheet
。请注意,这些操作应在window.onload
之后进行。
这是示例代码:
window.onload = setPathAnimationAll;
var seqAnimate = ["l-vertical", "l-horizen", "l-hypo"];
function setPathAnimationAll() {
for(var i = 0; i < seqAnimate.length; ++i) {
setPathAnimationSingle(seqAnimate[i]);
}
}
function setPathAnimationSingle(id){
var target = document.getElementById(id);
var nameAnimete = genAnimateName(id);
var msgCss = genPathAnimateMsg(nameAnimete, getSvgLineLength(target));
insertCss(msgCss);
target.style.animationName = nameAnimete;
}
function getSvgLineLength(ele)
{
return Math.sqrt(Math.pow(ele.x1.animVal.value - ele.x2.animVal.value, 2) + Math.pow(ele.y1.animVal.value - ele.y2.animVal.value, 2));
}
function genAnimateName(id) {
return "dynamic-animation-" + id;
}
function genPathAnimateMsg(name, length){
return "@keyframes " + name +" { from { stroke-dasharray: 0, " + length + "; } to { stroke-dasharray: " + length + "; }}" + "\n";
}
function insertCss(msg) {
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '';
document.getElementsByTagName('head')[0].appendChild(style);
window.stylesheet = document.styleSheets[document.styleSheets.length - 1];
window.stylesheet.insertRule(msg, window.stylesheet.cssRules.length);
}
svg line {
//animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-duration: 1s;
}
<svg width="400px" height="200px" viewBox="0 0 400 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="#FABE00" stroke-width="3">
<line x1="301" y1="0" x2="301" y2="183" id="l-vertical"></line>
<line x1="301" y1="183" x2="120" y2="183" id="l-horizen"></line>
<line x1="120" y1="183" x2="301" y2="0" id="l-hypo"></line>
</g>
</svg>
答案 1 :(得分:0)
解决方案1:
最后,我仅使用css变量在css中找到了解决方案。唯一的缺点是,已将此css变量提供给每个笔画的实际路径长度(使用任何一种脚本语言创建笔画时,只能计算一次)。在svg中,on将pathLength="1000"
替换为style="--L:nnn"
,其中--L
是一个css变量,nnn是路径的实际长度:
<svg width="1000px" height="100px">
<g stroke="#FAB" stroke-width="3">
<line style="--L:500;" id="Line1" x1="20" y1="20" x2="520" y2="20"/>
<line style="--L:760;" id="Line2" x1="20" y1="50" x2="780" y2="50"/>
</g>
</svg>
在CSS中,使用--L
代码中的@keyframes
变量:
line {
animation-name: line-grow;
animation-duration: 3s;
animation-iteration-count: infinite;
}
@keyframes line-grow {
from {
stroke-dasharray: 0 var(--L);
}
to {
stroke-dasharray: var(--L) var(--L);
}
}
解决方案2:
如果不能或不希望预先计算每个笔画的路径长度,则下面是使用简短的javascript代码即时完成工作的解决方案。
css:
@keyframes line-grow {
from {
stroke-dasharray: 0 var(--L);
}
to {
stroke-dasharray: var(--L) var(--L);
}
}
svg:
<svg width="1000px" height="100px">
<g stroke="#FAB" stroke-width="3">
<line id="Line1" x1="20" y1="20" x2="520" y2="20"/>
<line id="Line2" x1="20" y1="50" x2="780" y2="50"/>
</g>
</svg>
javascript:
function magic()
{
var list, k, style;
list = document.querySelectorAll("line");
for (k=0; k<list.length; k++)
{
style = "--L:" + list[k].getTotalLength() + ";";
style += "animation: line-grow 3s infinite;";
list[k].setAttribute("style", style);
}
}
window.addEventListener("load", magic, false);
解决方案3:
为便于记录,以下是与Cigany解决方案类似的以前的解决方案,但是使用getTotalLength()
方法来计算线长(因此,可以轻松地计算任何类型的路径的长度,包括那些包含贝塞尔曲线)。
只需在页面末尾添加一个脚本(javascript),即可对每一行执行操作:
getTotalLength()
pathLength
属性(以使知道如何使用此属性的浏览器正常工作)代码可以是:
function setKeyframes(name, len)
{
// add a specific keyframes for each line using its length
// to the style of the page
var a, e = document.createElement("style");
a = "@keyframes " + name + " {";
a += "from {stroke-dasharray: 0, " + len + ";}";
a += "to {stroke-dasharray: " + len + ", " + len + ";}";
a += "}";
e.type = 'text/css';
if (e.styleSheet) e.styleSheet.cssText = a;
else e.appendChild(document.createTextNode(a));
document.getElementsByTagName('head')[0].appendChild(e);
}
function magic()
{
// does the job for each line
var list, k, name, len;
// adapt the following instruction
// if all the lines of the document are not concerned
list = document.querySelectorAll("line");
for (k=0; k<list.length; k++)
{
name = "line-grow-" + k;
len = list[k].getTotalLength();
setKeyframes(name, len);
list[k].style.animationName = name;
list[k].setAttribute("pathLength", len);
}
}
window.addEventListener("load", magic, false);