Interactive Cursor Effects In jQuery And GSAP

File Size: 12.6 KB
Views Total: 2298
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Interactive Cursor Effects In jQuery And GSAP

A set of pretty cool custom cursors and interactive cursor effects implemented in jQuery and GSAP.

See Also:

Table Of Contents:

How to use it:

1. These custom cursor effects requires the latest jQuery and GSAP libraries.

<script src="/path/to/cdn/gsap.min.js"></script>
<script src="/path/to/cdn/jquery.min.js"></script>

2. Create a custom cursor that interacts with mouse movement. Live Demo.

Interactive Custom Cursor

/* Custom Cursor */
.custom-cursor, .custom-cursor-dot {
  position:fixed; z-index:999; top:0; left:0;
  transform:translate(-50%, -50%);
  pointer-events:none; opacity:0;
}

/* decorative */
.custom-cursor {
  width:62px; 
  height:62px; 
  border:1px solid #1c1c1c; 
  border-radius:50%;
}

.custom-cursor-dot {
  width:7px; 
  height:7px; 
  border-radius:50%; 
  background-color:#1c1c1c;
}
function customCursor(options) {
  let settings = $.extend({
      targetClass: 'custom-cursor', // create element with this class
      wrapper: $('body'), // jQuery
      speed: .1,
      movingDelay: 300, // fire event onStop after delay
      hasHover: false, // has hover events
      hoverTarget: $('a[href], button'),
      touchDevices: false, // show on touch devices
      onMove: function(data) {}
    }, options),
    data = {},
    checkTouch = !settings.touchDevices && "undefined" !== typeof document.documentElement.ontouchstart,
    timer = null;

  // exit
  if (checkTouch || !settings.wrapper.length) return;

  // append the ball
  settings.wrapper.append(`<div class="${settings.targetClass}"></div>`);

  let $cursor = $('.' + settings.targetClass),
    position = {
      x: window.innerWidth / 2,
      y: window.innerHeight / 2
    },
    mouse = {
      x: position.x,
      y: position.y
    },
    setX = gsap.quickSetter($cursor, "x", "px"),
    setY = gsap.quickSetter($cursor, "y", "px");

  // update data
  data.cursor = $cursor;

  // on mouse move
  window.addEventListener("mousemove", init);

  function init() {
    // remove default mousemove event
    window.removeEventListener("mousemove", init);

    // add new custom event
    window.addEventListener("mousemove", e => {
      mouse.x = e.x;
      mouse.y = e.y;

      // update data and trigger event
      data.isMoving = true;
      settings.onMove(data);

      timer = setTimeout(function() {
        // update data and trigger event
        data.isMoving = false;
        settings.onMove(data);
      }, settings.movingDelay);
    });

    // fade out cursor
    document.addEventListener("mouseleave", e => {
      // update data and trigger event
      data.isInViewport = false;
      settings.onMove(data);
    });

    // update cursor's position
    document.addEventListener("mouseenter", e => {
      mouse.x = position.x = e.x;
      mouse.y = position.y = e.y;

      // update data and trigger event
      data.isInViewport = true;
      settings.onMove(data);
    });

    gsap.ticker.add((time, deltaTime) => {
      let fpms = 60 / 1000,
        delta = deltaTime * fpms,
        dt = 1 - Math.pow(1 - settings.speed, delta);
      position.x += (mouse.x - position.x) * dt;
      position.y += (mouse.y - position.y) * dt;
      setX(position.x);
      setY(position.y);
    });

    data.isInViewport = true;
  }

  // on hover
  if (settings.hasHover && settings.hoverTarget.length) {
    setTimeout(function() {
      settings.hoverTarget.hover(function() {
        data.hoverTarget = $(this);
        data.isHover = true;
        settings.onMove(data);
      }, function() {
        data.hoverTarget = $(this);
        data.isHover = false;
        settings.onMove(data);
      });
    }, 100);
  }
}

// big ball
customCursor({
  hasHover: true,
  onMove: function(data) {
    if (data.isInViewport) {
      // in viewport
      if (data.isMoving) {
        if (data.isHover) {
          gsap.to(data.cursor, {
            opacity: 1,
            scale: 1.5
          });
        } else {
          gsap.to(data.cursor, {
            opacity: .5,
            scale: .8
          });
        }
      } else {
        if (data.isHover) {
          gsap.to(data.cursor, {
            opacity: 1,
            scale: 1.5
          });
        } else {
          gsap.to(data.cursor, {
            opacity: .5,
            scale: 1
          });
        }
      }
    } else {
      // out viewport
      gsap.to(data.cursor, {
        opacity: 0,
        scale: 0
      });
    }
  },
});

