在背景图像上动画虚线 svg
Animate dashed svg on background image
我有一个看起来像这样的任务:
我需要在背景图像上动画(绘制)这条虚线(或者只是 <img />
- 无关紧要)。我曾经使用 SVG path
、stroke-dasharray
和 stroke-dashoffset
通过创建 *2 <path />
来制作这样的动画 - 第一个是实线,第二个是虚线 *。
但在这种情况下,第二个 path
需要与背景颜色相同,在我的情况下显然不会因为图像而发生这种情况。
我制作了jsfiddle来展示我现在拥有的东西。
不过我的问题是:是否有可能在某些图像上方实现这种类型的动画?
对于弯曲的路径,这很棘手。只要线条有主导方向,就可以用剪切矩形覆盖路径,有点像在先前隐藏的图像上打开窗帘:
<svg width="575" height="115" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="curtain">
<rect height="115" width="0">
<animate attributeType="XML" attributeName="width"
from="0" to="575" dur="10s" fill="freeze" />
</rect>
</clipPath>
</defs>
<path id="dashed" d="m14,112c21,-11 35,-14 35,-14c0,0 14,-1 14,-1c0,0 21,0 21,0c0,0 22,0 23,0c1,0 29,5 29,5c0,0 17,6 17,6c0,0 16,-2 17,-2c1,0 14,-1 14,-1c0,0 17,-3 17,-3c0,0 13,-3 13,-3c0,0 15,-9 15,-9c0,0 25,-10 25,-10c0,0 24,-2 24,-2c0,0 16,-3 17,-3c1,0 21,-1 21,-1c0,0 18,0 19,0c1,0 21,0 21,0c0,0 21,0 21,0c0,0 21,-1 21,-1c0,0 13,-2 14,-2c1,0 14,-8 15,-8c1,0 17,-7 17,-7c0,0 6,-1 7,-2c1,-1 11,-3 11,-3c0,0 21,-2 22,-2c1,0 20,-5 22,-6c2,-1 11,-8 12,-9c1,-1 17,-13 18,-13c1,0 16,-17 17,-18" stroke-width="4" stroke-dasharray="10" stroke="#E8511B" fill="none" clip-path="url(#curtain)"/>
</svg>
在 HTML 方面可以用 css 实现同样的效果:
#content {
width: 700px;
height: 300px;
position: relative;
}
#curtain {
position: relative;
width: 0%;
height: 100%;
overflow: hidden;
animation-name: draw;
animation-duration: 10s;
animation-fill-mode: forwards; // Stay on the last frame
animation-iteration-count: 1; // Run only once
animation-timing-function: linear;
}
.img {
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
z-index: 1;
}
svg {
position: absolute;
top: 20px;
left: 0;
}
#dashed {
stroke-dasharray: 10;
stroke: #E8511B;
stroke-width: 4;
fill: none;
}
@keyframes draw {
to {
width: 100%;
}
}
<div id="content">
<div id="curtain">
<svg width="575" height="115" xmlns="http://www.w3.org/2000/svg">
<path id="dashed" d="m14,112c21,-11 35,-14 35,-14c0,0 14,-1 14,-1c0,0 21,0 21,0c0,0 22,0 23,0c1,0 29,5 29,5c0,0 17,6 17,6c0,0 16,-2 17,-2c1,0 14,-1 14,-1c0,0 17,-3 17,-3c0,0 13,-3 13,-3c0,0 15,-9 15,-9c0,0 25,-10 25,-10c0,0 24,-2 24,-2c0,0 16,-3 17,-3c1,0 21,-1 21,-1c0,0 18,0 19,0c1,0 21,0 21,0c0,0 21,0 21,0c0,0 21,-1 21,-1c0,0 13,-2 14,-2c1,0 14,-8 15,-8c1,0 17,-7 17,-7c0,0 6,-1 7,-2c1,-1 11,-3 11,-3c0,0 21,-2 22,-2c1,0 20,-5 22,-6c2,-1 11,-8 12,-9c1,-1 17,-13 18,-13c1,0 16,-17 17,-18" />
</svg>
</div>
<img src="" class="img">
</div>
显然,这不会导致稳定的步伐 "along the path"。我不知道如何用弯曲的路径实现这一点(除了一些非常特殊的情况,其中 "leading" 点可以用数学上简单的时间函数表示)。
我一直在思考这个问题,最后找到了解决方案:简单地使用遮罩,而不是 clipPath:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="575" height="115" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="startAnimation()">
<defs>
<path id="dashed" d="m14,112c21,-11 35,-14 35,-14c0,0 14,-1 14,-1c0,0 21,0 21,0c0,0 22,0 23,0c1,0 29,5 29,5c0,0 17,6 17,6c0,0 16,-2 17,-2c1,0 14,-1 14,-1c0,0 17,-3 17,-3c0,0 13,-3 13,-3c0,0 15,-9 15,-9c0,0 25,-10 25,-10c0,0 24,-2 24,-2c0,0 16,-3 17,-3c1,0 21,-1 21,-1c0,0 18,0 19,0c1,0 21,0 21,0c0,0 21,0 21,0c0,0 21,-1 21,-1c0,0 13,-2 14,-2c1,0 14,-8 15,-8c1,0 17,-7 17,-7c0,0 6,-1 7,-2c1,-1 11,-3 11,-3c0,0 21,-2 22,-2c1,0 20,-5 22,-6c2,-1 11,-8 12,-9c1,-1 17,-13 18,-13c1,0 16,-17 17,-18" />
<mask id="mask">
<use xlink:href="#dashed" stroke-width="6" stroke="white" stroke-dasharray="1000,0" fill="none">
<animate id="reveal" attributeType="CSS" attributeName="stroke-dasharray"
from="0,1000" to="1000,0" begin="indefinite" dur="5s" fill="freeze" />
</use>
</mask>
<script type="application/ecmascript"><![CDATA[
function startAnimation() {
var len = document.getElementById('dashed').getTotalLength();
var animate = document.getElementById('reveal');
animate.setAttribute('from', '0,' + len);
animate.setAttribute('to', len + ',0');
animate.beginElement();
}
]]></script>
</defs>
<use xlink:href="#dashed" stroke-width="4" stroke-dasharray="10" stroke="#E8511B" fill="none" mask="url(#mask)"/>
</svg>
作为另一个优化,并受此 d3 Stroke Dash Interpolation 的启发,我计算了路径长度并对 stroke-dasharray
属性的两个值进行了动画处理,从而保持破折号 + 间隙的恒定长度。
我有一个看起来像这样的任务:
我需要在背景图像上动画(绘制)这条虚线(或者只是 <img />
- 无关紧要)。我曾经使用 SVG path
、stroke-dasharray
和 stroke-dashoffset
通过创建 *2 <path />
来制作这样的动画 - 第一个是实线,第二个是虚线 *。
但在这种情况下,第二个 path
需要与背景颜色相同,在我的情况下显然不会因为图像而发生这种情况。
我制作了jsfiddle来展示我现在拥有的东西。
不过我的问题是:是否有可能在某些图像上方实现这种类型的动画?
对于弯曲的路径,这很棘手。只要线条有主导方向,就可以用剪切矩形覆盖路径,有点像在先前隐藏的图像上打开窗帘:
<svg width="575" height="115" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="curtain">
<rect height="115" width="0">
<animate attributeType="XML" attributeName="width"
from="0" to="575" dur="10s" fill="freeze" />
</rect>
</clipPath>
</defs>
<path id="dashed" d="m14,112c21,-11 35,-14 35,-14c0,0 14,-1 14,-1c0,0 21,0 21,0c0,0 22,0 23,0c1,0 29,5 29,5c0,0 17,6 17,6c0,0 16,-2 17,-2c1,0 14,-1 14,-1c0,0 17,-3 17,-3c0,0 13,-3 13,-3c0,0 15,-9 15,-9c0,0 25,-10 25,-10c0,0 24,-2 24,-2c0,0 16,-3 17,-3c1,0 21,-1 21,-1c0,0 18,0 19,0c1,0 21,0 21,0c0,0 21,0 21,0c0,0 21,-1 21,-1c0,0 13,-2 14,-2c1,0 14,-8 15,-8c1,0 17,-7 17,-7c0,0 6,-1 7,-2c1,-1 11,-3 11,-3c0,0 21,-2 22,-2c1,0 20,-5 22,-6c2,-1 11,-8 12,-9c1,-1 17,-13 18,-13c1,0 16,-17 17,-18" stroke-width="4" stroke-dasharray="10" stroke="#E8511B" fill="none" clip-path="url(#curtain)"/>
</svg>
在 HTML 方面可以用 css 实现同样的效果:
#content {
width: 700px;
height: 300px;
position: relative;
}
#curtain {
position: relative;
width: 0%;
height: 100%;
overflow: hidden;
animation-name: draw;
animation-duration: 10s;
animation-fill-mode: forwards; // Stay on the last frame
animation-iteration-count: 1; // Run only once
animation-timing-function: linear;
}
.img {
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
z-index: 1;
}
svg {
position: absolute;
top: 20px;
left: 0;
}
#dashed {
stroke-dasharray: 10;
stroke: #E8511B;
stroke-width: 4;
fill: none;
}
@keyframes draw {
to {
width: 100%;
}
}
<div id="content">
<div id="curtain">
<svg width="575" height="115" xmlns="http://www.w3.org/2000/svg">
<path id="dashed" d="m14,112c21,-11 35,-14 35,-14c0,0 14,-1 14,-1c0,0 21,0 21,0c0,0 22,0 23,0c1,0 29,5 29,5c0,0 17,6 17,6c0,0 16,-2 17,-2c1,0 14,-1 14,-1c0,0 17,-3 17,-3c0,0 13,-3 13,-3c0,0 15,-9 15,-9c0,0 25,-10 25,-10c0,0 24,-2 24,-2c0,0 16,-3 17,-3c1,0 21,-1 21,-1c0,0 18,0 19,0c1,0 21,0 21,0c0,0 21,0 21,0c0,0 21,-1 21,-1c0,0 13,-2 14,-2c1,0 14,-8 15,-8c1,0 17,-7 17,-7c0,0 6,-1 7,-2c1,-1 11,-3 11,-3c0,0 21,-2 22,-2c1,0 20,-5 22,-6c2,-1 11,-8 12,-9c1,-1 17,-13 18,-13c1,0 16,-17 17,-18" />
</svg>
</div>
<img src="" class="img">
</div>
显然,这不会导致稳定的步伐 "along the path"。我不知道如何用弯曲的路径实现这一点(除了一些非常特殊的情况,其中 "leading" 点可以用数学上简单的时间函数表示)。
我一直在思考这个问题,最后找到了解决方案:简单地使用遮罩,而不是 clipPath:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="575" height="115" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="startAnimation()">
<defs>
<path id="dashed" d="m14,112c21,-11 35,-14 35,-14c0,0 14,-1 14,-1c0,0 21,0 21,0c0,0 22,0 23,0c1,0 29,5 29,5c0,0 17,6 17,6c0,0 16,-2 17,-2c1,0 14,-1 14,-1c0,0 17,-3 17,-3c0,0 13,-3 13,-3c0,0 15,-9 15,-9c0,0 25,-10 25,-10c0,0 24,-2 24,-2c0,0 16,-3 17,-3c1,0 21,-1 21,-1c0,0 18,0 19,0c1,0 21,0 21,0c0,0 21,0 21,0c0,0 21,-1 21,-1c0,0 13,-2 14,-2c1,0 14,-8 15,-8c1,0 17,-7 17,-7c0,0 6,-1 7,-2c1,-1 11,-3 11,-3c0,0 21,-2 22,-2c1,0 20,-5 22,-6c2,-1 11,-8 12,-9c1,-1 17,-13 18,-13c1,0 16,-17 17,-18" />
<mask id="mask">
<use xlink:href="#dashed" stroke-width="6" stroke="white" stroke-dasharray="1000,0" fill="none">
<animate id="reveal" attributeType="CSS" attributeName="stroke-dasharray"
from="0,1000" to="1000,0" begin="indefinite" dur="5s" fill="freeze" />
</use>
</mask>
<script type="application/ecmascript"><![CDATA[
function startAnimation() {
var len = document.getElementById('dashed').getTotalLength();
var animate = document.getElementById('reveal');
animate.setAttribute('from', '0,' + len);
animate.setAttribute('to', len + ',0');
animate.beginElement();
}
]]></script>
</defs>
<use xlink:href="#dashed" stroke-width="4" stroke-dasharray="10" stroke="#E8511B" fill="none" mask="url(#mask)"/>
</svg>
作为另一个优化,并受此 d3 Stroke Dash Interpolation 的启发,我计算了路径长度并对 stroke-dasharray
属性的两个值进行了动画处理,从而保持破折号 + 间隙的恒定长度。