Files
ihk-projekt/Smartes-Klassenzimmer-Frontend/src/lib/stores/whiteboard.svelte.ts
2025-12-11 09:49:24 +01:00

187 lines
4.6 KiB
TypeScript

// 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<string>('default-room');
userId = $state<string>('');
activeUsers = $state<string[]>([]);
remoteCursors = $state<Map<string, RemoteCursor>>(new Map());
drawings = $state<DrawingData[]>([]);
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();