【问题标题】:SVG pathLength don't work on safariSVG pathLength 不适用于 safari
【发布时间】:2019-01-24 03:38:18
【问题描述】:

我正在尝试使用 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 中返回了一些东西。

【问题讨论】:

  • 如果您只有水平的&lt;line&gt; 元素,您可以将动画从scale(0, 1) 转换为scale(1, 1)。您需要为每个单独的线设置transform-origin,对于非水平线,在缩放后旋转它们。
  • 这在 safari 中实际上对我有用,虽然动画感觉不同,但线条是动画的
  • @godblessstrawberry 是的,还有动画,但是stroke-dasharray 计算忽略了pathLength。其实这个bug和动画没有直接关系,但是我想用这个特性来实现和你在Chrome中看到的一样的动画效果。

标签: svg safari css-animations


【解决方案1】:

解决方案 #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中,在@keyframes代码中使用--L变量:

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() 方法来计算线长度(因此,可以轻松计算任何类型路径的长度,包括包含 Bézier 的路径曲线)。

只需在页面末尾添加一个脚本 (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);

【讨论】:

    【解决方案2】:

    我暂时使用一种解决方法。这不是一种美丽的方式,但我认为至少它仍然是一种干净的方式。这是给遇到同样问题的人的参考。

    我使用 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>

    【讨论】:

      猜你喜欢
      • 2017-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 2014-10-24
      • 2015-11-02
      • 2021-03-21
      • 2012-03-20
      相关资源
      最近更新 更多