Interactive Cursor Effects In jQuery And GSAP
| File Size: | 12.6 KB |
|---|---|
| Views Total: | 2554 |
| Last Update: | |
| Publish Date: | |
| Official Website: | Go to website |
| License: | MIT |
A set of pretty cool custom cursors and interactive cursor effects implemented in jQuery and GSAP.
See Also:
- Fancy Cursor Animations In jQuery & GSAP - Cursor & Magnetic
- Elastic Hover Effect With jQuery And GSAP
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.

/* 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.

.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.

.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.