// dot inside
customCursor({
  targetClass: 'custom-cursor-dot',
  speed: .5,
  onMove: function(data) {
    if (data.isInViewport) {
      gsap.to(data.cursor, {
        opacity: 1
      });
    } else {
      gsap.to(data.cursor, {
        opacity: 0
      });
    }
  },
});

3. Create a magnetic button that interacts with mouse cursor. Live Demo.

Magnetic Button

.buttons {
  height:30vh; 
  display:flex; 
  flex-direction:column; 
  justify-content:space-around;
}

.magnetic {
  padding:15px 30px;
  font-size:1.2em;
  border-radius:5px;
  background-color:#1c1c1c; color:#fff;
}
function magneticButton(options) {
  let settings = $.extend({
      target: $('[data-magnetic]'), // jQuery element
      class: 'magnetizing',
      attraction: 0.45, // 1 is weak, 0 is strong
      distance: 100, // magnetic area around element
      onEnter: function(data) {},
      onExit: function(data) {},
      onUpdate: function(data) {},
    }, options),

    isEnter = false,

    // distance from mouse to center of target
    distanceFromMouse = function($target, mouseX, mouseY) {
      let centerX = $target.offset().left + $target.outerWidth() / 2,
        centerY = $target.offset().top + $target.outerHeight() / 2,
        pointX = mouseX - centerX,
        pointY = mouseY - centerY,
        distance = Math.sqrt(Math.pow(pointX, 2) + Math.pow(pointY, 2));

      return Math.floor(distance);
    },

    // processing
    magnetize = function($this, e) {
      let mouseX = e.pageX,
        mouseY = e.pageY;

      $this.each(function() {
        let $this = $(this),
          centerX = $this.offset().left + $this.outerWidth() / 2,
          centerY = $this.offset().top + $this.outerHeight() / 2,
          deltaX = Math.floor(centerX - mouseX) * -1 * settings.attraction,
          deltaY = Math.floor(centerY - mouseY) * -1 * settings.attraction,
          mouseDistance = distanceFromMouse($this, mouseX, mouseY),
          data = {
            target: $this,
            y: deltaY,
            x: deltaX,
            distance: mouseDistance
          };

        if (mouseDistance < settings.distance) {
          gsap.to($this, {
            y: deltaY,
            x: deltaX
          });

          // enter
          if (!isEnter) {
            isEnter = true;
            $this.addClass(settings.class);
            settings.onEnter(data);
          }

          // update
          settings.onUpdate(data);
        } else {
          gsap.to($this, {
            y: 0,
            x: 0
          });

          // exit
          if (isEnter) {
            isEnter = false;
            $this.removeClass(settings.class);
            settings.onExit(data);
          }
        }
      });
    };

  // exit
  if (!settings.target.length) return;

  // on mouse move
  $(window).on('mousemove', function(e) {
    magnetize(settings.target, e);
  });
}

// init
magneticButton({
  distance: 120,
  onEnter: function(data) {
    //gsap.to(data.target, {scale: 1.2});
    console.log(data);
  },
  onExit: function(data) {
    //gsap.to(data.target, {scale: 1});
    console.log(data);
  },
  onUpdate: function(data) {
    console.log(data);
  }
});

4. Enable an element to always follow your mouse cursor. Live Demo.

mouse-follower

.follower {
  /* positioning */
  position:absolute; top:50%; left:50%;
  transform:translate(-50%, -50%);

  /* decorative */
  width:100px; height:100px; border-radius:50%;
  background-color:#1c1c1c; color:#fff;

  /* avoid transition conflict with GSAP */
  transition:none;

  /* sometimes you need this to avoid hovering flicker */
  pointer-events:none;
}
function cursorFollowAndReturn(options) {
  let settings = $.extend({
    follower: '', // jQuery element
    container: '', // jQuery element
  }, options);

  // exit if elements are not found
  if (!settings.follower.length && !settings.container.length) return;

  // set button position when mouse move inside wrapper
  settings.container.on("mousemove", function(e) {
    let x = e.pageX,
      y = e.pageY, // mouse offset
      offsetX = settings.container.offset().left, // container offset
      offsetY = settings.container.offset().top,
      valX = x - offsetX - (settings.container.outerWidth() / 2),
      valY = y - offsetY - (settings.container.outerHeight() / 2);

    gsap.to(settings.follower, .5, {
      x: valX,
      y: valY
    });
  });

  // set button to center of wrapper when mouse out
  settings.container.on("mouseout", function(e) {
    gsap.to(settings.follower, .5, {
      x: 0,
      y: 0
    });
  });
}

// init
cursorFollowAndReturn({
  follower: $('.follower'),
  container: $('.box'),
});

This awesome jQuery plugin is developed by phucbm. For more Advanced Usages, please check the demo page or visit the official website.