228 lines
7.3 KiB
JavaScript
228 lines
7.3 KiB
JavaScript
// Simple cursor.js - Fixed version with better line effects
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Check if touch device
|
|
if (window.matchMedia("(pointer: coarse)").matches) return;
|
|
|
|
const toggleBtn = document.getElementById('cursorToggle');
|
|
const body = document.body;
|
|
|
|
// Start with system cursor
|
|
let isCustomCursor = false;
|
|
|
|
function updateCursorState() {
|
|
if (isCustomCursor) {
|
|
body.classList.remove('system-cursor');
|
|
if (toggleBtn) {
|
|
toggleBtn.classList.add('active');
|
|
}
|
|
} else {
|
|
body.classList.add('system-cursor');
|
|
if (toggleBtn) {
|
|
toggleBtn.classList.remove('active');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize cursor state
|
|
updateCursorState();
|
|
|
|
// Toggle button click handler
|
|
if (toggleBtn) {
|
|
toggleBtn.addEventListener('click', () => {
|
|
isCustomCursor = !isCustomCursor;
|
|
localStorage.setItem('customCursor', isCustomCursor);
|
|
updateCursorState();
|
|
});
|
|
}
|
|
|
|
// Create canvas for custom cursor
|
|
const canvas = document.createElement("canvas");
|
|
canvas.id = "custom-cursor";
|
|
canvas.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
pointer-events: none;
|
|
z-index: 999999;
|
|
display: none;
|
|
`;
|
|
document.body.appendChild(canvas);
|
|
|
|
const ctx = canvas.getContext("2d");
|
|
const tentacles = [];
|
|
const mouse = { x: 0, y: 0 };
|
|
const oldMouse = { x: 0, y: 0 };
|
|
|
|
// Mouse move handler
|
|
document.addEventListener("mousemove", (e) => {
|
|
mouse.x = e.clientX;
|
|
mouse.y = e.clientY;
|
|
|
|
if (isCustomCursor) {
|
|
canvas.style.display = 'block';
|
|
} else {
|
|
canvas.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// Window resize handler
|
|
window.addEventListener("resize", () => {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
});
|
|
|
|
// Tentacle class with better line effects
|
|
class Tentacle {
|
|
constructor(x, y, targetX, targetY) {
|
|
this.startX = x;
|
|
this.startY = y;
|
|
this.endX = targetX;
|
|
this.endY = targetY;
|
|
this.life = 1.0;
|
|
this.decay = 0.015;
|
|
this.growth = 0;
|
|
this.maxLength = 0;
|
|
}
|
|
|
|
update() {
|
|
// Grow the tentacle
|
|
if (this.growth < 1.0) {
|
|
this.growth += 0.1;
|
|
}
|
|
|
|
// Calculate actual end point based on growth
|
|
const currentEndX = this.startX + (this.endX - this.startX) * this.growth;
|
|
const currentEndY = this.startY + (this.endY - this.startY) * this.growth;
|
|
|
|
this.currentEndX = currentEndX;
|
|
this.currentEndY = currentEndY;
|
|
|
|
// Decay over time
|
|
this.life -= this.decay;
|
|
}
|
|
|
|
draw(ctx) {
|
|
if (this.life <= 0) return;
|
|
|
|
const opacity = this.life * this.growth;
|
|
|
|
// Draw main line with gradient effect
|
|
const gradient = ctx.createLinearGradient(
|
|
this.startX, this.startY,
|
|
this.currentEndX, this.currentEndY
|
|
);
|
|
gradient.addColorStop(0, `rgba(20, 20, 20, ${opacity * 0.8})`);
|
|
gradient.addColorStop(1, `rgba(20, 20, 20, ${opacity * 0.2})`);
|
|
|
|
ctx.strokeStyle = gradient;
|
|
ctx.lineWidth = 3 * opacity * this.growth;
|
|
ctx.lineCap = 'round';
|
|
ctx.beginPath();
|
|
ctx.moveTo(this.startX, this.startY);
|
|
ctx.lineTo(this.currentEndX, this.currentEndY);
|
|
ctx.stroke();
|
|
|
|
// Draw glowing endpoint
|
|
const glowSize = 6 * opacity;
|
|
const glowGradient = ctx.createRadialGradient(
|
|
this.currentEndX, this.currentEndY, 0,
|
|
this.currentEndX, this.currentEndY, glowSize
|
|
);
|
|
glowGradient.addColorStop(0, `rgba(20, 20, 20, ${opacity})`);
|
|
glowGradient.addColorStop(1, `rgba(20, 20, 20, 0)`);
|
|
|
|
ctx.fillStyle = glowGradient;
|
|
ctx.beginPath();
|
|
ctx.arc(this.currentEndX, this.currentEndY, glowSize, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
// Draw connection dots along the line
|
|
const dotCount = 3;
|
|
for (let i = 1; i <= dotCount; i++) {
|
|
const t = i / (dotCount + 1);
|
|
const dotX = this.startX + (this.currentEndX - this.startX) * t;
|
|
const dotY = this.startY + (this.currentEndY - this.startY) * t;
|
|
const dotOpacity = opacity * (1 - t) * 0.5;
|
|
|
|
ctx.fillStyle = `rgba(20, 20, 20, ${dotOpacity})`;
|
|
ctx.beginPath();
|
|
ctx.arc(dotX, dotY, 2, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Animation loop
|
|
function animate() {
|
|
if (!isCustomCursor) {
|
|
requestAnimationFrame(animate);
|
|
return;
|
|
}
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
// Create new tentacles on movement
|
|
const dx = mouse.x - oldMouse.x;
|
|
const dy = mouse.y - oldMouse.y;
|
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
if (distance > 3) {
|
|
// Create multiple tentacles in movement direction
|
|
const angle = Math.atan2(dy, dx);
|
|
const spread = 0.3;
|
|
|
|
for (let i = 0; i < 4; i++) {
|
|
const spreadAngle = angle + (Math.random() - 0.5) * spread;
|
|
const length = 60 + Math.random() * 80;
|
|
const targetX = mouse.x + Math.cos(spreadAngle) * length;
|
|
const targetY = mouse.y + Math.sin(spreadAngle) * length;
|
|
tentacles.push(new Tentacle(mouse.x, mouse.y, targetX, targetY));
|
|
}
|
|
|
|
oldMouse.x = mouse.x;
|
|
oldMouse.y = mouse.y;
|
|
}
|
|
|
|
// Update and draw tentacles
|
|
for (let i = tentacles.length - 1; i >= 0; i--) {
|
|
const tentacle = tentacles[i];
|
|
tentacle.update();
|
|
if (tentacle.life <= 0) {
|
|
tentacles.splice(i, 1);
|
|
} else {
|
|
tentacle.draw(ctx);
|
|
}
|
|
}
|
|
|
|
// Limit tentacle count
|
|
if (tentacles.length > 15) {
|
|
tentacles.splice(0, tentacles.length - 15);
|
|
}
|
|
|
|
// Draw cursor point with glow
|
|
const cursorGradient = ctx.createRadialGradient(
|
|
mouse.x, mouse.y, 0,
|
|
mouse.x, mouse.y, 8
|
|
);
|
|
cursorGradient.addColorStop(0, 'rgba(20, 20, 20, 0.8)');
|
|
cursorGradient.addColorStop(1, 'rgba(20, 20, 20, 0)');
|
|
|
|
ctx.fillStyle = cursorGradient;
|
|
ctx.beginPath();
|
|
ctx.arc(mouse.x, mouse.y, 6, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
// Add central bright point
|
|
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
|
|
ctx.beginPath();
|
|
ctx.arc(mouse.x, mouse.y, 2, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
animate();
|
|
});
|