Created
March 4, 2025 12:23
-
-
Save shricodev/d0083c72d80f66056cf6f9a9cc042614 to your computer and use it in GitHub Desktop.
Collaborative whiteboard application (generated by GPT-4.5 AI Model). This gist is for one of my blog post comparison of AI Models.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| "use client"; | |
| import React, { useRef, useEffect, useState } from "react"; | |
| export default function Whiteboard() { | |
| const canvasRef = useRef<HTMLCanvasElement>(null); | |
| const ws = useRef<WebSocket | null>(null); | |
| const [drawing, setDrawing] = useState(false); | |
| const [lastPos, setLastPos] = useState<{ x: number; y: number } | null>(null); | |
| useEffect(() => { | |
| ws.current = new WebSocket("ws://localhost:3001"); | |
| ws.current.onopen = () => { | |
| console.log("Connected to WebSocket server"); | |
| }; | |
| ws.current.onmessage = (event) => { | |
| const message = JSON.parse(event.data); | |
| if (message.type === "draw") { | |
| const { from, to } = message; | |
| const canvas = canvasRef.current; | |
| if (canvas) { | |
| const ctx = canvas.getContext("2d"); | |
| if (ctx) { | |
| ctx.beginPath(); | |
| ctx.moveTo(from.x, from.y); | |
| ctx.lineTo(to.x, to.y); | |
| ctx.strokeStyle = "black"; | |
| ctx.lineWidth = 2; | |
| ctx.stroke(); | |
| ctx.closePath(); | |
| } | |
| } | |
| } else if (message.type === "clear") { | |
| const canvas = canvasRef.current; | |
| if (canvas) { | |
| const ctx = canvas.getContext("2d"); | |
| if (ctx) { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| } | |
| } | |
| } | |
| }; | |
| return () => { | |
| if (ws.current) ws.current.close(); | |
| }; | |
| }, []); | |
| // Mouse event handlers for drawing | |
| const handleMouseDown = (e: React.MouseEvent<HTMLCanvasElement>) => { | |
| setDrawing(true); | |
| setLastPos({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY }); | |
| }; | |
| const handleMouseMove = (e: React.MouseEvent<HTMLCanvasElement>) => { | |
| if (!drawing) return; | |
| const canvas = canvasRef.current; | |
| const ctx = canvas?.getContext("2d"); | |
| if (!ctx || !lastPos) return; | |
| const newPos = { x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY }; | |
| // Draw line locally on the canvas | |
| ctx.beginPath(); | |
| ctx.moveTo(lastPos.x, lastPos.y); | |
| ctx.lineTo(newPos.x, newPos.y); | |
| ctx.strokeStyle = "black"; | |
| ctx.lineWidth = 2; | |
| ctx.stroke(); | |
| ctx.closePath(); | |
| // Broadcast the drawing data to other clients via WebSocket | |
| const message = { | |
| type: "draw", | |
| from: lastPos, | |
| to: newPos, | |
| }; | |
| ws.current?.send(JSON.stringify(message)); | |
| setLastPos(newPos); | |
| }; | |
| const handleMouseUp = () => { | |
| setDrawing(false); | |
| setLastPos(null); | |
| }; | |
| // Clear the canvas (both locally and for all connected clients) | |
| const clearCanvas = () => { | |
| const canvas = canvasRef.current; | |
| const ctx = canvas?.getContext("2d"); | |
| if (ctx && canvas) { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| const message = { | |
| type: "clear", | |
| }; | |
| ws.current?.send(JSON.stringify(message)); | |
| } | |
| }; | |
| return ( | |
| <div className="text-black flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4"> | |
| <h1 className="text-3xl font-bold mb-6"> | |
| Real-Time Collaborative Whiteboard | |
| </h1> | |
| <canvas | |
| ref={canvasRef} | |
| width={800} | |
| height={600} | |
| className="border border-gray-400 bg-white" | |
| onMouseDown={handleMouseDown} | |
| onMouseMove={handleMouseMove} | |
| onMouseUp={handleMouseUp} | |
| onMouseLeave={handleMouseUp} | |
| /> | |
| <button | |
| onClick={clearCanvas} | |
| className="mt-4 px-6 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors" | |
| > | |
| Clear Canvas | |
| </button> | |
| </div> | |
| ); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const WebSocket = require("ws"); | |
| const PORT = 3001; | |
| const wss = new WebSocket.Server({ port: PORT }); | |
| wss.on("connection", (ws) => { | |
| console.log("New client connected"); | |
| ws.on("message", (data) => { | |
| // Broadcast the incoming message to all clients except the sender. | |
| wss.clients.forEach((client) => { | |
| if (client !== ws && client.readyState === WebSocket.OPEN) { | |
| client.send(data); | |
| } | |
| }); | |
| }); | |
| ws.on("close", () => { | |
| console.log("Client disconnected"); | |
| }); | |
| }); | |
| console.log(`WebSocket server is running on ws://localhost:${PORT}`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment