SVG元素的反向动画

时间:2016-05-20 12:37:09

标签: css css3 animation svg css-animations

我正在研究一个动画,当一个点击事件后用jQuery添加一个类时会触发该动画。

它有点像切换:

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

  2. 第二次点击相同的按钮后,需要运行反向动画

  3. 有没有办法轻松扭转动画链?

    .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 个答案:

答案 0 :(得分:2)

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

演示过渡:

&#13;
&#13;
window.onload = function() {
  var btn = document.querySelector('button');
  btn.addEventListener('click', function() {
    document.querySelector('.container').classList.toggle('opened');
  });
}
&#13;
.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;
}
&#13;
<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>
&#13;
&#13;
&#13;

另一方面,动画不能自动产生反向效果,需要编写代码。即使编写了反向动画的代码,使其工作也很复杂(并且不能用纯CSS完成),因为你必须删除&#34; open&#34;添加&#34;关闭&#34;之前的动画动画和发生时,元素将在执行反向效果之前立即捕捉到其原始位置。输出不会像转换一样优雅,除非你输入很多混乱的代码。

使用动画进行演示:

&#13;
&#13;
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;
  });
}
&#13;
.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;
}
&#13;
<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>
&#13;
&#13;
&#13;

动画版本有一个虚拟调用container.clientHeight,这样做是为了确保在删除一个动画和添加另一个动画之间存在重画。否则,看起来好像没有发生任何事情您可以在我的回答here中找到更多详细信息。