如何为 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-delayanimation-duration 的值。

【讨论】:

【参考方案6】:

您确实可以使用关键帧,除了不透明度之外,还有很多事情要做。您可以使用stroke-dashoffsetstroke-dasharray 动画绘制轮廓。还有一些方法可以让它们从 let 和 right 淡入 translateXtranslateY。还有旋转动画。 看看我做的笔中的css:https://codepen.io/YilmazTut/pen/JzaQEy.

还有一系列关于 svg 的 css 技巧:https://css-tricks.com/lodge/svg/ 我用它在我的笔中创建徽标。从教程 16 开始,他解释了动画以及路径绘图的工作原理。我希望你能找到你的路!

【讨论】:

我也可以尝试为你的 svg 创建一些东西,但我需要你更具体地说明它需要如何制作动画。

以上是关于如何为 SVG 多边形设置动画以进行填充?的主要内容,如果未能解决你的问题,请参考以下文章

如何在React Native中为SVG坐标设置动画?

如何为 CAShapeLayer 路径和填充颜色设置动画

使用 SVG 动画和翻转六边形

您如何为视图填充的变化设置动画?

当它们移动以填充其他淡出的 div 留下的空白空间时如何为 div 设置动画

如何为svg rect设置填充颜色