SVG CSS动画平滑过渡和原点

时间:2021-01-02 18:25:40

标签: css animation svg

我有以下设置,其中多个对象以交错延迟缩小。我面临以下问题:

  • 缩小动画设置为从 0% 加速到 15%,然后减慢其余关键帧的速度。但是当动画从 15% 过渡到 16% 时,运动明显不和谐。我如何才能使这种过渡顺利进行?
  • 当圆圈开始时,它们从左边出现,而不是以它们的原点为中心。我该如何解决这个问题?

HTML:

<div>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <circle class="blk" cx="10" cy="10" r="5"/>
  
  <circle class="red" cx="20" cy="10" r="5" color="red" stroke="red" fill="red"/>
  
  <circle class="green" cx="30" cy="20" r="5" color="red" stroke="green" fill="green"/>
</svg>
</div>

CSS:

.blk{
  animation-name: zoom-out;
  animation-duration: 2s;
    animation-timing-function: ease-in-out;
    -webkit-animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 2.5s;
}


.red{
  animation-name: zoom-out;
  animation-duration: 2s;
    animation-timing-function: ease-in-out;
    -webkit-animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 1.5s;
}

.green{
  animation-name: zoom-out;
  animation-duration: 2s;
    animation-timing-function: ease-in-out;
    -webkit-animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 0.5s;
}

@keyframes zoom-out {
    0% {
        transform: scale(5,5);
    }
    15% {
        transform: scale(2,2);
    }
    100% {
        transform: scale(1,1);
    }
}  

1 个答案:

答案 0 :(得分:1)

一种可能的解决方案是使用 cx="0" 和 cy="0" 的圆圈,并使用具有 x 和 y 位置的这些圆圈,如下所示:

circle {
  animation-name: zoom-out;
  animation-duration: 2s;
  /*animation-timing-function: ease-in-out;
    -webkit-animation-timing-function: ease-in-out;*/
  animation-iteration-count: infinite;
}

#blk {
  animation-delay: 2.5s;
}

#red {
  stroke: red;
  fill: red;
  animation-delay: 1.5s;
}

#green {
  stroke: green;
  fill: green;
  animation-delay: 0.5s;
}

@keyframes zoom-out {
  0% {
    transform: scale(5, 5);
  }
  15% {
    transform: scale(2, 2);
  }
  100% {
    transform: scale(1, 1);
  }
}
<div>
  <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <circle id="blk" r="5" />
      <circle id="red" r="5" />
      <circle id="green" r="5" />
    </defs>

    <use xlink:href="#blk" x="10" y="10" />
    <use xlink:href="#red" x="20" y="10" />
    <use xlink:href="#green" x="30" y="20" />

  </svg>
</div>

此外,为了使过渡平滑,您可以使用 animation-timing-function: linear; 而不是 ease-in-out

更新

OP 正在评论:

<块引用>

至于原点,我使用的实际 SVG 是一个插画矢量,其中的每个对象都有多个路径和形状。因此,红色圆圈实际上是一个具有 50 个路径/形状的对象。我如何将一组路径的坐标归零?

接下来是我使用路径集合的示例:

let wrap = document.querySelector("#red .wrap")
let bb = wrap.getBBox();

wrap.setAttribute("transform",`translate(${-(bb.x + bb.width/2)}, ${-(bb.y + bb.height/2)})`)
g[id] {
  animation-name: zoom-out;
  animation-duration: 2s;
  animation-iteration-count: infinite;
}

#red {
  stroke: red;
  fill: red;
  animation-delay: 1.5s;
}

@keyframes zoom-out {
  0% {
    transform: scale(5, 5);
  }
  15% {
    transform: scale(2, 2);
  }
  100% {
    transform: scale(1, 1);
  }
}

svg{border:solid}
<svg viewBox="0 0 1000 500">
  <defs>
  <g id="red">
    <g class="wrap">
<path id="body" fill-rule="evenodd" clip-rule="evenodd" d="M121.506,108.953c3.145-2.115,5.896-3.967,8.624-5.802 c20.948,12.522,42.66,12.281,65.725,4.354c0.778,3.128,1.687,6.18,2.285,9.291c3.208,16.677,0.616,36.326-2.758,52.719
    c0,0-152.162,0.035-154.82,0.035c8.408,10.604,18.647,16.674,31.173,16.227c15.059-0.536,30.099-2.491,45.07-4.433
    c26.453-3.431,50.783,0.317,70.991,19.392c1.675,1.581,7.179,9.382,3.632,13.47c-3.524,4.062-12.062-1.289-13.795-3.036
    c-10.215-10.294-22.693-16.145-37.008-15.98c-14.568,0.166-29.103,2.376-43.679,3.216c-11.405,0.656-22.888,1.255-34.268,0.634
    c-9.862-0.538-18.646-5.258-25.691-12.131c-15.127-14.758-26.56-31.716-26.923-53.792c-0.396-24.125,17.008-44.198,40.835-48.153
    c23.477-3.897,43.372,4.666,62.051,17.569C115.82,104.515,118.537,106.717,121.506,108.953z"/>
<path id="head" fill-rule="evenodd" clip-rule="evenodd" d="M129.747,18.651c3.646,6.147,7.048,11.646,10.189,17.291
    c1.404,2.523,2.761,3.481,5.888,2.718c14.09-3.439,28.227-3.932,42.396-0.046c1.308,0.358,3.815-0.733,4.608-1.923
    c4.043-6.072,7.705-12.398,11.814-19.149c8.693,15.648,15.012,31.447,13.169,49.204c-1.48,14.266-9.114,24.946-22.028,31.172
    c-17.641,8.503-35.969,9.511-54.067,1.823c-15.169-6.443-22.96-18.723-23.677-35.151C117.396,49.828,122.038,32.188,129.747,18.651z
     M189.467,81.017c7.232,0.084,15.334-6.867,14.292-13.652c-0.832-5.418-11.566-6.019-11.732-6.025
    c-7.238-0.308-13.768,6.133-14.144,13.949C177.731,78.444,182.773,80.938,189.467,81.017z M145.369,81.453
    c3.597,0.294,11.258-2.441,11.324-6.992c0.079-5.443-3.357-10.158-8.897-12.255c-5.807-2.197-16.523,1.484-17.065,5.19
    C129.692,74.494,138.107,81.089,145.369,81.453z"/>
    </g>
  </g>
  </defs>
 <use xlink:href="#red"  x="300" y="175" />
</svg>

为了将路径集合的坐标归零我正在使用 javaScript。

  • 首先我将路径包装在一个组 class="wrap"
  • 我正在获取包装的边界框:let bb = wrap.getBBox();
  • 我正在使用边界框值来计算所需的平移并设置包装的变换属性。