// Whiteboard WebSocket Store mit Svelte 5 Runes import { io, Socket } from 'socket.io-client'; export interface Point { x: number; y: number; } export type DrawingTool = 'pen' | 'eraser' | 'line' | 'rectangle' | 'circle' | 'text'; export interface DrawingData { id: string; whiteboardId: string; tool: DrawingTool; points: Point[]; color?: string; lineWidth?: number; text?: string; userId: string; timestamp: number; } export interface RemoteCursor { userId: string; x: number; y: number; } class WhiteboardStore { socket: Socket | null = null; connected = $state(false); whiteboardId = $state('default-room'); userId = $state(''); activeUsers = $state([]); remoteCursors = $state>(new Map()); drawings = $state([]); connect(whiteboardId: string, userId: string) { this.whiteboardId = whiteboardId; this.userId = userId; if (this.socket) return; this.socket = io(`http://${window.location.hostname}:3000/whiteboard`, { withCredentials: true, transports: ['websocket', 'polling'] }); this.setupEventListeners(); // Dem Whiteboard beitreten this.socket.emit('join-whiteboard', { whiteboardId, userId }); } private setupEventListeners() { if (!this.socket) return; this.socket.on('connect', () => { console.log('✅ Connected to whiteboard'); this.connected = true; }); this.socket.on('disconnect', () => { console.log('❌ Disconnected from whiteboard'); this.connected = false; }); // Empfange aktuelle Whiteboard-Daten this.socket.on('whiteboard-state', (drawings: DrawingData[]) => { console.log('📥 Received whiteboard state:', drawings.length, 'drawings'); this.drawings = drawings; }); // Empfange neue Zeichnungen von anderen Benutzern this.socket.on('drawing', (drawing: DrawingData) => { console.log('🎨 Received drawing from user:', drawing.userId); this.drawings = [...this.drawings, drawing]; }); // Benutzer ist beigetreten this.socket.on('user-joined', (data: { userId: string; activeUsers: string[] }) => { console.log('👋 User joined:', data.userId); this.activeUsers = data.activeUsers; }); // Benutzer hat verlassen this.socket.on('user-left', (data: { userId: string; activeUsers: string[] }) => { console.log('👋 User left:', data.userId); this.activeUsers = data.activeUsers; // Entferne Cursor des Benutzers this.remoteCursors.delete(data.userId); }); // Whiteboard wurde gelöscht this.socket.on('whiteboard-cleared', (data: { userId: string }) => { console.log('🗑️ Whiteboard cleared by:', data.userId); this.drawings = []; }); // Cursor-Position von anderen Benutzern this.socket.on('cursor-position', (data: { userId: string; x: number; y: number }) => { this.remoteCursors.set(data.userId, { userId: data.userId, x: data.x, y: data.y }); // Trigger reaktivität this.remoteCursors = new Map(this.remoteCursors); }); // Undo wurde angefordert this.socket.on('undo-requested', (data: { userId: string }) => { console.log('↩️ Undo requested by:', data.userId); // Hier könnte man Undo-Logik implementieren }); } sendDrawing(tool: DrawingTool, points: Point[], color: string, lineWidth: number, text?: string, id?: string) { if (!this.socket || !this.connected) { console.error('❌ Not connected to whiteboard'); return; } const drawingData: DrawingData = { id: id || `${Date.now()}-${Math.random()}`, whiteboardId: this.whiteboardId, tool, points, color, lineWidth, text, userId: this.userId, timestamp: Date.now() }; console.log('📤 Sending drawing:', tool, 'points:', points.length); // Füge die Zeichnung sofort lokal hinzu (optimistische Update) this.drawings = [...this.drawings, drawingData]; // Sende an den Server (wird nur an andere Clients weitergeleitet) this.socket.emit('draw', drawingData); } clearWhiteboard() { if (!this.socket || !this.connected) { console.error('❌ Not connected to whiteboard'); return; } this.socket.emit('clear-whiteboard', { whiteboardId: this.whiteboardId, userId: this.userId }); // Lösche lokal this.drawings = []; } sendCursorPosition(x: number, y: number) { if (!this.socket || !this.connected) return; this.socket.emit('cursor-move', { whiteboardId: this.whiteboardId, userId: this.userId, x, y }); } disconnect() { if (this.socket) { this.socket.disconnect(); this.socket = null; } this.connected = false; this.activeUsers = []; this.remoteCursors = new Map(); this.drawings = []; } } export const whiteboardStore = new WhiteboardStore();