magnetic-hover.js
Version:
Lightweight magnetic text hover effect animation library
8 lines (7 loc) • 5.24 kB
JavaScript
/**
* magnetic-hover.js - Lightweight magnetic text hover effect animation library
* @version 1.0.0
* @author tizee
* @license MIT
*/
var c=Object.defineProperty;var h=Object.getOwnPropertySymbols;var m=Object.prototype.hasOwnProperty,u=Object.prototype.propertyIsEnumerable;var d=(n,t,e)=>t in n?c(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e,a=(n,t)=>{for(var e in t||(t={}))m.call(t,e)&&d(n,e,t[e]);if(h)for(var e of h(t))u.call(t,e)&&d(n,e,t[e]);return n};var p=(n,t)=>()=>(t||n((t={exports:{}}).exports,t),t.exports);var f=p((g,l)=>{var r=class{constructor(t,e={}){this.defaults={maxScaleX:1.12,minScaleX:1,maxScaleY:1,minScaleY:.9,maxStroke:.1,minStroke:0,maxPaddingInline:.1,minPaddingInline:0,effectRadius:120,smoothing:.12,charClassName:"maghover-char",throttleDelay:16},this.options=a(a({},this.defaults),e),this.elements=typeof t=="string"?document.querySelectorAll(t):[t],this.mousePos={x:0,y:0},this.chars=[],this.isActive=!1,this.animationFrameId=null,this.handleMouseMove=this.throttle(this.onMouseMove.bind(this),this.options.throttleDelay),this.handleResize=this.throttle(this.updateCharPositions.bind(this),100),this.handleScroll=this.throttle(this.updateCharPositions.bind(this),16),this.init()}init(){this.elements.length!==0&&(this.splitTextIntoChars(),this.bindEvents(),this.start())}splitTextIntoChars(){this.elements.forEach(t=>{let e=t.textContent.trim();t.innerHTML="",[...e].forEach(i=>{let s=document.createElement("span");s.className=this.options.charClassName,s.textContent=i===" "?"\xA0":i,s.style.display="inline-block",s.style.webkitTextStroke=`${this.options.minStroke}em`,s.style.transform=`scaleX(${this.options.minScaleX}) scaleY(${this.options.maxScaleY})`;let o={element:s,parent:t,targetScaleX:this.options.minScaleX,targetScaleY:this.options.maxScaleY,currentScaleX:this.options.minScaleX,currentScaleY:this.options.maxScaleY,targetStroke:this.options.minStroke,currentStroke:this.options.minStroke,targetPaddingInline:this.options.minPaddingInline,currentPaddingInline:this.options.minPaddingInline,rect:null};this.chars.push(o),t.appendChild(s)})})}bindEvents(){document.addEventListener("mousemove",this.handleMouseMove),window.addEventListener("resize",this.handleResize),window.addEventListener("scroll",this.handleScroll,{passive:!0}),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{setTimeout(()=>this.updateCharPositions(),100)}):setTimeout(()=>this.updateCharPositions(),100)}onMouseMove(t){this.mousePos.x=t.clientX,this.mousePos.y=t.clientY}updateCharPositions(){this.chars.forEach(t=>{t.rect=t.element.getBoundingClientRect()})}calculateDistance(t,e,i,s){return Math.sqrt(Math.pow(i-t,2)+Math.pow(s-e,2))}easeOutQuart(t){return 1-Math.pow(1-t,4)}lerp(t,e,i){return t+(e-t)*i}updateEffects(){this.chars.forEach(t=>{if(!t.rect)return;let e=t.rect.left+t.rect.width/2,i=t.rect.top+t.rect.height/2,s=this.calculateDistance(this.mousePos.x,this.mousePos.y,e,i),o=0;s<this.options.effectRadius&&(o=1-s/this.options.effectRadius,o=this.easeOutQuart(o)),t.targetScaleX=this.lerp(this.options.minScaleX,this.options.maxScaleX,o),t.targetScaleY=this.lerp(this.options.maxScaleY,this.options.minScaleY,o),t.targetStroke=this.lerp(this.options.minStroke,this.options.maxStroke,o),t.targetPaddingInline=this.lerp(this.options.minPaddingInline,this.options.maxPaddingInline,o),t.currentScaleX=this.lerp(t.currentScaleX,t.targetScaleX,this.options.smoothing),t.currentScaleY=this.lerp(t.currentScaleY,t.targetScaleY,this.options.smoothing),t.currentStroke=this.lerp(t.currentStroke,t.targetStroke,this.options.smoothing),t.currentPaddingInline=this.lerp(t.currentPaddingInline,t.targetPaddingInline,this.options.smoothing),t.element.style.transform=`scaleX(${t.currentScaleX}) scaleY(${t.currentScaleY})`,t.element.style.webkitTextStroke=`${t.currentStroke}em`,t.element.style.paddingInline=`${t.currentPaddingInline}em`})}animate(){this.isActive&&(this.updateEffects(),this.animationFrameId=requestAnimationFrame(()=>this.animate()))}throttle(t,e){let i;return function(...s){i||(t.apply(this,s),i=!0,setTimeout(()=>i=!1,e))}}start(){this.isActive||(this.isActive=!0,this.animate())}stop(){this.isActive=!1,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restart(){this.stop(),this.start()}updateOptions(t){this.options=a(a({},this.options),t),t.throttleDelay!==void 0&&(document.removeEventListener("mousemove",this.handleMouseMove),this.handleMouseMove=this.throttle(this.onMouseMove.bind(this),this.options.throttleDelay),document.addEventListener("mousemove",this.handleMouseMove)),this.updateCharPositions()}destroy(){this.stop(),document.removeEventListener("mousemove",this.handleMouseMove),window.removeEventListener("resize",this.handleResize),window.removeEventListener("scroll",this.handleScroll),this.elements.forEach(t=>{let e=this.chars.filter(i=>i.parent===t).map(i=>i.element.textContent==="\xA0"?" ":i.element.textContent).join("");t.innerHTML=e}),this.chars=[],this.elements=[]}static get version(){return"1.0.0"}};typeof l!="undefined"&&l.exports?l.exports=r:typeof define=="function"&&define.amd?define([],function(){return r}):window.MagneticHover=r});export default f();