Anime.js: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
 
(6 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 6: Zeile 6:
 
  https://www.youtube.com/watch?v=uRDLFXxihgc - guter Einstieg
 
  https://www.youtube.com/watch?v=uRDLFXxihgc - guter Einstieg
 
  https://codepen.io/rexjbull/pen/RwRRezq Beispiel mit Scrollmagic
 
  https://codepen.io/rexjbull/pen/RwRRezq Beispiel mit Scrollmagic
 +
http://snapsvg.io/ SVG Tools
  
 
== Quickstart ==
 
== Quickstart ==
Zeile 39: Zeile 40:
 
* Animieren von '''JavaScript Objekten''' (mit mindestens einem Zahlenwert)
 
* Animieren von '''JavaScript Objekten''' (mit mindestens einem Zahlenwert)
 
* Animieren von '''DOM Attributen'''
 
* Animieren von '''DOM Attributen'''
 +
 +
== Staggering ==
 +
https://animejs.com/documentation/#staggeringBasics
 +
 +
 +
== Morphing SVG ==
 +
https://codepen.io/kholja/pen/KKgbBQe
 +
Anime.js kann im Prinzip alle Werte in Bereichen verändern. Das funktioniert auch mit dem d Attribut in SVG Path Elementen oder Polygonen etc. Dabei sind ein paar Vorarbeiten notwendig:
 +
* Punktanzahl der Pfade sollte gleich sein.
 +
* Bei Pfaden kann es bei relativen Pfadangaben Probleme geben
 +
* Bei Punkten die mit H oder V (Horizontal, Vertikal) angegeben sind gibt es nur eine statt zwei Koordinaten. Das kann dazu führen dass unterschiedliche viele Werte entstehen.
 +
 +
Im Vergleich zum GSAP Morph Plugin ist Anime.js deutlich unflexibler. Performance ist aber OK und es ist kostenfrei. Für kleine Morphs durchaus geeignet.
 +
''Beispiel''
 +
<syntaxhighlight lang="html5">
 +
<div>
 +
    <button id="b1">Play</button>
 +
  </div>
 +
  <div id="ani1">
 +
    <svg xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" stroke-miterlimit="5" clip-rule="evenodd" viewBox="0 0 282 181">
 +
      <path fill="none" stroke="#000" stroke-width="2" d="M2 178L70 61l21 37 7-12 19 32 9 15 20-33 13 23 54-93 22 37 8-14 36 64"/>
 +
  </svg>
 +
</div>
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="javascript">
 +
var ani1 = anime({
 +
  targets: document.querySelector("#ani1 path"),
 +
  // using range [] on 2 paths here, coordinates are converted to absolute values.
 +
  d: [
 +
    "M 0,178 L 70,61 L 91,98 L 98,86 L 117,118 L 126,133 L 146,100 L 159,123 L 213,30 L 235,67 L 243,53 L 279,117",
 +
    "M 0,178 L 73,99 L 92,120 L 98,120 L 106,133 L 134,2 L 164,178L180,120 L197,120L212,102 L224,116 L279,116"],
 +
  easing: 'easeInOutCubic',
 +
  duration: 1000,
 +
  autoplay: false,
 +
  loop: true,
 +
  direction: 'alternate',
 +
  delay: 1000,
 +
  endDelay:500,
 +
});
 +
 +
document.querySelector('#b1').onclick = ani1.play;
 +
</syntaxhighlight>
 +
 +
==Helpüers==
 +
 +
<syntaxhighlight lang="javascript">
 +
// import anime from '../../../src/index.js';
 +
 +
/* Ontersection observer */
 +
 +
!function(t,e){"use strict";function n(t){this.time=t.time,this.target=t.target,this.rootBounds=t.rootBounds,this.boundingClientRect=t.boundingClientRect,this.intersectionRect=t.intersectionRect||a(),this.isIntersecting=!!t.intersectionRect;var e=this.boundingClientRect,n=e.width*e.height,i=this.intersectionRect,o=i.width*i.height;n?this.intersectionRatio=o/n:this.intersectionRatio=this.isIntersecting?1:0}function i(t,e){var n=e||{};if("function"!=typeof t)throw new Error("callback must be a function");if(n.root&&1!=n.root.nodeType)throw new Error("root must be an Element");this._checkForIntersections=r(this._checkForIntersections.bind(this),this.THROTTLE_TIMEOUT),this._callback=t,this._observationTargets=[],this._queuedEntries=[],this._rootMarginValues=this._parseRootMargin(n.rootMargin),this.thresholds=this._initThresholds(n.threshold),this.root=n.root||null,this.rootMargin=this._rootMarginValues.map(function(t){return t.value+t.unit}).join(" ")}function o(){return t.performance&&performance.now&&performance.now()}function r(t,e){var n=null;return function(){n||(n=setTimeout(function(){t(),n=null},e))}}function s(t,e,n,i){"function"==typeof t.addEventListener?t.addEventListener(e,n,i||!1):"function"==typeof t.attachEvent&&t.attachEvent("on"+e,n)}function h(t,e,n,i){"function"==typeof t.removeEventListener?t.removeEventListener(e,n,i||!1):"function"==typeof t.detatchEvent&&t.detatchEvent("on"+e,n)}function c(t,e){var n=Math.max(t.top,e.top),i=Math.min(t.bottom,e.bottom),o=Math.max(t.left,e.left),r=Math.min(t.right,e.right),s=r-o,h=i-n;return s>=0&&h>=0&&{top:n,bottom:i,left:o,right:r,width:s,height:h}}function u(t){var e;try{e=t.getBoundingClientRect()}catch(n){}return e?(e.width&&e.height||(e={top:e.top,right:e.right,bottom:e.bottom,left:e.left,width:e.right-e.left,height:e.bottom-e.top}),e):a()}function a(){return{top:0,bottom:0,left:0,right:0,width:0,height:0}}function l(t,e){for(var n=e;n;){if(n==t)return!0;n=p(n)}return!1}function p(t){var e=t.parentNode;return e&&11==e.nodeType&&e.host?e.host:e}if("IntersectionObserver"in t&&"IntersectionObserverEntry"in t&&"intersectionRatio"in t.IntersectionObserverEntry.prototype)return void("isIntersecting"in t.IntersectionObserverEntry.prototype||Object.defineProperty(t.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}}));var f=[];i.prototype.THROTTLE_TIMEOUT=100,i.prototype.POLL_INTERVAL=null,i.prototype.observe=function(t){var e=this._observationTargets.some(function(e){return e.element==t});if(!e){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},i.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter(function(e){return e.element!=t}),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},i.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},i.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},i.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter(function(t,e,n){if("number"!=typeof t||isNaN(t)||0>t||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==n[e-1]})},i.prototype._parseRootMargin=function(t){var e=t||"0px",n=e.split(/\s+/).map(function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}});return n[1]=n[1]||n[0],n[2]=n[2]||n[0],n[3]=n[3]||n[1],n},i.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(s(t,"resize",this._checkForIntersections,!0),s(e,"scroll",this._checkForIntersections,!0),"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},i.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,h(t,"resize",this._checkForIntersections,!0),h(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},i.prototype._checkForIntersections=function(){var t=this._rootIsInDom(),e=t?this._getRootRect():a();this._observationTargets.forEach(function(i){var r=i.element,s=u(r),h=this._rootContainsTarget(r),c=i.entry,a=t&&h&&this._computeTargetAndRootIntersection(r,e),l=i.entry=new n({time:o(),target:r,boundingClientRect:s,rootBounds:e,intersectionRect:a});c?t&&h?this._hasCrossedThreshold(c,l)&&this._queuedEntries.push(l):c&&c.isIntersecting&&this._queuedEntries.push(l):this._queuedEntries.push(l)},this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},i.prototype._computeTargetAndRootIntersection=function(n,i){if("none"!=t.getComputedStyle(n).display){for(var o=u(n),r=o,s=p(n),h=!1;!h;){var a=null,l=1==s.nodeType?t.getComputedStyle(s):{};if("none"==l.display)return;if(s==this.root||s==e?(h=!0,a=i):s!=e.body&&s!=e.documentElement&&"visible"!=l.overflow&&(a=u(s)),a&&(r=c(a,r),!r))break;s=p(s)}return r}},i.prototype._getRootRect=function(){var t;if(this.root)t=u(this.root);else{var n=e.documentElement,i=e.body;t={top:0,left:0,right:n.clientWidth||i.clientWidth,width:n.clientWidth||i.clientWidth,bottom:n.clientHeight||i.clientHeight,height:n.clientHeight||i.clientHeight}}return this._expandRectByRootMargin(t)},i.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map(function(e,n){return"px"==e.unit?e.value:e.value*(n%2?t.width:t.height)/100}),n={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},i.prototype._hasCrossedThreshold=function(t,e){var n=t&&t.isIntersecting?t.intersectionRatio||0:-1,i=e.isIntersecting?e.intersectionRatio||0:-1;if(n!==i)for(var o=0;o<this.thresholds.length;o++){var r=this.thresholds[o];if(r==n||r==i||n>r!=i>r)return!0}},i.prototype._rootIsInDom=function(){return!this.root||l(e,this.root)},i.prototype._rootContainsTarget=function(t){return l(this.root||e,t)},i.prototype._registerInstance=function(){f.indexOf(this)<0&&f.push(this)},i.prototype._unregisterInstance=function(){var t=f.indexOf(this);-1!=t&&f.splice(t,1)},t.IntersectionObserver=i,t.IntersectionObserverEntry=n}(window,document);
 +
 +
/* Helpers */
 +
 +
function dragElement(el, events) {
 +
 +
  function getPointer(e) {
 +
    var x = 'clientX';
 +
    var y = 'clientY';
 +
    var evt = e.touches ? e.touches[0] : e;
 +
    return { x: evt[x], y: evt[y] };
 +
  }
 +
 +
  var drag = { x: 0, y: 0, deltaX: 0, deltaY: 0, active: true, events: events || {} };
 +
  var originalX = 0;
 +
  var originalY = 0;
 +
  var pointerX = 0;
 +
  var pointerY = 0;
 +
 +
  function move(e) {
 +
    if (drag.active) return;
 +
    drag.deltaX = pointerX - getPointer(e).x;
 +
    drag.deltaY = pointerY - getPointer(e).y;
 +
    drag.x = originalX - drag.deltaX;
 +
    drag.y = originalY - drag.deltaY;
 +
    if (drag.events.move) drag.events.move(drag);
 +
  }
 +
 +
  function release(e) {
 +
    drag.active = true;
 +
    if (drag.events.release) drag.events.release(drag);
 +
    document.removeEventListener('mousemove', move, false);
 +
    document.removeEventListener('mouseup', release, false);
 +
    document.removeEventListener('touchmove', move, false);
 +
    document.removeEventListener('touchend', release, false);
 +
  }
 +
 +
  function start(e) {
 +
    if (!drag.active) return;
 +
    e.preventDefault();
 +
    drag.active = false;
 +
    pointerX = getPointer(e).x;
 +
    pointerY = getPointer(e).y;
 +
    originalX = drag.x;
 +
    originalY = drag.y;
 +
    if (drag.events.begin) drag.events.begin(drag);
 +
    document.addEventListener('mousemove', move, false);
 +
    document.addEventListener('mouseup', release, false);
 +
    document.addEventListener('touchmove', move, false);
 +
    document.addEventListener('touchend', release, false);
 +
  }
 +
 +
  el.addEventListener('mousedown', start, false);
 +
  el.addEventListener('touchstart', start, false);
 +
 +
  return drag;
 +
 +
}
 +
 +
// Better scroll events
 +
 +
function onScroll(cb) {
 +
  var isTicking = false;
 +
  var scrollY = 0;
 +
  var body = document.body;
 +
  var html = document.documentElement;
 +
  var scrollHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
 +
  function scroll() {
 +
    scrollY = window.scrollY;
 +
    if (cb) cb(scrollY, scrollHeight);
 +
    requestTick();
 +
  }
 +
  function requestTick() {
 +
    if (!isTicking) requestAnimationFrame(updateScroll);
 +
    isTicking = true;
 +
  }
 +
  function updateScroll() {
 +
    isTicking = false;
 +
    var currentScrollY = scrollY;
 +
  }
 +
  scroll();
 +
  window.onscroll = scroll;
 +
}
 +
 +
// Scroll to element
 +
 +
function scrollToElement(el, offset) {
 +
  var off = offset || 0;
 +
  var rect = el.getBoundingClientRect();
 +
  var top = rect.top + off;
 +
  var animation = anime({
 +
    targets: [document.body, document.documentElement],
 +
    scrollTop: '+='+top,
 +
    easing: 'easeInOutSine',
 +
    duration: 1500
 +
  });
 +
  // onScroll(animation.pause);
 +
}
 +
 +
// Check if element is in viewport
 +
 +
function isElementInViewport(el, inCB, outCB, rootMargin) {
 +
  var margin = rootMargin || '-10%';
 +
  function handleIntersect(entries, observer) {
 +
    var entry = entries[0];
 +
    if (entry.isIntersecting) {
 +
      if (inCB && typeof inCB === 'function') inCB(el, entry);
 +
    } else {
 +
      if (outCB && typeof outCB === 'function') outCB(el, entry);
 +
    }
 +
  }
 +
  var observer = new IntersectionObserver(handleIntersect, {rootMargin: margin});
 +
  observer.observe(el);
 +
}
 +
 +
function fitElementToParent(el, padding, exception) {
 +
  let windowWidth = 0;
 +
  let timeout = 0;
 +
  function resize() {
 +
    anime.set(el, {scale: 1});
 +
    if (exception) anime.set(exception, {scale: 1});
 +
    var pad = padding || 0;
 +
    var parentEl = el.parentNode;
 +
    var elOffsetWidth = el.offsetWidth - pad;
 +
    var parentOffsetWidth = parentEl.offsetWidth;
 +
    var ratio = parentOffsetWidth / elOffsetWidth;
 +
    var invertedRatio = elOffsetWidth / parentOffsetWidth;
 +
    anime.set(el, {scale: ratio});
 +
    if (exception) anime.set(exception, {scale: invertedRatio});
 +
  }
 +
  resize();
 +
  window.addEventListener('resize', function() {
 +
    if (window.innerWidth === windowWidth) return;
 +
    clearTimeout(timeout);
 +
    timeout = setTimeout(function() {
 +
      windowWidth = window.innerWidth;
 +
      resize();
 +
    }, 15);
 +
  });
 +
}
 +
</syntaxhighlight>

Aktuelle Version vom 17. Januar 2021, 08:38 Uhr

Anime.js ist ein Animation Framework.

Links[Bearbeiten]

https://animejs.com/
https://www.youtube.com/watch?v=uRDLFXxihgc - guter Einstieg
https://codepen.io/rexjbull/pen/RwRRezq Beispiel mit Scrollmagic
http://snapsvg.io/ SVG Tools

Quickstart[Bearbeiten]

  • create anime object

anime({});

  • pass configuration object
    • target (CSS selector)
    • css properties die animiert werden sollen
anime({
  targets: '.square',
  translateX: '250px',
});

Mehr Properties[Bearbeiten]

anime({
  targets: '.square',
  translateX: '250px',
  rotateZ: 360,
  scale: 2,
  loop: true,
  duration: 5000,
});

Besonderheiten[Bearbeiten]

Anime.js kann einige besondere Dinge:

  • Animieren von JavaScript Objekten (mit mindestens einem Zahlenwert)
  • Animieren von DOM Attributen

Staggering[Bearbeiten]

https://animejs.com/documentation/#staggeringBasics


Morphing SVG[Bearbeiten]

https://codepen.io/kholja/pen/KKgbBQe

Anime.js kann im Prinzip alle Werte in Bereichen verändern. Das funktioniert auch mit dem d Attribut in SVG Path Elementen oder Polygonen etc. Dabei sind ein paar Vorarbeiten notwendig:

  • Punktanzahl der Pfade sollte gleich sein.
  • Bei Pfaden kann es bei relativen Pfadangaben Probleme geben
  • Bei Punkten die mit H oder V (Horizontal, Vertikal) angegeben sind gibt es nur eine statt zwei Koordinaten. Das kann dazu führen dass unterschiedliche viele Werte entstehen.

Im Vergleich zum GSAP Morph Plugin ist Anime.js deutlich unflexibler. Performance ist aber OK und es ist kostenfrei. Für kleine Morphs durchaus geeignet. Beispiel

<div>
    <button id="b1">Play</button>
  </div>
  <div id="ani1">
    <svg xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" stroke-miterlimit="5" clip-rule="evenodd" viewBox="0 0 282 181">
      <path fill="none" stroke="#000" stroke-width="2" d="M2 178L70 61l21 37 7-12 19 32 9 15 20-33 13 23 54-93 22 37 8-14 36 64"/>
  </svg>
 </div>
var ani1 = anime({
  targets: document.querySelector("#ani1 path"),
  // using range [] on 2 paths here, coordinates are converted to absolute values.
  d: [
    "M 0,178 L 70,61 L 91,98 L 98,86 L 117,118 L 126,133 L 146,100 L 159,123 L 213,30 L 235,67 L 243,53 L 279,117",
    "M 0,178 L 73,99 L 92,120 L 98,120 L 106,133 L 134,2 L 164,178L180,120 L197,120L212,102 L224,116 L279,116"], 
  easing: 'easeInOutCubic',
  duration: 1000,
  autoplay: false,
  loop: true,
  direction: 'alternate',
  delay: 1000,
  endDelay:500,
});

document.querySelector('#b1').onclick = ani1.play;

Helpüers[Bearbeiten]

// import anime from '../../../src/index.js';

/* Ontersection observer */

!function(t,e){"use strict";function n(t){this.time=t.time,this.target=t.target,this.rootBounds=t.rootBounds,this.boundingClientRect=t.boundingClientRect,this.intersectionRect=t.intersectionRect||a(),this.isIntersecting=!!t.intersectionRect;var e=this.boundingClientRect,n=e.width*e.height,i=this.intersectionRect,o=i.width*i.height;n?this.intersectionRatio=o/n:this.intersectionRatio=this.isIntersecting?1:0}function i(t,e){var n=e||{};if("function"!=typeof t)throw new Error("callback must be a function");if(n.root&&1!=n.root.nodeType)throw new Error("root must be an Element");this._checkForIntersections=r(this._checkForIntersections.bind(this),this.THROTTLE_TIMEOUT),this._callback=t,this._observationTargets=[],this._queuedEntries=[],this._rootMarginValues=this._parseRootMargin(n.rootMargin),this.thresholds=this._initThresholds(n.threshold),this.root=n.root||null,this.rootMargin=this._rootMarginValues.map(function(t){return t.value+t.unit}).join(" ")}function o(){return t.performance&&performance.now&&performance.now()}function r(t,e){var n=null;return function(){n||(n=setTimeout(function(){t(),n=null},e))}}function s(t,e,n,i){"function"==typeof t.addEventListener?t.addEventListener(e,n,i||!1):"function"==typeof t.attachEvent&&t.attachEvent("on"+e,n)}function h(t,e,n,i){"function"==typeof t.removeEventListener?t.removeEventListener(e,n,i||!1):"function"==typeof t.detatchEvent&&t.detatchEvent("on"+e,n)}function c(t,e){var n=Math.max(t.top,e.top),i=Math.min(t.bottom,e.bottom),o=Math.max(t.left,e.left),r=Math.min(t.right,e.right),s=r-o,h=i-n;return s>=0&&h>=0&&{top:n,bottom:i,left:o,right:r,width:s,height:h}}function u(t){var e;try{e=t.getBoundingClientRect()}catch(n){}return e?(e.width&&e.height||(e={top:e.top,right:e.right,bottom:e.bottom,left:e.left,width:e.right-e.left,height:e.bottom-e.top}),e):a()}function a(){return{top:0,bottom:0,left:0,right:0,width:0,height:0}}function l(t,e){for(var n=e;n;){if(n==t)return!0;n=p(n)}return!1}function p(t){var e=t.parentNode;return e&&11==e.nodeType&&e.host?e.host:e}if("IntersectionObserver"in t&&"IntersectionObserverEntry"in t&&"intersectionRatio"in t.IntersectionObserverEntry.prototype)return void("isIntersecting"in t.IntersectionObserverEntry.prototype||Object.defineProperty(t.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}}));var f=[];i.prototype.THROTTLE_TIMEOUT=100,i.prototype.POLL_INTERVAL=null,i.prototype.observe=function(t){var e=this._observationTargets.some(function(e){return e.element==t});if(!e){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},i.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter(function(e){return e.element!=t}),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},i.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},i.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},i.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter(function(t,e,n){if("number"!=typeof t||isNaN(t)||0>t||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==n[e-1]})},i.prototype._parseRootMargin=function(t){var e=t||"0px",n=e.split(/\s+/).map(function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}});return n[1]=n[1]||n[0],n[2]=n[2]||n[0],n[3]=n[3]||n[1],n},i.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(s(t,"resize",this._checkForIntersections,!0),s(e,"scroll",this._checkForIntersections,!0),"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},i.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,h(t,"resize",this._checkForIntersections,!0),h(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},i.prototype._checkForIntersections=function(){var t=this._rootIsInDom(),e=t?this._getRootRect():a();this._observationTargets.forEach(function(i){var r=i.element,s=u(r),h=this._rootContainsTarget(r),c=i.entry,a=t&&h&&this._computeTargetAndRootIntersection(r,e),l=i.entry=new n({time:o(),target:r,boundingClientRect:s,rootBounds:e,intersectionRect:a});c?t&&h?this._hasCrossedThreshold(c,l)&&this._queuedEntries.push(l):c&&c.isIntersecting&&this._queuedEntries.push(l):this._queuedEntries.push(l)},this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},i.prototype._computeTargetAndRootIntersection=function(n,i){if("none"!=t.getComputedStyle(n).display){for(var o=u(n),r=o,s=p(n),h=!1;!h;){var a=null,l=1==s.nodeType?t.getComputedStyle(s):{};if("none"==l.display)return;if(s==this.root||s==e?(h=!0,a=i):s!=e.body&&s!=e.documentElement&&"visible"!=l.overflow&&(a=u(s)),a&&(r=c(a,r),!r))break;s=p(s)}return r}},i.prototype._getRootRect=function(){var t;if(this.root)t=u(this.root);else{var n=e.documentElement,i=e.body;t={top:0,left:0,right:n.clientWidth||i.clientWidth,width:n.clientWidth||i.clientWidth,bottom:n.clientHeight||i.clientHeight,height:n.clientHeight||i.clientHeight}}return this._expandRectByRootMargin(t)},i.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map(function(e,n){return"px"==e.unit?e.value:e.value*(n%2?t.width:t.height)/100}),n={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},i.prototype._hasCrossedThreshold=function(t,e){var n=t&&t.isIntersecting?t.intersectionRatio||0:-1,i=e.isIntersecting?e.intersectionRatio||0:-1;if(n!==i)for(var o=0;o<this.thresholds.length;o++){var r=this.thresholds[o];if(r==n||r==i||n>r!=i>r)return!0}},i.prototype._rootIsInDom=function(){return!this.root||l(e,this.root)},i.prototype._rootContainsTarget=function(t){return l(this.root||e,t)},i.prototype._registerInstance=function(){f.indexOf(this)<0&&f.push(this)},i.prototype._unregisterInstance=function(){var t=f.indexOf(this);-1!=t&&f.splice(t,1)},t.IntersectionObserver=i,t.IntersectionObserverEntry=n}(window,document);

/* Helpers */

function dragElement(el, events) {

  function getPointer(e) {
    var x = 'clientX';
    var y = 'clientY';
    var evt = e.touches ? e.touches[0] : e;
    return { x: evt[x], y: evt[y] };
  }

  var drag = { x: 0, y: 0, deltaX: 0, deltaY: 0, active: true, events: events || {} };
  var originalX = 0;
  var originalY = 0;
  var pointerX = 0;
  var pointerY = 0;

  function move(e) {
    if (drag.active) return;
    drag.deltaX = pointerX - getPointer(e).x;
    drag.deltaY = pointerY - getPointer(e).y;
    drag.x = originalX - drag.deltaX;
    drag.y = originalY - drag.deltaY;
    if (drag.events.move) drag.events.move(drag);
  }

  function release(e) {
    drag.active = true;
    if (drag.events.release) drag.events.release(drag);
    document.removeEventListener('mousemove', move, false);
    document.removeEventListener('mouseup', release, false);
    document.removeEventListener('touchmove', move, false);
    document.removeEventListener('touchend', release, false);
  }

  function start(e) {
    if (!drag.active) return;
    e.preventDefault();
    drag.active = false;
    pointerX = getPointer(e).x;
    pointerY = getPointer(e).y;
    originalX = drag.x;
    originalY = drag.y;
    if (drag.events.begin) drag.events.begin(drag);
    document.addEventListener('mousemove', move, false);
    document.addEventListener('mouseup', release, false);
    document.addEventListener('touchmove', move, false);
    document.addEventListener('touchend', release, false);
  }

  el.addEventListener('mousedown', start, false);
  el.addEventListener('touchstart', start, false);

  return drag;

}

// Better scroll events

function onScroll(cb) {
  var isTicking = false;
  var scrollY = 0;
  var body = document.body;
  var html = document.documentElement;
  var scrollHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
  function scroll() {
    scrollY = window.scrollY;
    if (cb) cb(scrollY, scrollHeight);
    requestTick();
  }
  function requestTick() {
    if (!isTicking) requestAnimationFrame(updateScroll);
    isTicking = true;
  }
  function updateScroll() {
    isTicking = false;
    var currentScrollY = scrollY;
  }
  scroll();
  window.onscroll = scroll;
}

// Scroll to element

function scrollToElement(el, offset) {
  var off = offset || 0;
  var rect = el.getBoundingClientRect();
  var top = rect.top + off;
  var animation = anime({
    targets: [document.body, document.documentElement],
    scrollTop: '+='+top,
    easing: 'easeInOutSine',
    duration: 1500
  });
  // onScroll(animation.pause);
}

// Check if element is in viewport

function isElementInViewport(el, inCB, outCB, rootMargin) {
  var margin = rootMargin || '-10%';
  function handleIntersect(entries, observer) {
    var entry = entries[0];
    if (entry.isIntersecting) {
      if (inCB && typeof inCB === 'function') inCB(el, entry);
    } else {
      if (outCB && typeof outCB === 'function') outCB(el, entry);
    }
  }
  var observer = new IntersectionObserver(handleIntersect, {rootMargin: margin});
  observer.observe(el);
}

function fitElementToParent(el, padding, exception) {
  let windowWidth = 0;
  let timeout = 0;
  function resize() {
    anime.set(el, {scale: 1});
    if (exception) anime.set(exception, {scale: 1});
    var pad = padding || 0;
    var parentEl = el.parentNode;
    var elOffsetWidth = el.offsetWidth - pad;
    var parentOffsetWidth = parentEl.offsetWidth;
    var ratio = parentOffsetWidth / elOffsetWidth;
    var invertedRatio = elOffsetWidth / parentOffsetWidth;
    anime.set(el, {scale: ratio});
    if (exception) anime.set(exception, {scale: invertedRatio});
  }
  resize();
  window.addEventListener('resize', function() {
    if (window.innerWidth === windowWidth) return;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      windowWidth = window.innerWidth;
      resize();
    }, 15);
  });
}