UNPKG

atropos

Version:

Touch-friendly 3D parallax hover effects

13 lines (12 loc) 9.57 kB
/** * Atropos 2.0.2 * Touch-friendly 3D parallax hover effects * https://atroposjs.com * * Copyright 2021-2023 * * Released under the MIT License * * Released on: July 4, 2023 */ !function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){"use strict";const t=(t,e)=>t.querySelector(e),e=(t={})=>{const e={};return Object.keys(t).forEach((o=>{void 0!==t[o]&&(e[o]=t[o])})),e},o={alwaysActive:!1,activeOffset:50,shadowOffset:50,shadowScale:1,duration:300,rotate:!0,rotateTouch:!0,rotateXMax:15,rotateYMax:15,rotateXInvert:!1,rotateYInvert:!1,stretchX:0,stretchY:0,stretchZ:0,commonOrigin:!0,shadow:!0,highlight:!0};function a(a={}){let{el:s,eventsEl:n}=a;const{isComponent:r}=a;let i;const p={__atropos__:!0,params:{...o,onEnter:null,onLeave:null,onRotate:null,...e(a||{})},destroyed:!1,isActive:!1},{params:c}=p;let l,d,h,u,f,m,v,y,g,w;const x=[];let b;const M=()=>{b=requestAnimationFrame((()=>{x.forEach((t=>{if("function"==typeof t)t();else{const{element:e,prop:o,value:a}=t;e.style[o]=a}})),x.splice(0,x.length),M()}))};M();const $=(t,e)=>{x.push({element:t,prop:"transitionDuration",value:e})},E=(t,e)=>{x.push({element:t,prop:"transitionTimingFunction",value:e})},L=(t,e)=>{x.push({element:t,prop:"transform",value:e})},C=(t,e)=>{x.push({element:t,prop:"opacity",value:e})},O=(t,e,o,a)=>t.addEventListener(e,o,a),S=(t,e,o,a)=>t.removeEventListener(e,o,a),T=({rotateXPercentage:t=0,rotateYPercentage:e=0,duration:o,opacityOnly:a,easeOut:s})=>{((t,e)=>t.querySelectorAll(e))(i,"[data-atropos-offset], [data-atropos-opacity]").forEach((n=>{$(n,o),E(n,s?"ease-out":"");const r=(t=>{if(t.dataset.atroposOpacity&&"string"==typeof t.dataset.atroposOpacity)return t.dataset.atroposOpacity.split(";").map((t=>parseFloat(t)))})(n);if(0===t&&0===e)a||L(n,"translate3d(0, 0, 0)"),r&&C(n,r[0]);else{const o=parseFloat(n.dataset.atroposOffset)/100;if(Number.isNaN(o)||a||L(n,`translate3d(${-e*-o}%, ${t*-o}%, 0)`),r){const[o,a]=r,s=Math.max(Math.abs(t),Math.abs(e));C(n,o+(a-o)*s/100)}}}))},X=(t,e)=>{const o=s!==n;if(u||(u=s.getBoundingClientRect()),o&&!f&&(f=n.getBoundingClientRect()),void 0===t&&void 0===e){const a=o?f:u;t=a.left+a.width/2,e=a.top+a.height/2}let a=0,r=0;const{top:i,left:p,width:d,height:h}=u;let m;if(o){const{top:o,left:s,width:n,height:l}=f,u=d/2+(p-s),v=h/2+(i-o),y=t-s,g=e-o;r=c.rotateYMax*(y-u)/(n-d/2)*-1,a=c.rotateXMax*(g-v)/(l-h/2),m=`${t-p}px ${e-i}px`}else{const o=d/2,s=h/2,n=t-p,l=e-i;r=c.rotateYMax*(n-o)/(d/2)*-1,a=c.rotateXMax*(l-s)/(h/2)}a=Math.min(Math.max(-a,-c.rotateXMax),c.rotateXMax),c.rotateXInvert&&(a=-a),r=Math.min(Math.max(-r,-c.rotateYMax),c.rotateYMax),c.rotateYInvert&&(r=-r);const y=a/c.rotateXMax*100,g=r/c.rotateYMax*100,w=(o?g/100*c.stretchX:0)*(c.rotateYInvert?-1:1),b=(o?y/100*c.stretchY:0)*(c.rotateXInvert?-1:1),M=o?Math.max(Math.abs(y),Math.abs(g))/100*c.stretchZ:0;var O,S;L(l,`translate3d(${w}%, ${-b}%, ${-M}px) rotateX(${a}deg) rotateY(${r}deg)`),m&&c.commonOrigin&&(O=l,S=m,x.push({element:O,prop:"transformOrigin",value:S})),v&&($(v,`${c.duration}ms`),E(v,"ease-out"),L(v,`translate3d(${.25*-g}%, ${.25*y}%, 0)`),C(v,Math.max(Math.abs(y),Math.abs(g))/100)),T({rotateXPercentage:y,rotateYPercentage:g,duration:`${c.duration}ms`,easeOut:!0}),"function"==typeof c.onRotate&&c.onRotate(a,r)},Y=()=>{x.push((()=>s.classList.add("atropos-active"))),$(l,`${c.duration}ms`),E(l,"ease-out"),L(d,`translate3d(0,0, ${c.activeOffset}px)`),$(d,`${c.duration}ms`),E(d,"ease-out"),m&&($(m,`${c.duration}ms`),E(m,"ease-out")),p.isActive=!0},k=t=>{if(y=void 0,!("pointerdown"===t.type&&"mouse"===t.pointerType||"pointerenter"===t.type&&"mouse"!==t.pointerType)){if("pointerdown"===t.type&&t.preventDefault(),g=t.clientX,w=t.clientY,c.alwaysActive)return u=void 0,void(f=void 0);Y(),"function"==typeof c.onEnter&&c.onEnter()}},_=t=>{!1===y&&t.cancelable&&t.preventDefault()},A=t=>{if(!c.rotate||!p.isActive)return;if("mouse"!==t.pointerType){if(!c.rotateTouch)return;t.preventDefault()}const{clientX:e,clientY:o}=t,a=e-g,n=o-w;if("string"==typeof c.rotateTouch&&(0!==a||0!==n)&&void 0===y){if(a*a+n*n>=25){const t=180*Math.atan2(Math.abs(n),Math.abs(a))/Math.PI;y="scroll-y"===c.rotateTouch?t>45:90-t>45}!1===y&&(s.classList.add("atropos-rotate-touch"),t.cancelable&&t.preventDefault())}"mouse"!==t.pointerType&&y||X(e,o)},R=t=>{if(u=void 0,f=void 0,p.isActive&&!(t&&"pointerup"===t.type&&"mouse"===t.pointerType||t&&"pointerleave"===t.type&&"mouse"!==t.pointerType)){if("string"==typeof c.rotateTouch&&y&&s.classList.remove("atropos-rotate-touch"),c.alwaysActive)return X(),"function"==typeof c.onRotate&&c.onRotate(0,0),void("function"==typeof c.onLeave&&c.onLeave());x.push((()=>s.classList.remove("atropos-active"))),$(d,`${c.duration}ms`),E(d,""),L(d,"translate3d(0,0, 0px)"),m&&($(m,`${c.duration}ms`),E(m,"")),v&&($(v,`${c.duration}ms`),E(v,""),L(v,"translate3d(0, 0, 0)"),C(v,0)),$(l,`${c.duration}ms`),E(l,""),L(l,"translate3d(0,0,0) rotateX(0deg) rotateY(0deg)"),T({duration:`${c.duration}ms`}),p.isActive=!1,"function"==typeof c.onRotate&&c.onRotate(0,0),"function"==typeof c.onLeave&&c.onLeave()}},I=t=>{const e=t.target;!n.contains(e)&&e!==n&&p.isActive&&R()};return p.destroy=()=>{p.destroyed=!0,cancelAnimationFrame(b),S(document,"click",I),S(n,"pointerdown",k),S(n,"pointerenter",k),S(n,"pointermove",A),S(n,"touchmove",_),S(n,"pointerleave",R),S(n,"pointerup",R),S(n,"lostpointercapture",R),delete s.__atropos__},"string"==typeof s&&(s=t(document,s)),s&&(s.__atropos__||(void 0!==n?"string"==typeof n&&(n=t(document,n)):n=s,i=r?s.parentNode.host:s,Object.assign(p,{el:s}),l=t(s,".atropos-rotate"),d=t(s,".atropos-scale"),h=t(s,".atropos-inner"),s.__atropos__=p)),s&&n&&(c.shadow&&(()=>{let e;m=t(s,".atropos-shadow"),m||(m=document.createElement("span"),m.classList.add("atropos-shadow"),e=!0),L(m,`translate3d(0,0,-${c.shadowOffset}px) scale(${c.shadowScale})`),e&&l.appendChild(m)})(),c.highlight&&(()=>{let e;v=t(s,".atropos-highlight"),v||(v=document.createElement("span"),v.classList.add("atropos-highlight"),e=!0),L(v,"translate3d(0,0,0)"),e&&h.appendChild(v)})(),c.rotateTouch&&("string"==typeof c.rotateTouch?s.classList.add(`atropos-rotate-touch-${c.rotateTouch}`):s.classList.add("atropos-rotate-touch")),t(i,"[data-atropos-opacity]")&&T({opacityOnly:!0}),O(document,"click",I),O(n,"pointerdown",k),O(n,"pointerenter",k),O(n,"pointermove",A),O(n,"touchmove",_),O(n,"pointerleave",R),O(n,"pointerup",R),O(n,"lostpointercapture",R),c.alwaysActive&&(Y(),X())),p}const s=".atropos{position:relative;display:block;perspective:1200px;transform:translate3d(0,0,0)}.atropos-rotate-scroll-x,.atropos-rotate-scroll-y,.atropos-rotate-touch{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;user-select:none}.atropos-rotate-touch-scroll-y{touch-action:pan-y}.atropos-rotate-touch-scroll-x{touch-action:pan-x}.atropos-rotate-touch{touch-action:none}.atropos-rotate,.atropos-scale{width:100%;height:100%;transform-style:preserve-3d;transition-property:transform;display:block}.atropos-highlight,.atropos-shadow{position:absolute;pointer-events:none;transition-property:transform,opacity;display:block;opacity:0}.atropos-shadow{z-index:-1;background:#000;left:0;top:0;width:100%;height:100%;filter:blur(30px)}.atropos-highlight{left:-50%;top:-50%;width:200%;height:200%;background-image:radial-gradient(circle at 50%,rgba(255,255,255,.25),transparent 50%);z-index:0}.atropos-rotate{position:relative}.atropos-inner{width:100%;height:100%;position:relative;overflow:hidden;transform-style:preserve-3d;transform:translate3d(0,0,0);display:block}.atropos-active{z-index:1}.atropos-active .atropos-shadow{opacity:1!important}::slotted([data-atropos-offset]),[data-atropos-offset]{transition-property:transform}[data-atropos-opacity]{transition-property:opacity}::slotted([data-atropos-offset][data-atropos-opacity]),[data-atropos-offset][data-atropos-opacity]{transition-property:transform,opacity}";class n extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.init()}disconnectedCallback(){this.destroy()}init(){const t={...o},e={};Object.keys(t).forEach((o=>{const a=o.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`)),s=this.getAttribute(a);if(null===s)e[o]=t[o];else switch(typeof t[o]){case"boolean":e[o]="false"!==s;break;case"number":e[o]=isNaN(parseFloat(s,10))?t[o]:parseFloat(s,10);break;default:e[o]=s}}));const n=this.cls("atropos-inner",e.innerClass),r=document.createElement("div");if(r.classList.add("atropos"),r.innerHTML=`\n <div class="atropos-scale" part="scale">\n <div class="atropos-rotate" part="rotate">\n <div class="${n}" part="inner">\n <slot></slot>\n </div>\n <slot name="rotate"></slot>\n </div>\n <slot name="scale"></slot>\n </div>\n <slot name="root"></slot>\n `,this.shadow.innerHTML="","undefined"!=typeof CSSStyleSheet&&this.shadow.adoptedStyleSheets){const t=new CSSStyleSheet;t.replaceSync(s),this.shadow.adoptedStyleSheets=[t]}else{const t=document.createElement("style");t.rel="stylesheet",t.textContent=s,this.shadow.appendChild(t)}this.shadow.appendChild(r),this.atroposRef=a({el:r,isComponent:!0,...e,onEnter:()=>{this.dispatchEvent(new CustomEvent("enter"))},onLeave:()=>{this.dispatchEvent(new CustomEvent("leave"))},onRotate:(...t)=>{this.dispatchEvent(new CustomEvent("rotate",{detail:t}))}})}destroy(){this.atroposInstance&&(this.atroposInstance.destroy(),this.atroposInstance=null)}cls(...t){return t.filter((t=>!!t)).join(" ")}}customElements.define("atropos-component",n)}));