多人共享、同时操作的电子白板,让不同的参入者以不同的颜色来画画;可以保存当前room的内容,以让后来者可以直接加载所有内容。
在github上找到一个用html5 canvas实现的一个电子白板的例子:
https://github.com/kblcuk/canvas-whiteboard
它是基于socket.io来实现多人白板的共享、操作。本文在它的基础上加上了房间,这样只有同一房间的人才会共享。
1 加入房间
客户端:
var roomName = location.search.split(‘?‘)[1];
// Init socket.io
App.socket = io.connect(‘http://localhost‘);
App.socket.emit(‘create‘, roomName);
服务端:
io.sockets.on(‘connection‘, function(socket) {
socket.on(‘create‘, function(room) {
socket.room = room;
socket.join(room);
//get existed image as soon as join room
io.sockets.in(socket.room).emit(‘setup‘, colors[i++], imageData[socket.room]);
});
……
2 后进房间的人,要可以看到前面所有的内容
io.sockets.in(socket.room).emit(‘setup‘, colors[i++], imageData[socket.room]);
3 只在房间内广播
服务端:
socket.emit(‘draw‘, data);
4 发送、接收
发送:
App.socket.emit(‘do-the-draw‘, data); // Broadcast draw.
注: 客户端发送时,不需要加上broadcast.to(socket.room)
接收:
// Broadcast all draw clicks.
socket.on(‘do-the-draw‘, function(data) {
socket.broadcast.to(socket.room).emit(‘draw‘, data);
imageData[socket.room] = data.imageData;
});
5. 客户端
客户端代码<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>White Board</title> <style> .whiteboard-canvas { margin: 0 auto; border: 1px solid yellowgreen } #clear { display: block; } </style> </head> <body> <script src="https://code.jquery.com/jquery-1.9.1.js"></script> <script src="/socket.io/socket.io.js"></script> <script> // Keep everything we need outside global scope var App = {}; var roomName = location.search.split(‘?‘)[1]; // Init socket.io App.socket = io.connect(‘http://localhost‘); App.socket.emit(‘create‘, roomName); // Flag to indicate whether we‘re currently drawing or not App._startedDrawing = false; /** * Do the draw. Acts differently * depending on event type passed. */ App.draw = function (data) { var originalColor = App.ctx.strokeStyle; App.ctx.strokeStyle = data.color; if (data.type == "mousedown") { // Start drawing App.ctx.beginPath(); App.ctx.moveTo(data.x, data.y) } else if (data.type == "mouseup") { // Stop drawing App.ctx.stroke(); App.ctx.closePath(); App._startedDrawing = false; App.socket.emit(‘save-data‘, App.whiteboard[0].toDataURL()); } else { // Continue App.ctx.lineTo(data.x, data.y); App.ctx.stroke(); } App.ctx.strokeStyle = originalColor; }; /** * We want to draw whenever we receive * ‘draw‘ event from other sockets as well. */ App.socket.on(‘draw‘, App.draw); /** * Clears the canvas. */ App.clear = function () { App.ctx.clearRect(0, 0, App.whiteboard[0].width, App.whiteboard[0].height); }; App.socket.on(‘clear‘, App.clear); /** * Fetch color that this user should * use for drawing. */ App.socket.on(‘setup‘, function (color, dataUrl) { App.ctx.strokeStyle = color; if (dataUrl) { // load image from data url var imageObj = new Image(); imageObj.onload = function () { App.ctx.drawImage(this, 0, 0); }; imageObj.src = dataUrl; } }); /** * Bind mouse events to our canvas once DOM has loaded. * At this point we are also ready to emit * ‘doTheDraw‘ events. */ $(function () { App.whiteboard = $(‘#whiteboard‘); App.ctx = App.whiteboard[0].getContext("2d"); // Connect mouse events App.whiteboard.on(‘mousedown mouseup mousemove‘, null, function (e) { if (!App._startedDrawing && e.type != "mousedown") return; App._startedDrawing = true; var offset = $(this).offset(); var data = { x: (e.pageX - offset.left), y: (e.pageY - offset.top), type: e.handleObj.type, color: App.ctx.strokeStyle, imageData: App.whiteboard[0].toDataURL() }; App.draw(data); // Draw yourself. App.socket.emit(‘do-the-draw‘, data); // Broadcast draw. }); // Clear button $(‘#clear‘).on(‘click‘, function () { App.clear(); // Clear our screen App.socket.emit(‘clear‘); // Broadcast clear. }); }); </script> <canvas id="whiteboard" width="700px" height="500px" class="whiteboard-canvas"></canvas> <button id="clear">Clear this up</button> </body> </html>
6. 服务端
服务端代码/** * Our app starts here. */ // Setup var express = require(‘express‘); var app = express(); var server = app.listen(3210, function() { console.log(‘Listening on port %d‘, server.address().port); }); var io = require(‘socket.io‘)(server); // Return canvas.html for whatever request we get. app.get(‘/‘, function(req, res) { res.sendFile(__dirname + ‘/canvas.html‘); }); // We will store image data here, so users that // connect after startup receive the current // state of the image. var imageData = {}; // Color palette by Skyblue2u: http://www.colourlovers.com/palette/580974/Adrift_in_Dreams // Nice one! var colors = ["#CFF09E", "#A8DBA8", "#79BD9A", "#3B8686", "#0B486B"]; var i = 0; // Setup emitters for each connection io.sockets.on(‘connection‘, function(socket) { // Each new user gets a different color if (i == 5) i = 0; socket.on(‘create‘, function(room) { socket.room = room; socket.join(room); //get existed image as soon as join room io.sockets.in(socket.room).emit(‘setup‘, colors[i++], imageData[socket.room]); }); // Broadcast all draw clicks. socket.on(‘do-the-draw‘, function(data) { socket.broadcast.to(socket.room).emit(‘draw‘, data); imageData[socket.room] = data.imageData; }); // ...and clear clicks as well socket.on(‘clear‘, function() { socket.broadcast.to(socket.room).emit(‘clear‘); imageData[socket.room] = null; }); // Users modified image, let‘s save it socket.on(‘save-data‘, function(data) { imageData[socket.room] = data; }); });
http://yunpan.cn/cHFzQ2S9HpzeQ 访问密码 80a3
一步一步搭建客服系统
.