Banana Sprite JS使用JSON数据定制前进和后退动画

时间:2019-06-28 00:08:23

标签: javascript css animation

我需要创建一些自定义滚动动画-并希望开始探索制作一个简单块的动画。

enter image description here

使用json-我想提供块的骨架(类名,高度,宽度,背景),然后提供与滚动值相关的每个开始/结束帧的动作。

我该如何修改代码-使用数据json处理该块的前进/后退动画

所以在这个例子中。

-滚动为0时-或应用程序开始-创建块。 enter image description here

-如果滚动条在100-400的范围内-指示滚动条向右移动。 enter image description here

-如果卷轴超过400,则摧毁方块。

所以动画要在向前的方向上保持住,但是我想在相反的方向上反转动画-因此时间轴可以向前,向后移动-取决于滚动速度-因此是慢动作或加速情感可以抓住

这是第一步-添加具有多个对象的更复杂的动画,更长的复杂动画。

我已尝试捕获翻译细节,以使原汁原味的x或y翻译不会被覆盖-但我认为这是一个错误。...

请复查 Get translate3d values of a div?

// jsfiddle
https://jsfiddle.net/g10qe5m6/6/

var data = [{
  "structure": {
    "name": "square",
    "height": 30,
    "width": 30,
    "x": 10,
    "y": 10,
    "background": 'url("https://i.pinimg.com/originals/74/f3/5d/74f35d5885e8eb858e6af6b5a7844379.jpg")'
  },
  "frames": [{
    "create": [{
      "s": 0
    }, {
      "e": 0
    }]
  }, {
    "moveRight": [{
      "s": 1
    }, {
      "e": 400
    }]
  }, {
    "destroy": [{
      "s": 400
    }, {
      "e": 400
    }]
  }]
}]

//console.log(data)

function getCurrentValues(el) {
  var results = $(el).css('transform').match(/matrix(?:(3d)\(\d+(?:, \d+)*(?:, (\d+))(?:, (\d+))(?:, (\d+)), \d+\)|\(\d+(?:, \d+)*(?:, (\d+))(?:, (\d+))\))/)

if(!results) return [0, 0, 0];
if(results[1] == '3d') return results.slice(2,5);

results.push(0);
return results.slice(5, 8);
};


var animations = {
  createObj: function(obj) {
    //create object
    var block = $('<div></div>');
    $(block).addClass(obj.name);
    $(block).addClass("animatedblock");
    $(block).css("height", obj.height);
    $(block).css("width", obj.width);
    $(block).css("transform", 'translate(' + obj.x + 'px, ' + obj.y + 'px)');
    $(block).css("background", obj.background);
  $(block).css("background-size", "cover");

    $('.container').append($(block));
  },
  deleteObj: function(el) {
    //destroy object
    el.remove()
  },
  moveRight: function(el, pixels) {
    //el.css('')
    //move right

  console.log("x", getCurrentValues(el)[0])
   console.log("y", getCurrentValues(el)[1])

  el.css('transform', 'translate(' + pixels + 'px, ' + getCurrentValues(el)[1] + 'px');

    //el.css('transform', 'translate(' + pixels + 'px, ' + getCurrentValues(el).y + 'px');
  },
  moveLeft: function(el, pixels) {
    //move left     
    //el.css('transform', 'translate(' + -pixels + 'px, ' + getCurrentValues(el).y + 'px');


  console.log("x", getCurrentValues(el)[0])
   console.log("y", getCurrentValues(el)[1])


  el.css('transform', 'translate(' + -pixels + 'px, ' + getCurrentValues(el)[1] + 'px');

  },
  moveDown: function(el, pixels) {
    //move down     
    //el.css('transform', 'translate(' + getValues(el).x + 'px, ' + pixels + 'px)');


  el.css('transform', 'translate(' + getCurrentValues(el)[0] + 'px, ' + pixels + 'px');


  },
  moveUp: function(el, pixels) {
    //move up       
    // el.css('transform', 'translate(' + getValues(el).x + 'px, ' + -pixels + 'px)');

        el.css('transform', 'translate(' + getCurrentValues(el)[0] + 'px, ' + -pixels + 'px');

  }
}



//app.deleteObj($('.square'));

//data.skeleton

/*
    var instructor = {
      action: function(data, position) {

        console.log("position", position)

        $.each(data, function(i, item) {
          //alert(item.PageName);
          console.log("item", item.frames)
        });
      }
    }
*/


var frames = data[0].frames;

var instructor = {
  action: function(scroll, direction) {

    var sequence = [{
      "create": 0,
      "moveRight": 100,
      "moveDown": 200,
      "destroy": 400
    }]

    //if down - forward animation

    //if up - reverse animation

    ///use the data to detect what the block can do at what start and end frame
    if (scroll == 0) {
      //create block
      //animations.createObj(data[0].structure);
    }

    if (scroll > 100 && scroll < 400) {
      //move right
      animations.moveRight($('.square'), scroll);
    }


    if (scroll > 400 && scroll < 800) {
      //move right
      animations.moveDown($('.square'), scroll);
    }

    if (scroll > 800) {
      //animations.deleteObj($('.square'));
    }


    //move left
    //animations.moveLeft($('.square'), scroll);

  }
}



animations.createObj(data[0].structure);

var position = $(window).scrollTop();

