การดู : 0

12/04/2026 18:16น.

EP.120 Whiteboard & Real-time Drawing Synchronization ด้วย WebSocket

EP.120 Whiteboard & Real-time Drawing Synchronization ด้วย WebSocket

#WebSocket

#Golang The Series

#Golang

#Go

#whiteboard

หลังจากเราเรียนรู้การทำ Collaborative Document Editing (แบบตัวอักษร) มาแล้ว ตอนนี้ถึงเวลาขยับไปสู่สิ่งที่ "ท้าทายกว่า" การวาดรูปแบบเรียลไทม์ (Real-time Drawing)

 

Whiteboard App อย่าง Miro, FigJam หรือ Excalidraw จำเป็นต้องรองรับการทำงานที่ซับซ้อน เช่น

  • ผู้ใช้หลายคนวาดพร้อมกัน
  • การเคลื่อนไหวของเส้น รูปร่าง และ cursor แบบเรียลไทม์
  • Canvas ที่ต้อง sync เหมือนกันทุกคน
  • ระบบ Undo / Redo ที่ทำงานทันที
  • ความหน่วง (Latency) ต้องต่ำมาก

 

บทความนี้จะพาคุณออกแบบ Real-time Whiteboard System โดยใช้ Go + WebSocket เป็นแกนกลาง พร้อมแนวคิดที่สามารถนำไปใช้ได้จริงใน Production

 

🧠 ภาพรวม Architecture

 

Client (Canvas)
  ↕ WebSocket
Whiteboard Server (Go)
  ↕ Broadcast
Clients ทุกคนใน board เดียวกัน

 

องค์ประกอบหลัก

  • Canvas State – สถานะปัจจุบันของกระดาน
  • Draw Events – การวาดเส้นหรือรูปร่าง
  • Cursor Position – ตำแหน่งเมาส์ของแต่ละคน
  • History Stack – สำหรับ Undo / Redo
  • Room (Board) – แยกการวาดตาม board_id

 

✏️ 1. รูปแบบข้อมูลสำหรับ Drawing Event

 

เราไม่ส่งทั้ง Canvas ทุกครั้ง แต่ส่งเฉพาะ Draw Event

{
  "board_id": "board-001",
  "user_id": "user-a",
  "type": "draw",
  "tool": "pen",
  "points": [
    { "x": 120, "y": 240 },
    { "x": 122, "y": 245 }
  ],
  "color": "#FF0000",
  "stroke": 2
}

 

ประเภท Event ที่รองรับ:

  • draw (pen/brush)
  • shape (rectangle, circle, arrow)
  • cursor
  • undo, redo
  • clear

 

⚙️ 2. โครงสร้างข้อมูลฝั่ง Server (Go)

 

type DrawEvent struct {
	BoardID string      `json:"board_id"`
	UserID  string      `json:"user_id"`
	Type    string      `json:"type"`
	Tool    string      `json:"tool"`
	Points  []Point     `json:"points,omitempty"`
	Color   string      `json:"color,omitempty"`
	Stroke  int         `json:"stroke,omitempty"`
}

type Point struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

 

จัดการ Room แยกตาม board_id เพื่อให้ส่งเฉพาะกลุ่มที่ใช้งานร่วมกัน

 

🔄 3. Real-time Sync ด้วย WebSocket

 

var boards = make(map[string]map[*websocket.Conn]bool)

func handleWhiteboard(conn *websocket.Conn, boardID string) {
	if boards[boardID] == nil {
		boards[boardID] = make(map[*websocket.Conn]bool)
	}
	boards[boardID][conn] = true

	defer func() {
		delete(boards[boardID], conn)
		conn.Close()
	}()

	for {
		var event DrawEvent
		if err := conn.ReadJSON(&event); err != nil {
			return
		}
		broadcast(boardID, event)
	}
}

func broadcast(boardID string, event DrawEvent) {
	for c := range boards[boardID] {
		c.WriteJSON(event)
	}
}

 

ผลลัพธ์: ผู้ใช้ A วาด → ทุกคนเห็นทันที
Latency ต่ำ (ระดับ millisecond)

 

🖱️ 4. Mouse / Cursor Sync

 

เพื่อแสดงว่า “ใครกำลังทำอะไรอยู่บนกระดาน”

{
  "type": "cursor",
  "user_id": "user-b",
  "x": 450,
  "y": 300
}

 

  • Client ส่งตำแหน่งเมาส์ทุก ~50ms
  • Server broadcast → ทุก client แสดงตำแหน่ง cursor

 

↩️ 5. Undo / Redo แบบเรียลไทม์

 

แนวคิด:

  • ทุก draw event = 1 action
  • Stack per board (Undo, Redo)
type BoardHistory struct {
	Undo []DrawEvent
	Redo []DrawEvent
}

 

เมื่อ Undo:

  • pop จาก undo
  • push เข้า redo
  • broadcast event undo → ทุก client ลบ action ล่าสุด

 

⚡ 6. Performance Optimization

 

สิ่งที่ต้องคำนึงถึงเมื่อระบบมีผู้ใช้งานจำนวนมาก:

  • ส่งเฉพาะ delta (ไม่ส่งทั้งเส้น)
  • Throttle mouse event (30–60 fps)
  • Batch event ที่เกิดถี่ ๆ
  • ใช้ Binary Protocol สำหรับ board ขนาดใหญ่
  • แยก layer canvas (background / drawing / cursor)

 

🔐 7. Security & Access Control

 

ระบบควรมี:

  • Board Permission (read / write)
  • Rate Limit event ต่อวินาที
  • Validate Shape Data (กัน payload แปลก)
  • ป้องกัน flood draw / spam

 

🚀 ท้าให้ลอง!

 

Mini Project:

  • วาดพร้อมกัน 2–3 คน
  • Sync cursor แบบ real-time
  • Undo / Redo ทันที
  • เปิดหลาย tab → ต้อง sync กันเป๊ะ!

 

✅ ถ้าทำได้ครบ = คุณเข้าใจระบบ Real-time Drawing อย่างแท้จริง 🎯

 


 

🔮 EP ถัดไป: EP.121 Deploy WebSocket Server บน Kubernetes

 

ตอนหน้า เราจะนำ WebSocket Server ของคุณเข้าสู่โลก Production จริงจัง

 

คุณจะได้เรียนรู้:

  • การ Deploy ด้วย Kubernetes
  • Load Balancer และ Sticky Session
  • การรองรับ Auto Scaling สำหรับ WebSocket