【问题标题】:anime.js: how to reverse svg morphingAnime.js:如何反转 svg 变形
【发布时间】:2019-08-28 09:35:42
【问题描述】:

我尝试设置direction: 'reverse'timeline.reverse(),但它不起作用。如果我设置loop: true,那么你可以在循环中看到反向动画。但我想通过例如触发它一个按钮。这是codepen for pure javascripthere is a version with vue.js

function doFunction() {

var paths = [
  {id: '#path309', d: 'm 55.184523,127.42857 34.962798,139.6183 43.46726,120.24702 z'}, 
  {id: '#path311', d: 'm 54.389347,121.02185 -10.922087,-0.77483 11.717263,7.18155 z'}
];

var timeline = anime.timeline({ autoplay: true, direction: 'alternate', loop: false });

paths.forEach(function(path, index) {
  timeline
  .add({
    targets: path.id,
    d: {
      value: path.d,
      duration: 1000,
      easing: 'easeInOutQuad'
    },
    offset: 1000 + 10 * index
  });
});

}
<script src='https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js'></script>
<input id="clickMe" type="button" value="clickme" onclick="doFunction();" />  

<svg xmlns="http://www.w3.org/2000/svg" width="100mm" height="100mm" viewBox="0 0 200 200">

  <path d="m 110.51595,80.797791 26.28083,12.271789 2.96257,10.935445 z" id="path309" />
  <path d="m 70.51595,80.797791 -5.00762,25.058566 11.28845,-2.786777 z" id="path311" />

</svg>

【问题讨论】:

    标签: javascript animation vue.js svg anime.js


    【解决方案1】:

    通过使用timeline.reverse(),您可以反转要制作动画的时间线的方向。

    我将时间线放置在一个包含范围内,因此您不必在每次点击时重新构建时间线,并且可以在点击发生时将其反转。

    我还使用了一个事件监听器来绑定函数,而不是一个 html 内联事件监听器。

    使用animejs v2.2.0 很重要,因为offsettimeline 方面的API 在较新版本中已更改,因此此示例在较新版本中无法正常工作。

    这是纯 JavaScript 示例:

    /**
     * We start in a scoped function to store our timeline there
     */
    +function(button) {
      /**
       * A flag to know if we need to call reverse or not, we shouldn't on the first click
       */
      var firstRun = true;
      
      var paths = [
            {id: '#path309', d: 'm 55.184523,127.42857 34.962798,139.6183 43.46726,120.24702 z'}, 
            {id: '#path311', d: 'm 54.389347,121.02185 -10.922087,-0.77483 11.717263,7.18155 z'}
      ];
      /**
       * Disable the autoplay, we don't wanna jump the gun. 
       * Of if you do, remove the firstRun variable and if check.
       */ 
      var timeline = anime.timeline({ autoplay: false, direction: 'alternate', loop: false });
    
      paths.forEach(function(path, index) {
        timeline
          .add({
            targets: path.id,
            d: {
              value: path.d,
              duration: 1000,
              /**
               * I changed your chosen transform it because the delay 
               * your transform caused an almost second delay before
               * it started animating.
               */
              easing: 'easeInOutSine'
            },
            offset: 1000 + 10 * index
          });
      });
      /**
       * Listening to the click on the button
       */
      button.addEventListener('click', function() {
        /**
         * If the animation has run, reverse the timeline
         */
        if(!firstRun) {
           timeline.reverse();
        }    
        /**
         * Play the animation!
         */ 
        timeline.play();
        /**
         * We've run once. TIme to enable the reversing of the timeline.
         */
        firstRun = false;
      });
    }(document.getElementById("clickMe"));
    <script src='https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js'></script>
    <input id="clickMe" type="button" value="clickme" />  
    <svg xmlns="http://www.w3.org/2000/svg" width="100mm" height="100mm" viewBox="0 0 200 200">
    
      <path d="m 110.51595,80.797791 26.28083,12.271789 2.96257,10.935445 z" id="path309" />
      <path d="m 70.51595,80.797791 -5.00762,25.058566 11.28845,-2.786777 z" id="path311" />
    
    </svg>

    这里是vue.js 的例子:

    new Vue({
      el: '#app',
      data() { 
        return {
          timeline: anime.timeline({ autoplay: false, direction: 'alternate', loop: false }),
          prepared: false,
          switch1: false,
          paths: [
            {id: '#path309', d: 'm 55.184523,127.42857 34.962798,139.6183 43.46726,120.24702 z'}, 
            {id: '#path311', d: 'm 54.389347,121.02185 -10.922087,-0.77483 11.717263,7.18155 z'}
          ]
        }
      },
      
      watch: {
        //called whenever switch1 changes
        switch1(switchVal){
          this.transform(switchVal)
        }
      },
    
      methods: {
        /**
         *  Call prepare later on, because otherwise the dom doesn't really seem initalized when the code isn't placed at the end of the document. Otherwise you can use created: to do this and a seperate flag for the first run.
         */
        prepare:  function() {
          var timeline = this.timeline;
          this.paths.forEach(function(path, index) {
            timeline.add({
                targets: path.id,
                d: {
                  value: path.d,
                  duration: 1000,
                  easing: 'easeInOutSine'
                }, offset: 1000 + 10 * index
              })
            });
          
          this.prepared = true;
        },
        transform: function(direction) {
          if(!this.prepared) {
            this.prepare();
          }
          else {
            this.timeline.reverse();
          }
         this.timeline.play();
        }
      }   
    })
    #app {
       padding-bottom:200px;
    }
    <link rel='stylesheet' href='https://unpkg.com/vuetify/dist/vuetify.min.css'>
    <script src='https://unpkg.com/vue/dist/vue.js'></script>
    <script src='https://unpkg.com/vuetify/dist/vuetify.min.js'></script>
    <script src='https://unpkg.com/vue-i18n/dist/vue-i18n.js'></script>
    <script src='https://unpkg.com/animejs@2.2.0/anime.min.js'></script>
    
    <div id="app">
    
      <svg 
        xmlns="http://www.w3.org/2000/svg" 
        width="100mm" 
        height="100mm" 
        viewBox="0 0 200 200"
      >
          
        <path d="m 110.51595,80.797791 26.28083,12.271789 2.96257,10.935445 z" id="path309" />
        <path d="m 70.51595,80.797791 -5.00762,25.058566 11.28845,-2.786777 z" id="path311" />
          
      </svg>
      
      <v-switch 
        v-model="switch1" 
        label="Switch to transform and reverse"
        color="green"
      ></v-switch>
      
    </div>

    【讨论】:

    • 感谢您的回答。我试图用 vue.js 重现这一点,不幸的是 timeline.reverse() 没有做缓动,它只是跳回来。你能看一下吗? codepen.io/saitam1/pen/gyerEX
    • 是的,问题是你每次都重建你的时间线。您构建时间线一次。然后采取行动。您不记得状态,您进行了反转或其他操作,但这不是它的工作方式,您需要在开始反转后每次反转,因为时间线的状态是如何改变的。我会看看如何修改你的笔,它会真正起作用。但是您应该在最初的问题中添加您希望它与 vue 一起使用,即使核心概念保持不变。
    • @saitam 我在我的答案中添加了一个新的 sn-p 来说明如何使用我在 vue.js 中的答案中谈到的概念你可以在codepen.io/anon/pen/rbdKeq的codepen中看到它
    猜你喜欢
    • 1970-01-01
    • 2020-05-16
    • 2021-04-17
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多