diff --git a/common/recoil/room/room.hooks.ts b/common/recoil/room/room.hooks.ts index c1f42a5..44f9005 100644 --- a/common/recoil/room/room.hooks.ts +++ b/common/recoil/room/room.hooks.ts @@ -14,4 +14,4 @@ export const useSetRoomId = () => { setRoomId({id}); }; return handleSetRoomId -} \ No newline at end of file +}; \ No newline at end of file diff --git a/common/types/global.d.ts b/common/types/global.d.ts index 7d548ab..f3ad383 100644 --- a/common/types/global.d.ts +++ b/common/types/global.d.ts @@ -9,10 +9,10 @@ export declare global { options: CtxOptions; } - type Room =Map; + type Room = {users: Map; drawed: Move[]}; interface ServerToClientEvents { - room: (room: string)=> void; + room: (room: Room, usersToParse: string)=> void; created: (roomId: string) => void; joined:(roomId :string, failed?:boolean) => void; user_draw: (move: Move, userId: string) => void; diff --git a/modules/home/components/Home.tsx b/modules/home/components/Home.tsx index 262c773..fa70b15 100644 --- a/modules/home/components/Home.tsx +++ b/modules/home/components/Home.tsx @@ -1,18 +1,24 @@ import { FormEvent, useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import { socket } from '@/common/lib/socket'; +import { useSetRoomId } from '@/common/recoil/room'; const Home = () => { const [roomId, setRoomId] = useState(""); + + const setAtomRoomId = useSetRoomId(); + const router = useRouter(); useEffect(() => { const handleCreated = (roomIdFromServer: string) => { + setAtomRoomId(roomIdFromServer); router.push(roomIdFromServer); }; const handleJoined = (roomIdFromServer: string, failed?: boolean) => { if (!failed) { + setAtomRoomId(roomIdFromServer); router.push(roomIdFromServer); } else { console.log("Failed to join room"); @@ -26,7 +32,7 @@ const Home = () => { socket.off("created", handleCreated); socket.off("joined", handleJoined); }; - }, [router]); + }, [router, setAtomRoomId]); const handleCreateRoom = () => { socket.emit("create_room"); diff --git a/modules/room/components/MousePosition.tsx b/modules/room/components/MousePosition.tsx index 258d72c..109714c 100644 --- a/modules/room/components/MousePosition.tsx +++ b/modules/room/components/MousePosition.tsx @@ -18,7 +18,7 @@ export const MousePosition = () => { socket.emit("mouse_move", getPos(docX,x), getPos(docY, y)); prevPosition.current = { x: docX, y: docY }; } - }, 300); + }, 25); return ( { + const roomId = useRoomId(); + + if(!roomId) return
No Room ID
+ return (
diff --git a/modules/room/components/UserMouse.tsx b/modules/room/components/UserMouse.tsx index 8a7d73f..2960e26 100644 --- a/modules/room/components/UserMouse.tsx +++ b/modules/room/components/UserMouse.tsx @@ -38,7 +38,7 @@ const UserMouse = ({ userId }: { userId: string }) => { diff --git a/modules/room/helpers/Canvas.helpers.ts b/modules/room/helpers/Canvas.helpers.ts index b6dc17a..a26d141 100644 --- a/modules/room/helpers/Canvas.helpers.ts +++ b/modules/room/helpers/Canvas.helpers.ts @@ -18,13 +18,18 @@ export const handleMove = ( } }; - export const drawOnUndo = ( + export const drawAllMoves = ( ctx: CanvasRenderingContext2D, + movesWithoutUser: Move[], savedMoves: Move[], users: {[key: string]: Move[]} ) => { ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + movesWithoutUser.forEach((move)=>{ + handleMove(move,ctx); + }); + Object.values(users).forEach((user)=>{ user.forEach((move)=> handleMove(move,ctx)); }); diff --git a/modules/room/hooks/Canvas.hooks.ts b/modules/room/hooks/Canvas.hooks.ts index fc84d26..6908a97 100644 --- a/modules/room/hooks/Canvas.hooks.ts +++ b/modules/room/hooks/Canvas.hooks.ts @@ -1,14 +1,15 @@ -import { useCallback, useEffect, useState } from "react"; +import { use, useCallback, useEffect, useState } from "react"; import { socket } from "@/common/lib/socket"; import { useOptions } from "@/common/recoil/options"; -import { drawOnUndo, handleMove } from "../helpers/Canvas.helpers"; +import { drawAllMoves, handleMove } from "../helpers/Canvas.helpers"; import usersAtom, { useUsers } from "@/common/recoil/users"; import { useBoardPosition } from "./useBoardPosition"; import { getPos } from "@/common/lib/getPos"; import { useSetRecoilState } from "recoil"; +const movesWithoutUser: Move[] = []; const savedMoves: Move[] = []; -let moves: [number, number][] = []; +let tempMoves: [number, number][] = []; export const useDraw = ( ctx: CanvasRenderingContext2D | undefined, @@ -38,7 +39,7 @@ export const useDraw = ( socket.emit("undo"); - drawOnUndo(ctx, savedMoves, users); + drawAllMoves(ctx, movesWithoutUser, savedMoves, users); handleEnd(); } }, [ctx, handleEnd, users]); @@ -64,6 +65,16 @@ export const useDraw = ( ctx.beginPath(); ctx.lineTo(getPos(x, movedX), getPos(y, movedY)); ctx.stroke(); + + tempMoves = [[getPos(x, movedX), getPos(y, movedY)]]; + }; + + const handleDraw = (x: number, y: number) => { + if (!ctx || !drawing || blocked) return; + + ctx.lineTo(getPos(x, movedX), getPos(y, movedY)); + ctx.stroke(); + tempMoves.push([getPos(x, movedX), getPos(y, movedY)]); }; const handleEndDrawing = () => { @@ -72,24 +83,21 @@ export const useDraw = ( setDrawing(false); const move: Move = { - path: moves, + path: tempMoves, options }; savedMoves.push(move); + tempMoves = []; socket.emit("draw", move); - moves = []; + + drawAllMoves(ctx, movesWithoutUser, savedMoves, users); + handleEnd(); }; - const handleDraw = (x: number, y: number) => { - if (!ctx || !drawing || blocked) return; - - ctx.lineTo(getPos(x, movedX), getPos(y, movedY)); - ctx.stroke(); - moves.push([getPos(x, movedX), getPos(y, movedY)]); - }; + return { handleEndDrawing, @@ -109,19 +117,29 @@ export const useSocketDraw = ( const setUsers = useSetRecoilState(usersAtom); useEffect(()=> { - socket.emit("joined_room") - },[]); + if(ctx) socket.emit("joined_room") + },[ctx]); useEffect(() => { - socket.on("room", (roomJSON) => { - const room: Room = new Map(JSON.parse(roomJSON)); + socket.on("room", (room, usersToParse) => { + if(!ctx) return; - room.forEach((userMoves, userId) => { - if (ctx) userMoves.forEach((move) => handleMove(move, ctx)); - handleEnd(); - setUsers((prevUsers) => ({ ...prevUsers, [userId]: userMoves })); + const users= new Map(JSON.parse(usersToParse)); + + room.drawed.forEach((move) => { + handleMove(move, ctx); + movesWithoutUser.push(move); }); + + users.forEach((userMoves, userId) => { + userMoves.forEach((move)=>handleMove(move, ctx) ); + setUsers((prevUsers)=> ({...prevUsers, [userId]: userMoves})); }); + handleEnd(); + + }); + + return () => { socket.off("room"); @@ -170,7 +188,7 @@ export const useSocketDraw = ( newUsers[userId] = newUsers[userId].slice(0, -1); } if (ctx) { - drawOnUndo(ctx, savedMoves, newUsers); + drawAllMoves(ctx,movesWithoutUser, savedMoves, newUsers); handleEnd(); } return newUsers; diff --git a/server/index.ts b/server/index.ts index ac37f97..e283752 100644 --- a/server/index.ts +++ b/server/index.ts @@ -19,20 +19,30 @@ nextApp.prepare().then(async () => { }); const rooms = new Map(); - rooms.set("global", new Map()); + const addMove = (roomId: string, socketId: string, move: Move) => { const room = rooms.get(roomId); - if (!room?.has(socketId)) { - room?.set(socketId, [move]); + if (!room?.users.has(socketId)) { + room?.users.set(socketId, [move]); } - room?.get(socketId)?.push(move); + room?.users.get(socketId)?.push(move); }; const undoMove = (roomId: string, socketId: string) => { const room = rooms.get(roomId); - room?.get(socketId)?.pop(); + room?.users.get(socketId)?.pop(); + }; + + const leaveRoom = (roomId: string, socketId: string) => { + const room= rooms.get(roomId); + + const userMoves= room?.users.get(socketId)!; + room?.drawed.push(...userMoves); + room?.users.delete(socketId); + + console.log("user left room"); }; io.on("connection", (socket) => { @@ -51,8 +61,8 @@ nextApp.prepare().then(async () => { } while (rooms.has(roomId)); socket.join(roomId); - rooms.set(roomId, new Map()); - rooms.get(roomId)?.set(socket.id, []); + rooms.set(roomId, {users: new Map(), drawed: []}); + rooms.get(roomId)?.users.set(socket.id, []); io.to(socket.id).emit("created", roomId); @@ -71,17 +81,23 @@ nextApp.prepare().then(async () => { const roomId = getRoomId(); //add the socket to the room's map - rooms.get(roomId)?.set(socket.id, []); - io.to(socket.id).emit("room", JSON.stringify([...rooms.get(roomId)!])); + + const room= rooms.get(roomId); + if(room) { + room.users.set(socket.id, []); + + io.to(socket.id).emit("room", room, JSON.stringify([...room.users])); socket.broadcast.to(roomId).emit("new_user", socket.id); + }; }); socket.on("leave_room", () => { const roomId= getRoomId(); - const user= rooms.get(roomId)?.get(socket.id); - if(user?.length ===0 ) rooms.get(roomId)?.delete(socket.id); + leaveRoom(roomId, socket.id); + + io.to(roomId).emit("user_disconnected", socket.id); }); socket.on("draw", (move) => { @@ -106,15 +122,14 @@ nextApp.prepare().then(async () => { }); socket.on("disconnect", () => { - - io.to(getRoomId()).emit("user_disconnected", socket.id); - - const user= rooms.get(getRoomId())?.get(socket.id); - //remove user from the room if they have no moves + //remove user from the room if they have no moves + + leaveRoom(getRoomId(), socket.id ); + io.to(getRoomId()).emit("user_disconnected", socket.id); + + - if(user?.length === 0) rooms.get(getRoomId())?.delete(socket.id); console.log("disconnected"); - }); });