Initial commit
This commit is contained in:
96
public/hooks/useCursors.ts
Normal file
96
public/hooks/useCursors.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user