import * as React from "react"; import { _ } from "lodash"; function usePrevious(value) { const ref = React.useRef(); React.useEffect(() => { ref.current = value; }, [value]); return ref.current; } const renderCursor = ( name, color, x, y, currentPoint, pageState, owner = false ) => { const z = !owner ? 2 : 1; let _x = null; let _y = null; if (!currentPoint) { _x = (x + pageState?.camera?.point[0]) * pageState?.camera?.zoom; _y = (y + pageState?.camera?.point[1]) * pageState?.camera?.zoom; } return ( <>
{name}
); }; const PositionLabel = (props) => { const { currentUser, currentPoint, pageState, publishCursorUpdate, whiteboardId, pos, } = props; const { name, color, userId, presenter } = currentUser; const prevCurrentPoint = usePrevious(currentPoint); React.useEffect(() => { try { const point = [pos.x, pos.y]; publishCursorUpdate({ xPercent: point[0] / pageState?.camera?.zoom - pageState?.camera?.point[0], yPercent: point[1] / pageState?.camera?.zoom - pageState?.camera?.point[1], whiteboardId, }); } catch (e) { console.log(e); } }, [pos?.x, pos?.y]); return ( <>
{renderCursor(name, color, pos.x, pos.y, currentPoint, props.pageState)}
); }; export default function Cursors(props) { let cursorWrapper = React.useRef(null); const [active, setActive] = React.useState(false); const [pos, setPos] = React.useState({ x: 0, y: 0 }); const { whiteboardId, otherCursors, currentUser, tldrawAPI, publishCursorUpdate, children, isViewersCursorLocked, hasMultiUserAccess, } = props; const start = () => setActive(true); const end = () => { publishCursorUpdate({ xPercent: null, yPercent: null, whiteboardId: whiteboardId, }); setActive(false); }; const moved = (event) => { const { type } = event; const yOffset = parseFloat(document.getElementById('Navbar')?.style?.height); const getSibling = (el) => el?.previousSibling || null; const panel = getSibling(document.getElementById('Navbar')); const subPanel = panel && getSibling(panel); const xOffset = (parseFloat(panel?.style?.width) || 0) + (parseFloat(subPanel?.style?.width) || 0); if (type === 'touchmove') { !active && setActive(true); return setPos({ x: event?.changedTouches[0]?.clientX - xOffset, y: event?.changedTouches[0]?.clientY - yOffset }); } return setPos({ x: event.x - xOffset, y: event.y - yOffset }); } React.useEffect(() => { !cursorWrapper.hasOwnProperty("mouseenter") && cursorWrapper?.addEventListener("mouseenter", start); !cursorWrapper.hasOwnProperty("mouseleave") && cursorWrapper?.addEventListener("mouseleave", end); !cursorWrapper.hasOwnProperty("touchend") && cursorWrapper?.addEventListener("touchend", end); !cursorWrapper.hasOwnProperty("mousemove") && cursorWrapper?.addEventListener("mousemove", moved); !cursorWrapper.hasOwnProperty("touchmove") && cursorWrapper?.addEventListener("touchmove", moved); }, [cursorWrapper]); React.useEffect(() => { return () => { cursorWrapper.removeEventListener('mouseenter', start); cursorWrapper.removeEventListener('mouseleave', end); cursorWrapper.removeEventListener('mousemove', moved); cursorWrapper.removeEventListener('touchend', end); cursorWrapper.removeEventListener('touchmove', moved); } }, []); return ( (cursorWrapper = r)}>
{active && ( )} {children}
{otherCursors .filter((c) => c?.xPercent && c?.yPercent) .filter((c) => { if ((isViewersCursorLocked && c?.role !== "VIEWER") || !isViewersCursorLocked || currentUser?.presenter) { return c; } return null; }) .map((c) => { if (c && currentUser.userId !== c?.userId) { if (c.presenter) { return renderCursor( c?.userName, "#C70039", c?.xPercent, c?.yPercent, null, tldrawAPI?.getPageState(), true ); } return hasMultiUserAccess(whiteboardId, c?.userId) && ( renderCursor( c?.userName, "#AFE1AF", c?.xPercent, c?.yPercent, null, tldrawAPI?.getPageState(), true ) ); } })}
); }