Files
ag-beats/public/hooks/useCursors.ts
2025-12-20 16:32:05 +02:00

97 lines
3.1 KiB
TypeScript

import { useState, useEffect, useCallback, RefObject } from 'react';
const COLORS = [
'#F94144', '#F3722C', '#F8961E', '#F9C74F', '#90BE6D',
'#43AA8B', '#4D908E', '#577590', '#277DA1', '#F94144'
];
function getCursorColor(id: string) {
let hash = 0;
for (let i = 0; i < id.length; i++) {
hash = id.charCodeAt(i) + ((hash << 5) - hash);
}
return COLORS[Math.abs(hash) % COLORS.length];
}
export function useCursors(sendMessage: (message: any) => void, lastMessage: any, clientId: string | null, mainRef: RefObject<HTMLElement>) {
const [normalizedCursors, setNormalizedCursors] = useState<any>({});
const [cursors, setCursors] = useState<any>({});
const handleMouseMove = useCallback((e: MouseEvent) => {
if (!mainRef.current) return;
const mainRect = mainRef.current.getBoundingClientRect();
const x = e.clientX - mainRect.left;
const y = e.clientY - mainRect.top;
const normalizedX = x / mainRect.width;
const normalizedY = y / mainRect.height;
sendMessage({
type: 'cursor-move',
payload: { x: normalizedX, y: normalizedY }
});
}, [sendMessage, mainRef]);
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, [handleMouseMove]);
const updateCursorPositions = useCallback(() => {
if (!mainRef.current) return;
const mainRect = mainRef.current.getBoundingClientRect();
const newCursors = {};
for (const id in normalizedCursors) {
const nc = normalizedCursors[id];
newCursors[id] = {
...nc,
x: nc.x * mainRect.width,
y: nc.y * mainRect.height
};
}
setCursors(newCursors);
}, [normalizedCursors, mainRef]);
useEffect(() => {
if (!lastMessage) return;
const { type, payload, senderId } = lastMessage;
if (type === 'user-update') {
const remoteUsers = payload.users.filter((user: any) => user.id !== clientId);
const newCursors = {};
remoteUsers.forEach((user: any) => {
const existing = normalizedCursors[user.id];
newCursors[user.id] = {
id: user.id,
color: getCursorColor(user.id),
x: existing?.x || 0,
y: existing?.y || 0
};
});
setNormalizedCursors(newCursors);
} else if (type === 'cursor-move' && senderId !== clientId) {
setNormalizedCursors(prev => ({
...prev,
[senderId]: { ...prev[senderId], ...payload }
}));
}
}, [lastMessage, clientId]);
useEffect(() => {
updateCursorPositions();
window.addEventListener('resize', updateCursorPositions);
return () => {
window.removeEventListener('resize', updateCursorPositions);
};
}, [updateCursorPositions]);
return cursors;
}