Files
hakorune/examples/wasm/10_collaborative_drawing.hako

426 lines
12 KiB
Plaintext
Raw Permalink Normal View History

// 🎨 Collaborative Drawing Board Demo - WebCanvasBox + CanvasEventBox + P2P simulation
// Multi-user drawing application with Everything is Box architecture
print("🎨 === Collaborative Drawing Board Demo Starting ===")
// Initialize components
local canvas, events, timer, random
canvas = new WebCanvasBox("demo-canvas", 800, 600)
events = new CanvasEventBox("demo-canvas")
timer = new TimerBox()
random = new RandomBox()
// Drawing application state
local drawingState
drawingState = {
isDrawing: false,
tool: "brush", // brush, eraser, line, rectangle, circle, text
color: "#000000",
size: 3,
users: [],
history: [],
maxHistory: 50
}
// User management (simulated multiplayer)
local users
users = [
{id: 1, name: "Alice", color: "#e74c3c", cursor: {x: 100, y: 100}, isActive: true},
{id: 2, name: "Bob", color: "#3498db", cursor: {x: 200, y: 150}, isActive: true},
{id: 3, name: "Charlie", color: "#2ecc71", cursor: {x: 300, y: 200}, isActive: false},
{id: 4, name: "Diana", color: "#9b59b6", cursor: {x: 150, y: 250}, isActive: true}
]
// Tool palette
local tools
tools = [
{name: "brush", icon: "🖌️", size: 3},
{name: "eraser", icon: "🧽", size: 10},
{name: "line", icon: "📏", size: 2},
{name: "rectangle", icon: "⬜", size: 2},
{name: "circle", icon: "⭕", size: 2},
{name: "text", icon: "📝", size: 16}
]
// Color palette
local colorPalette
colorPalette = [
"#000000", "#ffffff", "#e74c3c", "#3498db", "#2ecc71",
"#f39c12", "#9b59b6", "#1abc9c", "#34495e", "#95a5a6",
"#e67e22", "#e91e63", "#673ab7", "#ff5722", "#795548"
]
// Drawing functions
local drawBrushStroke
drawBrushStroke = function(x1, y1, x2, y2, color, size) {
canvas.setStrokeStyle(color)
canvas.setLineWidth(size)
canvas.drawLine(x1, y1, x2, y2, color, size)
// Add to history
local stroke
stroke = {
type: "brush",
x1: x1, y1: y1, x2: x2, y2: y2,
color: color, size: size,
timestamp: timer.now()
}
drawingState.history.push(stroke)
}
local drawShape
drawShape = function(shape, x1, y1, x2, y2, color, size, filled) {
canvas.setStrokeStyle(color)
canvas.setLineWidth(size)
if (filled) {
canvas.setFillStyle(color)
}
if (shape == "rectangle") {
local width, height
width = x2 - x1
height = y2 - y1
if (filled) {
canvas.fillRect(x1, y1, width, height)
} else {
canvas.strokeRect(x1, y1, width, height)
}
} else if (shape == "circle") {
local centerX, centerY, radius
centerX = (x1 + x2) / 2
centerY = (y1 + y2) / 2
radius = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) / 2
if (filled) {
canvas.fillCircle(centerX, centerY, radius)
} else {
canvas.strokeCircle(centerX, centerY, radius)
}
} else if (shape == "line") {
canvas.drawLine(x1, y1, x2, y2, color, size)
}
// Add to history
local shapeData
shapeData = {
type: shape,
x1: x1, y1: y1, x2: x2, y2: y2,
color: color, size: size, filled: filled,
timestamp: timer.now()
}
drawingState.history.push(shapeData)
}
local drawText
drawText = function(text, x, y, color, size) {
canvas.setFillStyle(color)
canvas.fillText(text, x, y, size + "px Arial", color)
// Add to history
local textData
textData = {
type: "text",
text: text, x: x, y: y,
color: color, size: size,
timestamp: timer.now()
}
drawingState.history.push(textData)
}
// UI Drawing functions
local drawToolbar
drawToolbar = function() {
// Toolbar background
canvas.setFillStyle("#f8f9fa")
canvas.fillRect(0, 0, 800, 60)
canvas.setStrokeStyle("#dee2e6")
canvas.setLineWidth(1)
canvas.strokeRect(0, 0, 800, 60)
// Tools section
canvas.setFillStyle("#495057")
canvas.fillText("🛠️ Tools", 10, 20, "14px Arial", "#495057")
local i, tool, x, y
i = 0
loop(i < tools.length()) {
tool = tools[i]
x = 10 + i * 45
y = 25
// Tool button
if (tool.name == drawingState.tool) {
canvas.setFillStyle("#007bff")
} else {
canvas.setFillStyle("#6c757d")
}
canvas.fillRect(x, y, 35, 25)
// Tool icon
canvas.setFillStyle("#ffffff")
canvas.fillText(tool.icon, x + 8, y + 18, "16px Arial", "#ffffff")
i = i + 1
}
// Colors section
canvas.setFillStyle("#495057")
canvas.fillText("🎨 Colors", 300, 20, "14px Arial", "#495057")
i = 0
loop(i < colorPalette.length()) {
x = 300 + (i % 10) * 25
y = 25 + Math.floor(i / 10) * 20
canvas.setFillStyle(colorPalette[i])
canvas.fillRect(x, y, 20, 15)
// Current color indicator
if (colorPalette[i] == drawingState.color) {
canvas.setStrokeStyle("#007bff")
canvas.setLineWidth(3)
canvas.strokeRect(x - 2, y - 2, 24, 19)
} else {
canvas.setStrokeStyle("#000000")
canvas.setLineWidth(1)
canvas.strokeRect(x, y, 20, 15)
}
i = i + 1
}
// Size control
canvas.setFillStyle("#495057")
canvas.fillText("📏 Size: " + drawingState.size, 600, 20, "14px Arial", "#495057")
// Size slider representation
canvas.setStrokeStyle("#6c757d")
canvas.setLineWidth(2)
canvas.drawLine(600, 35, 700, 35, "#6c757d", 2)
// Size indicator
local sliderPos
sliderPos = 600 + (drawingState.size / 20) * 100
canvas.setFillStyle("#007bff")
canvas.fillCircle(sliderPos, 35, 6)
}
local drawUserCursors
drawUserCursors = function() {
local i, user
i = 0
loop(i < users.length()) {
user = users[i]
if (user.isActive) {
// Cursor dot
canvas.setFillStyle(user.color)
canvas.fillCircle(user.cursor.x, user.cursor.y, 8)
// User name label
canvas.setFillStyle("#ffffff")
canvas.fillRect(user.cursor.x + 15, user.cursor.y - 15, user.name.length() * 8, 20)
canvas.setStrokeStyle(user.color)
canvas.setLineWidth(2)
canvas.strokeRect(user.cursor.x + 15, user.cursor.y - 15, user.name.length() * 8, 20)
canvas.setFillStyle(user.color)
canvas.fillText(user.name, user.cursor.x + 18, user.cursor.y - 2, "12px Arial", user.color)
}
i = i + 1
}
}
local drawUserList
drawUserList = function() {
// Users panel
canvas.setFillStyle("#f8f9fa")
canvas.fillRect(680, 70, 115, 120)
canvas.setStrokeStyle("#dee2e6")
canvas.strokeRect(680, 70, 115, 120)
canvas.setFillStyle("#495057")
canvas.fillText("👥 Users", 690, 90, "14px Arial", "#495057")
local i, user, y
i = 0
loop(i < users.length()) {
user = users[i]
y = 105 + i * 20
// Status indicator
if (user.isActive) {
canvas.setFillStyle("#28a745")
canvas.fillCircle(690, y, 4)
} else {
canvas.setFillStyle("#6c757d")
canvas.fillCircle(690, y, 4)
}
// User name with color
canvas.setFillStyle(user.color)
canvas.fillText(user.name, 700, y + 5, "12px Arial", user.color)
i = i + 1
}
}
local drawCanvas
drawCanvas = function() {
// Canvas area (below toolbar)
canvas.setFillStyle("#ffffff")
canvas.fillRect(0, 60, 800, 540)
// Canvas border
canvas.setStrokeStyle("#dee2e6")
canvas.setLineWidth(2)
canvas.strokeRect(0, 60, 800, 540)
}
// Main drawing function
local drawCollaborativeBoard
drawCollaborativeBoard = function() {
// Clear entire canvas
canvas.clear()
// Draw main components
drawCanvas()
drawToolbar()
drawUserCursors()
drawUserList()
// Status bar
canvas.setFillStyle("#f8f9fa")
canvas.fillRect(0, 580, 800, 20)
canvas.setStrokeStyle("#dee2e6")
canvas.strokeRect(0, 580, 800, 20)
canvas.setFillStyle("#6c757d")
canvas.fillText("Connected users: " + users.length() + " | Tool: " + drawingState.tool + " | History: " + drawingState.history.length(), 10, 595, "12px Arial", "#6c757d")
}
// Simulate collaborative drawing
local simulateCollaborativeActivity
simulateCollaborativeActivity = function() {
// Simulate user drawing activities
local i, user
i = 0
loop(i < users.length()) {
user = users[i]
if (user.isActive) {
// Move cursor randomly
user.cursor.x = user.cursor.x + random.randInt(-20, 20)
user.cursor.y = user.cursor.y + random.randInt(-20, 20)
// Keep cursor in bounds
user.cursor.x = Math.max(50, Math.min(750, user.cursor.x))
user.cursor.y = Math.max(100, Math.min(550, user.cursor.y))
// Occasionally draw something
if (random.randInt(0, 10) == 0) {
local x1, y1, x2, y2
x1 = user.cursor.x
y1 = user.cursor.y
x2 = x1 + random.randInt(-30, 30)
y2 = y1 + random.randInt(-30, 30)
drawBrushStroke(x1, y1, x2, y2, user.color, 3)
}
}
i = i + 1
}
}
// Initialize the drawing board
drawCollaborativeBoard()
// Add some sample collaborative content
drawText("🎨 Collaborative Nyash Drawing", 250, 120, "#2c3e50", 24)
drawText("Everything is Box - even teamwork!", 270, 150, "#7f8c8d", 16)
// Draw some sample collaborative strokes
drawBrushStroke(100, 200, 150, 250, "#e74c3c", 5)
drawBrushStroke(150, 250, 200, 200, "#3498db", 4)
drawShape("circle", 300, 200, 350, 250, "#2ecc71", 3, false)
drawShape("rectangle", 400, 180, 500, 280, "#f39c12", 2, false)
// Run simulation
local simulationFrames
simulationFrames = 0
loop(simulationFrames < 5) {
simulateCollaborativeActivity()
drawCollaborativeBoard()
simulationFrames = simulationFrames + 1
}
print("🎨 Collaborative Drawing Board Demo Ready!")
print("• Connected users: " + users.length())
print("• Active users: " + (users.filter(function(u) { return u.isActive }).length()))
print("• Available tools: " + tools.length())
print("• Color palette: " + colorPalette.length() + " colors")
print("• Drawing history: " + drawingState.history.length() + " actions")
// Demo advanced collaboration features
print("🌟 Collaboration features demonstrated:")
print("• Real-time user cursors with names")
print("• User presence indicators")
print("• Shared drawing canvas with history")
print("• Multi-tool support (brush, shapes, text)")
print("• Professional UI with tool palette")
print("• Color selection and size controls")
// Show P2P concepts (simulated)
local p2pFeatures
p2pFeatures = [
"Real-time stroke synchronization",
"User presence broadcasting",
"Conflict resolution for simultaneous edits",
"Canvas state synchronization",
"Chat integration",
"File sharing and export"
]
canvas.setFillStyle("#17a2b8")
canvas.fillRect(500, 300, 200, 120)
canvas.setStrokeStyle("#138496")
canvas.strokeRect(500, 300, 200, 120)
canvas.setFillStyle("#ffffff")
canvas.fillText("🔗 P2P Features:", 510, 320, "14px Arial", "#ffffff")
local j
j = 0
loop(j < 4) { // Show first 4 features
canvas.fillText("• " + p2pFeatures[j].substring(0, 15) + "...", 510, 340 + j * 15, "10px Arial", "#ffffff")
j = j + 1
}
print("🔗 P2P architecture concepts:")
j = 0
loop(j < p2pFeatures.length()) {
print(" • " + p2pFeatures[j])
j = j + 1
}
// Performance statistics
local performanceStats
performanceStats = {
drawCalls: drawingState.history.length(),
activeConnections: users.filter(function(u) { return u.isActive }).length(),
memoryUsage: drawingState.history.length() * 50, // Estimated bytes
latency: random.randInt(15, 45) // Simulated ms
}
print("📊 Performance metrics:")
print(" • Draw calls: " + performanceStats.drawCalls)
print(" • Active connections: " + performanceStats.activeConnections)
print(" • Memory usage: " + performanceStats.memoryUsage + " bytes")
print(" • Network latency: " + performanceStats.latency + "ms")
print("🌐 Everything is Box - even creativity is collaborative!")
print("✅ Collaborative Drawing Board Demo Complete!")