Слежение за курсором
Скрипт описывающий принцип добавления эффекта слежения за курсором с анимацией и задержкой времени для добавления реалистичности.
HTML
<div id="el1" class="lerpme"></div>
<div id="el2" class="lerpme"></div>
CSS
body {
cursor: none;
width: 100vw;
height: 100vh;
background-image: radial-gradient(#b9d0be, #719998, #44656a);
}
.lerpme {
box-sizing: border-box;
position: absolute;
border-radius: 50%;
opacity: 0;
pointer-events: none;
-webkit-animation-name: reveal;
animation-name: reveal;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
@-webkit-keyframes reveal {
100% {
opacity: 1;
}
}
@keyframes reveal {
100% {
opacity: 1;
}
}
#el1 {
width: 20vh;
height: 20vh;
border: 4vh solid #dd8088;
box-shadow: 2px 2px 30px #44656a, inset 2px 2px 30px #44656a;
-webkit-animation-delay: 0.5s;
animation-delay: 0.5s;
}
@media (orientation: landscape) {
#el1 {
width: 20vw;
height: 20vw;
border: 4vw solid #dd8088;
}
}
#el2 {
width: 4vh;
height: 4vh;
background-color: #e6b7ad;
box-shadow: 2px 2px 20px #44656a;
}
@media (orientation: landscape) {
#el2 {
width: 4vw;
height: 4vw;
}
}
#title {
display: block;
position: absolute;
top: 75%;
left: 50%;
font-family: "Knewave", cursive;
font-size: 24px;
text-shadow: 1px 1px 3px #719998;
text-align: center;
color: #e4ddcb;
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
pointer-events: none;
}
#title::after {
content: "A Pen by Chris Caldwell";
display: block;
font-family: "Raleway", sans-serif;
font-size: 12px;
margin-top: 1em;
color: #44656a;
}
JS
// Variables
var mouseX = 0;
var mouseY = 0;
var mouseMoved = false;
// LERP || Linear Interpolation
function lerp(A, B, t) {
// A = Starting position
// B = Final position
// t = time or percentage A and B i.e. 0.0 to 1.0
return A + t * (B - A);
}
// Mouse Events
function handleMouseMove() {
mouseMoved = true;
mouseX = event.clientX;
mouseY = event.clientY;
}
document.onmousemove = handleMouseMove;
// Construct Transform
function setTransform(element, dx, dy) {
var transform = "translateX(" + (dx) + "px) translateY(" + (dy) + "px)";
element.style.webkitTransform = transform;
element.style.mozTransform = transform;
element.style.msTransform = transform;
element.style.oTransform = transform;
element.style.transform = transform;
}
// Tracking
function followMouse(element, t) {
// Determine Start Position
var startX = element.getBoundingClientRect().left;
var startY = element.getBoundingClientRect().top;
// Determine End Position
var targetX = mouseX - element.offsetWidth / 2;
var targetY = mouseY - element.offsetHeight / 2;
// Determine LERP position
var newX = lerp(startX, targetX, t);
var newY = lerp(startY, targetY, t);
// Set Position using Transforms
setTransform(element, newX, newY);
}
// Set Position
function setPosition(element, target) {
// Determine Position
var targetX = target.offsetWidth / 2 - element.offsetWidth / 2;
var targetY = target.offsetHeight / 2 - element.offsetHeight / 2;
// Set Position using Transforms
setTransform(element, targetX, targetY);
}
// Animation
/* requestAnimationFram, or "RAF", ensures animations
are NOT directly connected to frames. This means that
animation draws happen smoothly, at the correct time,
and without dropping 'frames'. */
window.requestAnimationFrame(draw); // Initial 'draw' call
function draw() {
if (mouseMoved) {
followMouse(el1, 0.1);
followMouse(el2, 0.3);
}
window.requestAnimationFrame(draw); // 'draw' calls itself so it can keep drawing without firing again.
}
// Handle Load
window.onload = function() {
var el1 = document.getElementById("el1");
var el2 = document.getElementById("el2");
var viewport = document.body;
// Set Initial Positions
setPosition(el1, viewport);
setPosition(el2, viewport);
};