$(window).scroll(function() {
  var scroll = $(window).scrollTop();
  console.log("scroll", scroll);

  if (scroll > position) {
    console.log('scrollDown');
    instructor.action(scroll, "down");
  } else {
    console.log('scrollUp');
    instructor.action(scroll, "up");
  }
  position = scroll;

});

1 个答案:

答案 0 :(得分:4)

尽管问题过于广泛,无法在一个答案中解决,但我会尽力给您 一个主意。将代码分解为小模块,以处理滚动事件和动画操作。 subscription方法用于以Observable模式绑定事件侦听器。其余的 该代码不言自明。如有任何疑问,请在下面评论。

let data = [{
    "structure": {
      "name": "square",
      "height": 30,
      "width": 30,
      "x": 0,
      "y": 0,
      "background": 'url("https://i.pinimg.com/originals/74/f3/5d/74f35d5885e8eb858e6af6b5a7844379.jpg")'
    },
    "frames": [{
      "animation": "move",
      "start": 0,
      "stop": 300,
      "startPositionX": 0,
      "startPositionY": 0,
      "endPositionX": 90,
      "endPositionY": 0,
    }, {
      "animation": "move",
      "start": 301,
      "stop": 600,
      "startPositionX": 90,
      "startPositionY": 0,
      "endPositionX": 90,
      "endPositionY": 80,
    }, {
      "animation": "move",
      "start": 601,
      "stop": 900,
      "startPositionX": 90,
      "startPositionY": 80,
      "endPositionX": 0,
      "endPositionY": 0,
    }, {
      "animation": "show",
      "start": 601,
      "stop": 9999,
      "positionX": 0,
      "positionY": 0,
    }],
  },
  {
    "structure": {
      "name": "pear",
      "height": 30,
      "width": 30,
      "x": 90,
      "y": 80,
      "background": 'url("https://i.pinimg.com/originals/74/f3/5d/74f35d5885e8eb858e6af6b5a7844379.jpg")'
    },
    "frames": [{
      "animation": "move",
      "start": 0,
      "stop": 300,
      "startPositionX": 90,
      "startPositionY": 80,
      "endPositionX": 0,
      "endPositionY": 80,
    }, {
      "animation": "move",
      "start": 301,
      "stop": 600,
      "startPositionX": 0,
      "startPositionY": 80,
      "endPositionX": 0,
      "endPositionY": 0,
    }, {
      "animation": "move",
      "start": 601,
      "stop": 900,
      "startPositionX": 0,
      "startPositionY": 0,
      "endPositionX": 90,
      "endPositionY": 80,
    }, {
      "animation": "show",
      "start": 601,
      "stop": 9999,
      "positionX": 90,
      "positionY": 80,
    }],
  }
]

let animations = {
  setup: function($container) {
    this.$container = $container;
    this.viewportWidth = $container.width();
    this.viewportHeight = $container.height();
  },
  createBlock: function(blockSpec) {
    let $block = $('<div>');
    $block.addClass(blockSpec.name);
    $block.addClass("animatedblock");
    $block.css("height", blockSpec.height);
    $block.css("width", blockSpec.width);
    $block.css("background", blockSpec.background);
    $block.css("background-size", "cover");
    this.$container.append($block);
    this.setPosition($block, blockSpec.x, blockSpec.y)
    return $block;
  },
  setPosition($block, x, y) {
    $block.css({
      left: x / 100 * this.viewportWidth,
      top: y / 100 * this.viewportHeight,
    });
  },
  moveBlock($block, frame, scrollProgress) {
    let blockPositionX = frame.startPositionX + scrollProgress * (frame.endPositionX - frame.startPositionX);
    let blockPositionY = frame.startPositionY + scrollProgress * (frame.endPositionY - frame.startPositionY);
    this.setPosition($block, blockPositionX, blockPositionY);
  },
  showBlock: function($block, frame) {
    $block.show()
    this.setPosition($block, frame.positionX, frame.positionY);
  },
  hideBlock: function($block) {
    $block.hide()
  },
}

class ScrollObserver {
  constructor() {
    let $window = $(window);
    this.STOP_DISPATCH = 'STOP_DISPATCH';
    this.subscribers = [];
    $window.scroll(event => this.dispatch($window.scrollTop()));
  }
  subscribe(subscriberFn) {
    this.subscribers.push(subscriberFn);
  }
  dispatch(scrollPosition) {
    for (let subscriberFn of this.subscribers) {
      if (subscriberFn(scrollPosition) == this.STOP_DISPATCH) break;
    }
  }
}

jQuery(function($) {
  animations.setup($('.container'));
  $(window).resize(event => animations.setup($('.container')));
  for (let obj of data) {
    let scrollObserver = new ScrollObserver();
    let blockSpec = obj.structure;
    let $block = animations.createBlock(blockSpec);
    for (let frame of obj.frames) {
      scrollObserver.subscribe(scrollPosition => {
        if (scrollPosition >= frame.start && scrollPosition <= frame.stop) {
          let scrollProgress = (scrollPosition - frame.start) / (frame.stop - frame.start);
          switch (frame.animation) {
            case 'move':
              animations.moveBlock($block, frame, scrollProgress);
              break;
            case 'show':
              animations.showBlock($block, frame);
          }
          return scrollObserver.STOP_DISPATCH;
        }
      });
    }
  }
});
body {
  height: 1500px;
}

.container {
  background: grey;
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  width: 100vw;
  box-sizing: content-box;
}

.animatedblock {
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container"></div>