使用HTML5的canvas畫布功能,在頁面進行繪畫,然后通過SignalR將畫布的每個點的顏色提交到服務端,服務端同時將這些畫布的信息推送到其他客戶端,實現共享同一個畫板的功能
類似下圖,在某一個瀏覽器進行繪畫,其他瀏覽器同步顯示內容,並且頁面刷新或者首次加載還能顯示之前的繪畫內容(站點不重啟的情況下)
實現過程
一、服務端
服務端的代碼主要功能是接收客戶端發送過來的繪畫坐標點和坐標點的顏色,同時將新的坐標點信息推送給客戶端,最后服務端還會保存這些繪畫坐標點信息到內存中,這樣客戶端刷新或者首次進入就能看到之前的繪畫信息。
step1:
創建一個Empty類型的ASP.NET 4.5的站點
step2:
引入SignalR的nuget包,將自動引入相關的關聯包
Install-Package Microsoft.AspNet.SignalR
step3:
新建一個SignalR Hub Class
實現代碼如下:

public class DrawingBoard : Hub { private const int BoardWidth = 300; private const int BoardHeight = 300; private static int[,] _pointBuffer = GetEmptyPointBuffer(); public Task DrawPoint(int x, int y) { if (x < 0) { x = 0; } if (x >= BoardWidth) { x = BoardWidth - 1; } if (y <0) { y = 0; } if (y >= BoardHeight) { y = BoardHeight - 1; } int color = 0; int.TryParse(Clients.Caller.color, out color); _pointBuffer[x, y] = color; return Clients.Others.drawPoint(x, y, Clients.Caller.color); } public Task Clear() { _pointBuffer = GetEmptyPointBuffer(); return Clients.Others.clear(); } public override Task OnConnected() { return Clients.Caller.update(_pointBuffer); } private static int[,] GetEmptyPointBuffer() { var buffer = new int[BoardWidth, BoardWidth]; return buffer; } }
step4:
新建一個startup類

public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } }
到此完成服務端的功能實現
二、客戶端
step1:
客戶端的html頁面只需要定義一個canvas元素和一個清除畫布的按鈕

<!DOCTYPE html> <html> <head> <title>在線畫板</title> <meta charset="utf-8" /> <style> div{ margin:3px; } canvas{ border:2px solid #808080; cursor:default; } </style> </head> <body> <div> <div> <label for="color">Color:</label> <select id="color"></select> </div> <canvas id="canvas" width="300" height="300"></canvas> <div> <button id="clear">Clear canvas</button> </div> </div> <script src="/Scripts/jquery-1.6.4.min.js"></script> <script src="/Scripts/jquery.signalR-2.2.0.min.js"></script> <script src="/signalr/js"></script> <script src="/Scripts/drawingboard.js"></script> </body> </html>
step2:
在scripts目錄創建drawingboard.js文件,實現主要的畫布操作和SingalR事件綁定。
主要是綁定了canvas的mousemove事件,然后再mousemove事件中實現繪畫,同時將繪畫的信息發送服務器,客戶端同時接收服務端推送的繪畫信息,實時提現在本地的畫布中。
客戶端連接成功之后,會獲得從服務端推送的歷史繪畫信息,實現記載之前畫布的效果

$(function () { // 畫布定義開始 var colors = ["black", "red", "green", "blue", "yellow", "magenta", "white"]; var canvas = $("#canvas"); var colorElement = $("#color"); for (var i = 0; i < colors.length; i++) { colorElement.append("<option value='" + (i + 1) + "'>" + colors[i] + "</option>"); } var buttonPressed = false; canvas .mousedown(function () { buttonPressed = true; }) .mouseup(function () { buttonPressed = false; }) .mousemove(function (e) { if (buttonPressed) { setPoint(e.offsetX, e.offsetY, colorElement.val()); } }); var ctx = canvas[0].getContext("2d"); function setPoint(x, y, color) { ctx.fillStyle = colors[color - 1]; ctx.beginPath(); ctx.arc(x, y, 2, 0, Math.PI * 2); ctx.fill(); } function clearPoints() { ctx.clearRect(0, 0, canvas.width(), canvas.height()); } $("#clear").click(function () { clearPoints(); }); // 畫布定義結束 // SignalR 客戶端代碼 var hub = $.connection.drawingBoard; hub.state.color = colorElement.val(); var connected = false; colorElement.change(function () { hub.state.color = $(this).val(); }); canvas.mousemove(function (e) { if (buttonPressed && connected) { hub.server.drawPoint(Math.round(e.offsetX), Math.round(e.offsetY)); } }); $("#clear").click(function () { if (connected) { hub.server.clear(); } }); // 定義客戶端方法 hub.client.clear = function () { clearPoints(); }; hub.client.drawPoint = function (x, y, color) { setPoint(x, y, color); }; hub.client.update = function (points) { if (!points) return; var width = canvas.width(); var height = canvas.height(); for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var color = points[x][y]; if (color > 0) { setPoint(x, y, color); } } } }; $.connection.hub.start().done(function () { connected = true; }); })
完整代碼下載