SVG元素的反向动画

3
我正在制作一个动画,它将在通过jQuery添加类并单击事件后触发。它必须像切换一样:

  1. 第一次点击按钮后,将运行动画1 https://codepen.io/thijs-webber/pen/dMBKRp

  2. 在同一个按钮上进行第二次点击,需要运行反向动画

有没有一种简单的方法来反转动画链?

.animation-container {
  width: 250px;
  position: relative;
  margin: 0 auto;
  margin-top: 50px;
}
.dot-pink-light {
  fill: #CE97AE;
}
.dot-pink {
  fill: #D82566;
}
.dot-green-light {
  fill: #AFBF99;
}
.dot-green {
  fill: #77BC1F;
}
/* ANIMATIONS */
@keyframes rotate_clockwise {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
  }
}
@keyframes rotate_anticlockwise {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(-90deg);
    transform: rotate(-90deg);
  }
}
@keyframes scale_down {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
  100% {
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
  }
}
@keyframes pop_out_dots_top {
  100% {
    transform: translate(0px, -80px);
  }
}
@keyframes pop_out_dots_bottom {
  100% {
    transform: translate(0px, 80px);
  }
}
/* 1 */
.container.opened {
  animation: scale_down 250ms ease;
  transform-origin: 50% 50% 0;
}
/* 2 */
.container.opened .groups .extra-dot-top {
  animation: pop_out_dots_top 250ms ease;
  -webkit-animation-delay: 250ms;
  animation-delay: 250ms;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
  animation: pop_out_dots_bottom 250ms ease;
  -webkit-animation-delay: 250ms;
  animation-delay: 250ms;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .group-2 {
  animation: rotate_anticlockwise 250ms ease;
  transform-origin: 50% 50% 0;
  -webkit-animation-delay: 250ms;
  animation-delay: 250ms;
}
/* 4 */
.container.opened .groups {
  animation: rotate_clockwise 250ms ease;
  transform-origin: 50% 50% 0;
  -webkit-animation-delay: 500ms;
  animation-delay: 500ms;
}
<div class="animation-container">
  <div class="col-xs-12">
    <?xml version="1.0" ?>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">

      <!-- Group 1 -->
      <g class="container opened">
        <g class="groups">
          <g class="group-1 pink">
            <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink" cx="100" cy="100" r="21.4" />
            <circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
          </g>

          <!-- Group 2 -->
          <g class="group-2 green">
            <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-green" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green" cx="100" cy="100" r="21.4" />
            <circle class="dot-green" cx="100" cy="178.6" r="21.4" />
          </g>
        </g>
      </g>
    </svg>
  </div>
</div>

1个回答

2

由于您正在寻找仅具有两种不同状态的切换效果,因此最好使用过渡而不是动画。当删除类时,过渡可以自动产生相反的效果。

使用过渡的演示:

window.onload = function() {
  var btn = document.querySelector('button');
  btn.addEventListener('click', function() {
    document.querySelector('.container').classList.toggle('opened');
  });
}
.animation-container {
  width: 250px;
  position: relative;
  margin: 0 auto;
  margin-top: 50px;
}
.dot-pink-light {
  fill: #CE97AE;
}
.dot-pink {
  fill: #D82566;
}
.dot-green-light {
  fill: #AFBF99;
}
.dot-green {
  fill: #77BC1F;
}
/* 1 */
.container {
  transform: scale(1);
  transition: transform 2.5s ease;
  transform-origin: 50% 50% 0;
  transition-delay: 5s;
}
.container.opened {
  transform: scale(0.5);
  transition-delay: 0s;
}

.container .groups .extra-dot-top {
  transform: translate(0px, 0px);
  transition: transform 2.5s ease;
  transition-delay: 2.5s;
  transform-origin: 50% 50% 0;
} 
.container.opened .groups .extra-dot-top {
  transform: translate(0px, -80px);
}
.container .groups .extra-dot-bottom {
  transform: translate(0px, 0px);
  transition: transform 2.5s ease;
  transition-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
  transform: translate(0px, 80px);
}
.container .groups .group-2 {
  transform: rotate(0deg);
  transition: transform 2.5s ease;
  transform-origin: 50% 50% 0;
  transition-delay: 2.5s;
}
.container.opened .groups .group-2 {
  transform: rotate(-90deg);
}
/* 4 */
.container .groups {
  transform: rotate(0deg);
  transition: transform 2.5s ease;
  transform-origin: 50% 50% 0;
}
.container.opened .groups {
  transform: rotate(45deg);
  transition-delay: 5s;
}
<div class="animation-container">
  <div class="col-xs-12">
    <?xml version="1.0" ?>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">

      <!-- Group 1 -->
      <g class="container">
        <g class="groups">
          <g class="group-1 pink">
            <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink" cx="100" cy="100" r="21.4" />
            <circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
          </g>

          <!-- Group 2 -->
          <g class="group-2 green">
            <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-green" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green" cx="100" cy="100" r="21.4" />
            <circle class="dot-green" cx="100" cy="178.6" r="21.4" />
          </g>
        </g>
      </g>
    </svg>
  </div>
</div>
<button>Click</button>

另一方面,动画不能自动产生相反的效果,需要编写代码。即使编写了反向动画的代码,让它正常工作也很复杂(不能仅使用 CSS),因为你必须在添加“关闭”动画之前删除“打开”动画,这时元素将立即弹回到原来的位置,才能执行反向效果。除非你加入大量混乱的代码,否则输出不会像过渡那样优雅。
具有动画的演示:

window.onload = function() {
  var btn = document.querySelector('button');
  var container = document.querySelector('.container');
  var groups = document.querySelector('.groups');
  var group2 = document.querySelector('.group-2');
  var extradtG = document.querySelector('.green .extra-dot-top');
  var extradtP = document.querySelector('.pink .extra-dot-top');
  var extradbG = document.querySelector('.green .extra-dot-bottom');
  var extradbP = document.querySelector('.pink .extra-dot-bottom');
  var opened = false;
  btn.addEventListener('click', function() {
    if (opened) {
      container.style.transform = 'scale(1)';
      extradtG.style.transform = 'translate( 0px, 0px)';
      extradtP.style.transform = 'translate( 0px, 0px)';
      extradbG.style.transform = 'translate( 0px, 0px)';
      extradbP.style.transform = 'translate( 0px, 0px)';
      group2.style.transform = 'rotate(0deg);'
      groups.style.transform = 'rotate(0deg)';
      container.classList.remove('opened');
      container.clientHeight; // dummy call
      container.classList.add('closed');
    } else {
      container.style.transform = 'scale(0.5)';
      extradtG.style.transform = 'translate( 0px, -80px)';
      extradtP.style.transform = 'translate( 0px, -80px)';
      extradbG.style.transform = 'translate( 0px, 80px)';
      extradbP.style.transform = 'translate( 0px, 80px)';
      group2.style.transform = 'rotate(-90deg);'
      groups.style.transform = 'rotate(45deg)';
      container.classList.remove('closed');
      container.clientHeight; // dummy call
      container.classList.add('opened');
    }
    opened = !opened;
  });
}
.animation-container {
  width: 250px;
  position: relative;
  margin: 0 auto;
  margin-top: 50px;
}
.dot-pink-light {
  fill: #CE97AE;
}
.dot-pink {
  fill: #D82566;
}
.dot-green-light {
  fill: #AFBF99;
}
.dot-green {
  fill: #77BC1F;
}
/* ANIMATIONS */

@keyframes rotate_clockwise {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(45deg);
  }
}
@keyframes rotate_anticlockwise {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}
@keyframes scale_down {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(0.5);
  }
}
@keyframes pop_out_dots_top {
  0% {
    transform: translate(0px, 0px);
  }
  100% {
    transform: translate(0px, -80px);
  }
}
@keyframes pop_out_dots_bottom {
  0% {
    transform: translate(0px, 0px);
  }
  100% {
    transform: translate(0px, 80px);
  }
}
/* 1 */

