Anime.js: Unterschied zwischen den Versionen
Aus Wikizone
| (2 dazwischenliegende Versionen desselben Benutzers 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 67: | Zeile 68: | ||
var ani1 = anime({ | var ani1 = anime({ | ||
targets: document.querySelector("#ani1 path"), | targets: document.querySelector("#ani1 path"), | ||
| + | // using range [] on 2 paths here, coordinates are converted to absolute values. | ||
d: [ | 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 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"], | + | "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', | easing: 'easeInOutCubic', | ||
duration: 1000, | duration: 1000, | ||
| Zeile 80: | Zeile 82: | ||
document.querySelector('#b1').onclick = ani1.play; | 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> | </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);
});
}