cleaned up
This commit is contained in:
256
Profice WebSite/scripts/cursor.js
Normal file
256
Profice WebSite/scripts/cursor.js
Normal file
@@ -0,0 +1,256 @@
|
||||
// cursor.js
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
if (window.matchMedia("(pointer: coarse)").matches) return;
|
||||
|
||||
// --- SETTINGS ---
|
||||
const CONFIG = {
|
||||
tentacleCount: 8,
|
||||
triggerDist: 10,
|
||||
maxLength: 300,
|
||||
connectionDist: 150,
|
||||
thickness: 1,
|
||||
color: "rgba(20, 20, 20, 1)",
|
||||
prediction: 3.5
|
||||
};
|
||||
|
||||
|
||||
const toggleBtn = document.getElementById('cursorToggle');
|
||||
const body = document.body;
|
||||
|
||||
// Default to system cursor (disabled custom cursor)
|
||||
let isCursorDisabled = localStorage.getItem('venomCursorDisabled') !== 'false';
|
||||
|
||||
function updateCursorState() {
|
||||
if (isCursorDisabled) {
|
||||
// System cursor (default) - show spidy icon
|
||||
body.classList.add('system-cursor');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.classList.remove('active');
|
||||
let icon = toggleBtn.querySelector('.cursor-icon');
|
||||
if (icon) {
|
||||
// Replace img with spidy.png if needed
|
||||
if (icon.tagName !== 'IMG') {
|
||||
const newIcon = document.createElement('img');
|
||||
newIcon.className = 'cursor-icon';
|
||||
newIcon.alt = 'Spider Cursor';
|
||||
|
||||
// Check if we're on a page in the sites/ folder
|
||||
const currentPath = window.location.pathname;
|
||||
const isInSitesFolder = currentPath.includes('/sites/');
|
||||
const imagePath = isInSitesFolder ? '../images/additional/spidy.png' : 'images/additional/spidy.png';
|
||||
newIcon.src = imagePath;
|
||||
|
||||
icon.parentNode.replaceChild(newIcon, icon);
|
||||
} else {
|
||||
// Update existing img
|
||||
const currentPath = window.location.pathname;
|
||||
const isInSitesFolder = currentPath.includes('/sites/');
|
||||
const imagePath = isInSitesFolder ? '../images/additional/spidy.png' : 'images/additional/spidy.png';
|
||||
icon.src = imagePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Custom cursor (secondary) - show standard cursor icon
|
||||
body.classList.remove('system-cursor');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.classList.add('active');
|
||||
let icon = toggleBtn.querySelector('.cursor-icon');
|
||||
if (icon) {
|
||||
// Replace img with cursor.png if needed
|
||||
if (icon.tagName !== 'IMG') {
|
||||
const newIcon = document.createElement('img');
|
||||
newIcon.className = 'cursor-icon';
|
||||
newIcon.alt = 'Custom Cursor';
|
||||
|
||||
// Check if we're on a page in the sites/ folder
|
||||
const currentPath = window.location.pathname;
|
||||
const isInSitesFolder = currentPath.includes('/sites/');
|
||||
const imagePath = isInSitesFolder ? '../images/additional/cursor.png' : 'images/additional/cursor.png';
|
||||
newIcon.src = imagePath;
|
||||
|
||||
icon.parentNode.replaceChild(newIcon, icon);
|
||||
} else {
|
||||
// Update existing img
|
||||
const currentPath = window.location.pathname;
|
||||
const isInSitesFolder = currentPath.includes('/sites/');
|
||||
const imagePath = isInSitesFolder ? '../images/additional/cursor.png' : 'images/additional/cursor.png';
|
||||
icon.src = imagePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateCursorState();
|
||||
|
||||
if (toggleBtn) {
|
||||
toggleBtn.addEventListener('click', () => {
|
||||
isCursorDisabled = !isCursorDisabled;
|
||||
localStorage.setItem('venomCursorDisabled', isCursorDisabled);
|
||||
updateCursorState();
|
||||
});
|
||||
}
|
||||
|
||||
function initCursor() {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.id = "venom-cursor";
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
const tentacles = [];
|
||||
const mouse = { x: 0, y: 0 };
|
||||
const oldMouse = { x: 0, y: 0 };
|
||||
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
mouse.x = e.clientX;
|
||||
mouse.y = e.clientY;
|
||||
});
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
});
|
||||
|
||||
return { canvas, ctx, tentacles, mouse, oldMouse };
|
||||
}
|
||||
|
||||
const cursorElements = initCursor();
|
||||
const canvas = cursorElements.canvas;
|
||||
const ctx = cursorElements.ctx;
|
||||
const tentacles = cursorElements.tentacles;
|
||||
const mouse = cursorElements.mouse;
|
||||
const oldMouse = cursorElements.oldMouse;
|
||||
|
||||
class Tentacle {
|
||||
constructor(mx, my, targetX, targetY) {
|
||||
this.dead = false;
|
||||
this.anchor = { x: targetX, y: targetY };
|
||||
this.currentDist = 0; // For calculating connection opacity
|
||||
}
|
||||
|
||||
update(currentMouse) {
|
||||
const dx = currentMouse.x - this.anchor.x;
|
||||
const dy = currentMouse.y - this.anchor.y;
|
||||
this.currentDist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
if (this.currentDist > CONFIG.maxLength) {
|
||||
this.dead = true;
|
||||
}
|
||||
}
|
||||
|
||||
draw(ctx, currentMouse) {
|
||||
if (this.dead) return;
|
||||
|
||||
// Tension (0..1)
|
||||
const tension = Math.min(this.currentDist / CONFIG.maxLength, 1);
|
||||
const dynamicThickness = CONFIG.thickness * (1 - tension * 0.9);
|
||||
|
||||
// Draw main line (Cursor -> Anchor)
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(currentMouse.x, currentMouse.y);
|
||||
ctx.lineTo(this.anchor.x, this.anchor.y);
|
||||
|
||||
ctx.lineWidth = Math.max(0.2, dynamicThickness);
|
||||
ctx.strokeStyle = CONFIG.color;
|
||||
ctx.lineCap = "butt";
|
||||
ctx.stroke();
|
||||
|
||||
// Draw anchor point
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.anchor.x, this.anchor.y, 1.5 * (1 - tension), 0, Math.PI * 2);
|
||||
ctx.fillStyle = CONFIG.color;
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
if (isCursorDisabled) {
|
||||
requestAnimationFrame(render);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// 1. Create new tentacles on movement
|
||||
const distMoved = Math.hypot(mouse.x - oldMouse.x, mouse.y - oldMouse.y);
|
||||
|
||||
if (distMoved > CONFIG.triggerDist) {
|
||||
const vx = mouse.x - oldMouse.x;
|
||||
const vy = mouse.y - oldMouse.y;
|
||||
|
||||
// "Spread" of shots increased slightly for better geometry
|
||||
const targetX = mouse.x + vx * CONFIG.prediction + (Math.random() - 0.5) * 60;
|
||||
const targetY = mouse.y + vy * CONFIG.prediction + (Math.random() - 0.5) * 60;
|
||||
|
||||
tentacles.push(new Tentacle(mouse.x, mouse.y, targetX, targetY));
|
||||
oldMouse.x = mouse.x;
|
||||
oldMouse.y = mouse.y;
|
||||
}
|
||||
|
||||
// Remove old ones (FIFO)
|
||||
if (tentacles.length > CONFIG.tentacleCount) {
|
||||
tentacles.shift();
|
||||
}
|
||||
|
||||
// 2. Draw main tentacles
|
||||
for (let i = tentacles.length - 1; i >= 0; i--) {
|
||||
const t = tentacles[i];
|
||||
t.update(mouse);
|
||||
if (t.dead) {
|
||||
tentacles.splice(i, 1);
|
||||
} else {
|
||||
t.draw(ctx, mouse);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. DRAW CONNECTIONS BETWEEN ANCHORS (New logic)
|
||||
// Iterate through all pairs of active tentacles
|
||||
ctx.beginPath(); // Begin common path for optimization
|
||||
ctx.lineWidth = 0.5; // Connections are always thin
|
||||
|
||||
for (let i = 0; i < tentacles.length; i++) {
|
||||
for (let j = i + 1; j < tentacles.length; j++) {
|
||||
const t1 = tentacles[i];
|
||||
const t2 = tentacles[j];
|
||||
|
||||
// Calculate distance between ends of two tentacles
|
||||
const dx = t1.anchor.x - t2.anchor.x;
|
||||
const dy = t1.anchor.y - t2.anchor.y;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// If they are close to each other — connect
|
||||
if (dist < CONFIG.connectionDist) {
|
||||
// Opacity depends on how far apart they are
|
||||
// And how much the tentacles themselves are stretched
|
||||
const alpha = (1 - dist / CONFIG.connectionDist) * 0.6;
|
||||
|
||||
ctx.beginPath(); // New path for each to control opacity
|
||||
ctx.strokeStyle = `rgba(20, 20, 20, ${alpha})`;
|
||||
ctx.moveTo(t1.anchor.x, t1.anchor.y);
|
||||
ctx.lineTo(t2.anchor.x, t2.anchor.y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Cursor (Rhombus)
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = CONFIG.color;
|
||||
ctx.moveTo(mouse.x, mouse.y - 5);
|
||||
ctx.lineTo(mouse.x + 5, mouse.y);
|
||||
ctx.lineTo(mouse.x, mouse.y + 5);
|
||||
ctx.lineTo(mouse.x - 5, mouse.y);
|
||||
ctx.fill();
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
render();
|
||||
});
|
||||
Reference in New Issue
Block a user