cursor-blob
Version:
Lightweight library for animated, interactive cursors using GSAP
2 lines (1 loc) • 2.02 kB
JavaScript
"use strict";const h=require("gsap"),c=.1,m=485,u=.35,l=180,p=Math.PI,S=.95,n=2;class e{static gsap=h;cursor;cursorRim;cursorDot;duration;ease;pos={x:0,y:0};vel={x:0,y:0};animFrame=null;boundMove=this.setFromEvent.bind(this);rimX;rimY;rimRotate;rimScaleX;rimScaleY;dotX;dotY;static registerGSAP(t){e.gsap=t}static getScale(t,s){const i=Math.hypot(t,s);return Math.min(i/m,u)}static getAngle(t,s){return Math.atan2(s,t)*l/p}constructor({cursorEl:t,cursorRimEl:s,cursorDotEl:i,duration:o=S,ease:r="expo.out"}){this.cursor=t,this.cursorRim=s,this.cursorDot=i,this.duration=o,this.ease=r,this.setupQuickSetters(),window.addEventListener("pointermove",this.boundMove),this.animate()}setupQuickSetters(){const t=e.gsap;this.rimX=t.quickSetter(this.cursorRim,"x","px"),this.rimY=t.quickSetter(this.cursorRim,"y","px"),this.rimRotate=t.quickSetter(this.cursorRim,"rotate","deg"),this.rimScaleX=t.quickSetter(this.cursorRim,"scaleX"),this.rimScaleY=t.quickSetter(this.cursorRim,"scaleY"),this.dotX=t.quickSetter(this.cursorDot,"x","px"),this.dotY=t.quickSetter(this.cursorDot,"y","px")}loop(){const{x:t,y:s}=this.pos,{x:i,y:o}=this.vel,r=e.getAngle(i,o),a=e.getScale(i,o);this.rimX(t),this.rimY(s),this.rimRotate(r),this.rimScaleX(1+a),this.rimScaleY(1-a),this.dotX(t+i*c),this.dotY(s+o*c)}animate=()=>{this.loop(),this.animFrame=requestAnimationFrame(this.animate)};setFromEvent(t){const{clientX:s,clientY:i}=t,o=this.cursorRim.offsetWidth/n,r=this.cursorRim.offsetHeight/n;e.gsap.killTweensOf(this.pos),e.gsap.to(this.pos,{x:s-o,y:i-r,duration:this.duration,ease:this.ease,onUpdate:()=>{this.vel.x=s-o-this.pos.x,this.vel.y=i-r-this.pos.y,this.applyStyle(t)}})}applyStyle(t){let s=t.target;for(;s&&!s.dataset?.cursorStyle&&s!==document.body;)s=s.parentElement;const i=s?.dataset?.cursorStyle??"default";this.cursor.className=`cursor cursor--${i}`}destroy(){window.removeEventListener("pointermove",this.boundMove),e.gsap.killTweensOf(this.pos),this.animFrame!==null&&cancelAnimationFrame(this.animFrame)}}module.exports=e;