.container.opened {
  animation: scale_down 2.5s ease;
  transform-origin: 50% 50% 0;
}
.container.closed {
  animation: scale_down 2.5s ease reverse backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 5s;
}
/* 2 */

.container.opened .groups .extra-dot-top {
  animation: pop_out_dots_top 2.5s ease backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.closed .groups .extra-dot-top {
  animation: pop_out_dots_top 2.5s ease reverse backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
  animation: pop_out_dots_bottom 2.5s ease backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.closed .groups .extra-dot-bottom {
  animation: pop_out_dots_bottom 2.5s ease reverse backwards;
  animation-delay: 2.5s;
  transform-origin: 50% 50% 0;
}
.container.opened .groups .group-2 {
  animation: rotate_anticlockwise 2.5s ease backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 2.5s;
}
.container.closed .groups .group-2 {
  animation: rotate_anticlockwise 2.5s ease reverse backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 2.5s;
}
/* 4 */

.container.opened .groups {
  animation: rotate_clockwise 2.5s ease backwards;
  transform-origin: 50% 50% 0;
  animation-delay: 5s;
}
.container.closed .groups {
  animation: rotate_clockwise 2.5s ease reverse backwards;
  transform-origin: 50% 50% 0;
}
<div class="animation-container">
  <div class="col-xs-12">
    <?xml version="1.0" ?>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">

      <!-- Group 1 -->
      <g class="container">
        <g class="groups">
          <g class="group-1 pink">
            <circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-pink" cx="100" cy="100" r="21.4" />
            <circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
          </g>

          <!-- Group 2 -->
          <g class="group-2 green">
            <circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
            <circle class="dot-green" cx="100" cy="21.4" r="21.4" />
            <circle class="dot-green" cx="100" cy="100" r="21.4" />
            <circle class="dot-green" cx="100" cy="178.6" r="21.4" />
          </g>
        </g>
      </g>
    </svg>
  </div>
</div>
<button>Click</button>

(动画版本有一个虚拟调用container.clientHeight,目的是确保在删除一个动画和添加另一个动画之间进行重新绘制。否则,看起来好像什么都没有发生。您可以在我的答案这里找到更多详细信息。)


1
哇!代码写得非常好,我真的很感激。尝试动画和过渡效果非常有趣。你帮了我很多,让我更好地理解了它们。 - Thijs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接