SVG pathLength在Safari中不起作用

时间:2018-08-17 06:27:14

标签: svg safari css-animations

我正在尝试使用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.logpathLength使用JS,但确实在Safari中返回了一些内容。

2 个答案:

答案 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);