/**
* Enhanced Cursor Tracker and Scroll Progress Indicator
* This script adds a custom animated cursor that follows mouse movement
* and a progress bar at the top of the screen showing the scroll position
*/
document.addEventListener("DOMContentLoaded", function() {
// Create cursor elements
createCursorElements();
// Create scroll progress indicator
createScrollProgressIndicator();
// Initialize both features
initCursorTracker();
initScrollProgressIndicator();
});
/**
* Creates the DOM elements needed for the custom cursor
*/
function createCursorElements() {
// Create cursor container
const cursorContainer = document.createElement('div');
cursorContainer.className = 'cursor-container';
// Create outer cursor (larger circle)
const cursorOuter = document.createElement('div');
cursorOuter.className = 'cursor-outer';
// Create inner cursor (smaller dot)
const cursorInner = document.createElement('div');
cursorInner.className = 'cursor-inner';
// Create cursor dot (smallest dot)
const cursorDot = document.createElement('div');
cursorDot.className = 'cursor-dot';
// Append cursors to container
cursorContainer.appendChild(cursorOuter);
cursorContainer.appendChild(cursorInner);
cursorContainer.appendChild(cursorDot);
// Add cursor container to body
document.body.appendChild(cursorContainer);
// Add CSS for cursor elements
const style = document.createElement('style');
style.textContent = `
/* Hide default cursor on body and clickable elements */
body, a, button, input[type="submit"], input[type="button"], .btn, .filter-btn, .slider-dot,
.social-icon, .read-more, .btn-view-profile, .nav-link, .dropdown-item {
cursor: none !important;
}
/* Cursor Container */
.cursor-container {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
pointer-events: none;
will-change: transform;
}
/* Outer cursor (large circle) */
.cursor-outer {
position: fixed;
width: 40px;
height: 40px;
border: 2px solid rgba(78, 115, 223, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.3s, height 0.3s, border 0.3s, transform 0.1s;
pointer-events: none;
}
/* Inner cursor (medium dot) */
.cursor-inner {
position: fixed;
width: 10px;
height: 10px;
background-color: rgba(78, 115, 223, 0.5);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.3s, height 0.3s, opacity 0.3s, background-color 0.3s;
pointer-events: none;
}
/* Cursor dot (smallest dot at center) */
.cursor-dot {
position: fixed;
width: 4px;
height: 4px;
background-color: #4e73df;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
/* Hover state for outer cursor */
.cursor-hover .cursor-outer {
width: 50px;
height: 50px;
border: 2px solid rgba(78, 115, 223, 0.5);
background-color: rgba(78, 115, 223, 0.03);
}
/* Hover state for inner cursor */
.cursor-hover .cursor-inner {
width: 15px;
height: 15px;
background-color: rgba(78, 115, 223, 0.7);
}
/* Active state (clicking) for cursors */
.cursor-active .cursor-outer {
width: 35px;
height: 35px;
border: 2px solid rgba(78, 115, 223, 0.7);
}
.cursor-active .cursor-inner {
width: 14px;
height: 14px;
background-color: rgba(78, 115, 223, 0.9);
}
/* Hide cursor on mobile devices */
@media (max-width: 992px) {
.cursor-container, .cursor-outer, .cursor-inner, .cursor-dot {
display: none;
}
body, a, button, input[type="submit"], input[type="button"], .btn {
cursor: auto !important;
}
}
`;
document.head.appendChild(style);
}
/**
* Creates the DOM element for scroll progress indicator
*/
function createScrollProgressIndicator() {
// Create progress bar container
const progressContainer = document.createElement('div');
progressContainer.className = 'scroll-progress-container';
// Create progress bar
const progressBar = document.createElement('div');
progressBar.className = 'scroll-progress-bar';
// Append progress bar to container
progressContainer.appendChild(progressBar);
// Add progress container to body
document.body.appendChild(progressContainer);
// Add CSS for progress bar
const style = document.createElement('style');
style.textContent = `
/* Progress bar container */
.scroll-progress-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 4px;
background-color: rgba(0, 0, 0, 0.05);
z-index: 9998;
}
/* Progress bar */
.scroll-progress-bar {
height: 100%;
width: 0;
background: linear-gradient(to right, #4e73df, #36b9cc);
transition: width 0.1s ease;
position: relative;
}
.scroll-progress-bar::after {
content: '';
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
background: linear-gradient(to right,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.4) 50%,
rgba(255, 255, 255, 0) 100%);
animation: shimmer 1.5s infinite;
transform: translateX(-100%);
}
@keyframes shimmer {
100% {
transform: translateX(100%);
}
}
`;
document.head.appendChild(style);
}
/**
* Initializes the custom cursor tracker
*/
function initCursorTracker() {
const cursorOuter = document.querySelector('.cursor-outer');
const cursorInner = document.querySelector('.cursor-inner');
const cursorDot = document.querySelector('.cursor-dot');
const cursorContainer = document.querySelector('.cursor-container');
// Cursor positions with damping effect
let outerX = 0, outerY = 0;
let innerX = 0, innerY = 0;
let dotX = 0, dotY = 0;
// Target positions (mouse position)
let mouseX = 0, mouseY = 0;
// Track mouse movement
document.addEventListener('mousemove', function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
// Detect hover on clickable elements
const clickableElements = document.querySelectorAll('a, button, input[type="submit"], input[type="button"], .btn, .filter-btn, .slider-dot, .social-icon, .read-more, .btn-view-profile, .nav-link, .dropdown-item');
clickableElements.forEach(el => {
el.addEventListener('mouseenter', () => {
cursorContainer.classList.add('cursor-hover');
});
el.addEventListener('mouseleave', () => {
cursorContainer.classList.remove('cursor-hover');
});
});
// Detect mouse down/up events for click animation
document.addEventListener('mousedown', () => {
cursorContainer.classList.add('cursor-active');
});
document.addEventListener('mouseup', () => {
cursorContainer.classList.remove('cursor-active');
});
// Update cursor position with damping effect (smooth following)
function updateCursorPosition() {
// Damping factors (smaller = smoother but slower)
const outerDampingFactor = 0.15;
const innerDampingFactor = 0.22;
const dotDampingFactor = 0.3;
// Update outer cursor position with damping
outerX += (mouseX - outerX) * outerDampingFactor;
outerY += (mouseY - outerY) * outerDampingFactor;
// Update inner cursor position with damping
innerX += (mouseX - innerX) * innerDampingFactor;
innerY += (mouseY - innerY) * innerDampingFactor;
// Update dot cursor position with damping
dotX += (mouseX - dotX) * dotDampingFactor;
dotY += (mouseY - dotY) * dotDampingFactor;
// Apply positions to cursor elements
cursorOuter.style.transform = `translate(${outerX}px, ${outerY}px) translate(-50%, -50%)`;
cursorInner.style.transform = `translate(${innerX}px, ${innerY}px) translate(-50%, -50%)`;
cursorDot.style.transform = `translate(${dotX}px, ${dotY}px) translate(-50%, -50%)`;
// Continue animation
requestAnimationFrame(updateCursorPosition);
}
// Start animation
updateCursorPosition();
}
/**
* Initializes the scroll progress indicator
*/
function initScrollProgressIndicator() {
const progressBar = document.querySelector('.scroll-progress-bar');
// Update progress bar width on scroll
window.addEventListener('scroll', function() {
const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scrolled = (winScroll / height) * 100;
progressBar.style.width = scrolled + "%";
});
}
/**
* Add these scripts to the main page by calling:
* <script src="assets/js/cursor_and_progress.js"></script>
*
* Or by inline including this entire JavaScript file
*/