如何为 SVG 多边形设置动画以进行填充?
Posted
技术标签:
【中文标题】如何为 SVG 多边形设置动画以进行填充?【英文标题】:How to animate a SVG polygon to fill? 【发布时间】:2019-08-31 18:04:39 【问题描述】:我有一个 SVG 字母 (A),它由两个多边形和一个矩形组成。我想以 第一个多边形变为可见然后第二个多边形的方式为它们设置动画。之后,矩形将变得可见。在动画开始之前,SVG 将不可见。
我已经尝试过关键帧描边,但由于它们不是基于路径而是基于多边形的点,所以它不起作用。
<svg >
<polygon points="34 537,150 536,289 130,314 53,196 51"/>
<animate attributeName="points" dur="5s" fill="freeze" />
<polygon points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<rect x="120" y="320" stroke-miterlimit="10" />
</svg>
如果你想用,这里有一支笔:https://codepen.io/anon/pen/vMxXaP
【问题讨论】:
【参考方案1】:SVG 解决方案
旋转和外观动画
.container
width:35%;
height:35%;
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<g fill="black" fill-opacity="0" >
<polygon
id="left" transform="rotate(72 306 200)" points="34 537,150 536,289 130,314 53,196 51">
<animateTransform
attributeName="transform"
type="rotate"
values="72 306 200;0 306 200"
begin="svg1.click"
dur="0.5s"
fill="freeze" />
<animate
id="an_op1"
attributeName="fill-opacity"
from="0"
to="1"
begin="svg1.click"
dur="0.5s"
fill="freeze" />
</polygon>
<polygon id="right" transform="rotate(-69 457.5 200)"
points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55">
<animateTransform
attributeName="transform"
type="rotate"
values="-69 457.5 200;0 457.5 200"
begin="an_op1.end"
dur="0.5s"
fill="freeze" />
<animate
id="an_op2"
attributeName="fill-opacity"
from="0"
to="1"
begin="an_op1.end"
dur="0.5s"
fill="freeze" />
</polygon>
<rect id="rect1" x="800" y="320" >
<animate
attributeName="x"
from="800"
to="120"
begin="an_op2.end"
dur="0.5s"
fill="freeze" />
<animate
id="an_op3"
attributeName="fill-opacity"
from="0"
to="1"
begin="an_op2.end"
dur="0.5s"
fill="freeze" />
</rect>
</g>
<text x="0" y="80" font-size="50" fill="purple">Click me</text>
</svg>
</div>
第二种解决方案
所有动画元素在开始时都是不可见的。 fill-opacity="0"
物品外观动画:
<animate
id="an_left"
attributeName="fill-opacity"
begin="1s"
from="0"
to="1"
dur="0.3s"
fill="freeze"/>
以下是完整代码:
.container
width:35%;
height:35%;
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<polygon id="right" fill="#008080" fill-opacity="0"
points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55">
<animate
id="an_right"
attributeName="fill-opacity"
begin="an_left.end"
from="0"
to="1"
dur="0.3s"
fill="freeze"/>
</polygon>
<polygon id="left" fill="#008080" fill-opacity="0" points="34 537,150 536,289 130,314 53,196 51">
<animate
id="an_left"
attributeName="fill-opacity"
begin="0.2s"
from="0"
to="1"
dur="0.3s"
fill="freeze"/>
</polygon>
<rect x="120" y="320" fill="#008080" fill-opacity="0" stroke-miterlimit="10" >
<animate
id="an_rect"
attributeName="fill-opacity"
from="0"
to="1"
begin="an_right.end"
dur="0.3s"
fill="freeze"/>
</rect>
</svg>
</div>
动画的顺序是通过属性中的一连串条件实现的——begin="an_left.end"
这样的记录意味着右侧矩形的动画将在左侧多边形的动画结束之后才开始。
CSS 解决方案
.container
width:35%;
height:35%;
#left,#right, #rect1
fill-opacity:0;
fill:#008080;
#left
animation:anLeft 0.3s ease forwards;
animation-delay: 0.1s;
@keyframes anLeft
100%
fill-opacity:1;
#right
animation:anRight 0.3s ease forwards;
animation-delay: 0.4s;
@keyframes anRight
100%
fill-opacity:1;
#rect1
animation:anRect 0.3s ease forwards;
animation-delay:0.7s;
@keyframes anRect
100%
fill-opacity:1;
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<polygon id="right"
points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<polygon id="left" points="34 537,150 536,289 130,314 53,196 51"/>
<rect id="rect1" x="120" y="320" stroke-miterlimit="10" />
</svg>
</div>
【讨论】:
动画fill-opacity
是最好的选择。
嘿伙计!你的回答对我来说几乎是完美的,但 web-tiki 发布了一个完美的答案。不过非常感谢老哥的解答!【参考方案2】:
奖金版本。在这里,我将您的路径变成了蒙版并添加了背景动画。
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<style>
svg
height:160px;
background: url(https://i.imgur.com/Pr8tfnT.png);
background-position: 0px 111px;
background-repeat: repeat-x;
background-size: 100%;
animation: water 10s forwards;
@keyframes water
100%
background-position: 2000px 0px;
</style>
<mask id="mask" fill="black">
<rect fill="white" />
<polygon id="right" points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<polygon id="left" points="34 537,150 536,289 130,314 53,196 51"/>
<rect id="rect1" x="120" y="320" stroke-miterlimit="10" />
</mask>
<rect fill="white" mask="url(#mask)"/>
</svg>
【讨论】:
【参考方案3】:这是一个纯 javascript 的示例,并通过增量时间改变不透明度
let left = document.querySelector('#left')
let right = document.querySelector('#right')
let rect1 = document.querySelector('#rect1')
let time = 3000; // animation time
let delay = 1000; // animation delay
// dt - time from animation start
function animate(dt)
let v = dt - delay;
opacity(left, v/time*3);
opacity(right, v/time*3 - 1);
opacity(rect1, v/time*3 - 2);
dt < time + delay + 50 && requestAnimationFrame(animate)
function opacity(el, v)
v = Math.min(1, Math.max(v, 0)); // clamp to 0-1
el.setAttribute('opacity', v)
requestAnimationFrame(animate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 600 800">
<g fill="#008080">
<polygon id="right" opacity="0" points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<polygon id="left" opacity="0" points="34 537,150 536,289 130,314 53,196 51"/>
<rect id="rect1" opacity="0" x="120" y="320" stroke-miterlimit="10" />
</g>
</svg>
【讨论】:
【参考方案4】:您仍然可以使用带笔触而不是填充的多边形来绘制 (A) 字母。以下示例使用 stroke-dasharray 上的两个关键帧动画分两步绘制 A 字母:
-
左上角和右上角线的第一步(svg 中的第一个多边形元素)
关闭 A 的水平线的第二步(svg 元素中的第二个多边形)
.letter
width:200px;height:auto;
stroke-width:2.5;
stroke:#000;
fill:none;
stroke-dasharray: 0 24;
.animateFirst animation: 0.5s animateFirst ease-in forwards;
.animateSecond animation: 0.2s 0.45s animateSecond ease-out forwards;
@keyframes animateFirst
to stroke-dasharray: 24 24;
@keyframes animateSecond
to stroke-dasharray: 6 24;
<svg class="letter" viewbox="0 0 12 10">
<polygon class="animateFirst" points="1,11.5 6,0 11,11.5" />
<polygon class="animateSecond" points="3,6.5 9,6.5" />
</svg>
【讨论】:
感受大师之手 可惜你最近很少回复 @Alexandr_TT 这是一个非常好的评论,谢谢 :) 我研究了你的旧作。我真的很喜欢他们,很多翻译成俄语。 SO 当然,我总是指出源头。 完全按照我的要求工作!非常感谢你!非常感谢!【参考方案5】:我使用 CSS 关键帧解决了这个问题,这是您要找的吗?
@keyframes fade
from
opacity: 0;
to
opacity: 1;
#right
animation-delay: 1s;
#center
animation-delay: 2s;
.shape
opacity: 0;
animation-fill-mode: forwards;
animation-iteration-count: 1;
animation-name: fade;
animation-duration: 1s;
<svg id="abcdef" >
<polygon class="shape" points="34 537,150 536,289 130,314 53,196 51"/>
<polygon id="right" class="shape" points="411 537,528 537,364 118,354 91,348 72,341 53,327 53,223 55"/>
<rect id="center" class="shape" x="120" y="320" filter="#008080" stroke-miterlimit="10" />
</svg>
如果您想调整动画的持续时间,您必须考虑更改 animation-delay
和 animation-duration
的值。
【讨论】:
【参考方案6】:您确实可以使用关键帧,除了不透明度之外,还有很多事情要做。您可以使用stroke-dashoffset
和stroke-dasharray
动画绘制轮廓。还有一些方法可以让它们从 let 和 right 淡入 translateX
或 translateY
。还有旋转动画。
看看我做的笔中的css:https://codepen.io/YilmazTut/pen/JzaQEy.
还有一系列关于 svg 的 css 技巧:https://css-tricks.com/lodge/svg/ 我用它在我的笔中创建徽标。从教程 16 开始,他解释了动画以及路径绘图的工作原理。我希望你能找到你的路!
【讨论】:
我也可以尝试为你的 svg 创建一些东西,但我需要你更具体地说明它需要如何制作动画。以上是关于如何为 SVG 多边形设置动画以进行填充?的主要内容,如果未能解决你的问题,请参考以下文章