使用HTML5+Singalr搭建多机协同画板(一)
虽然,HTML5出来好久了,但是,直到最近才开始学习。我就把最近的一些学习心得,通过这篇文章分享一下。
这个小例子使用Singalr作为底层通信的基础,与服务器进行交互。画板则使用Html5的canvas来实现。这一部分就先讲前端的部分。
1. 新建一个Javascript文件,这里叫做jDraw.js
1 (function ($) { 2 var methods = {}; 3 $.fn.jDraw = function (method) { 4 if (methods[method]) { 5 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 6 } else if (typeof method === 'object' || !method) { 7 return methods.init.apply(this, arguments); 8 } else { 9 $.error('Method ' + method + ' does not exist on DrawJS'); 10 } 11 }; 12 })(jQuery);
2. 我们为 jDraw.js 中的methods 添加一些方法,包括获取监控鼠标事件,以及各种画图功能的方法:
1 var methods = { 2 init: function (options) { 3 //初始化配置 4 var settings = { 5 backgroundColor: '#fff', 6 lineColor: '#bb2646', 7 drawType: 'pen' 8 }; 9 settings = $.extend(settings, options); 10 return this.each(function () { 11 var $this = $(this); 12 var data = $this.data('jDraw'); 13 if (!data) { 14 $(this).data('jDraw', { 15 target: $this, 16 jDraw: { 17 firstCoords: { X: -1, Y: -1 }, 18 lastCoords: { X: -1, Y: -1 }, 19 coords: { X: -1, Y: -1 } 20 }, 21 settings: settings 22 }); 23 } 24 $this.bind('mouseenter.jDraw', methods.mouseenter); 25 $this.bind('mousedown.jDraw', methods.mousedown); 26 $this.bind('mousemove.jDraw', methods.mousemove); 27 $this.jDraw('clear'); 28 }); 29 }, 30 destroy: function () { 31 return this.each(function () { 32 $(window).unbind('.jDraw'); 33 data.jDraw.remove(); 34 $this.removeData('jDraw'); 35 $(window).unbind('mousemove.jDraw', methods.enter); 36 $(window).unbind('mousedown.jDraw', methods.mousedown); 37 $(window).unbind('mousemove.jDraw', methods.mousemove); 38 }) 39 }, 40 mousedown: function (args) { 41 var $this = $(this); 42 var data = $this.data('jDraw').jDraw; 43 var settings = $this.data('jDraw').settings; 44 data.firstCoords.X = args.offsetX; 45 data.firstCoords.Y = args.offsetY; 46 }, 47 mousemove: function (args) { 48 var $this = $(this); 49 var data = $this.data('jDraw').jDraw; 50 var settings = $this.data('jDraw').settings; 51 data.coords.X = args.offsetX; 52 data.coords.Y = args.offsetY; 53 data.lastCoords.X = data.coords.X; 54 data.lastCoords.Y = data.coords.Y; 55 }, 56 mouseenter: function (args) { 57 var $this = $(this); 58 var data = $this.data('jDraw').jDraw; 59 data.lastCoords.X = args.offsetX; 60 data.lastCoords.Y = args.offsetY; 61 }, 62 clear: function (options) { 63 //清除画布的方法 64 }, 65 setDrawType: function (drawType) { 66 var $this = $(this); 67 var settings = $this.data('jDraw').settings; 68 settings.drawType = drawType; 69 }, 70 setLineColor: function (color) { 71 var $this = $(this); 72 var settings = $this.data('jDraw').settings; 73 settings.lineColor = color; 74 }, 75 pen: function (data) { 76 //实现画笔的方法 77 }, 78 brush: function (data) { 79 //实现刷子的方法 80 }, 81 rect: function (data) { 82 //实现画矩形的方法 83 }, 84 circle: function (data) { 85 //实现画圆的方法 86 }, 87 text: function (data) { 88 //实现文本的方法 89 }, 90 pic: function (data) { 91 //实现在画布上显示图片的方法 92 }, 93 cut: function (data) { 94 //实现裁剪的方法 95 }, 96 zoom: function (data) { 97 //实现缩放功能 98 }, 99 selectImg: function (data) { 100 //实现区域搜索功能 101 } 102 };
3. 当然,现在是不支持移动设备上的, 为了可以在移动设备上运行,我们还得处理移动设备上的touch事件:
1 //在jDraw.js中加入这几行代码,用来判断是否移动设备 2 var isPad = false; 3 if (navigator.userAgent.match(/mobile/i)) 4 isPad = true;
4. 为jDraw.js 中的 methods 增加移动设备上的touch事件监控:
1 init: function (options) { 2 //...省略... 3 return this.each(function () { 4 //...省略... 5 if (isPad) { 6 $this.bind('touchstart.jDraw', methods.touchstart); 7 $this.bind('touchenter.jDraw', methods.touchenter); 8 $this.bind('touchmove.jDraw', methods.touchmove); 9 $this.bind('touchend.jDraw', methods.touchend); 10 } else { 11 $this.bind('mouseenter.jDraw', methods.mouseenter); 12 $this.bind('mousedown.jDraw', methods.mousedown); 13 $this.bind('mousemove.jDraw', methods.mousemove); 14 } 15 $this.jDraw('clear'); 16 }); 17 },
5. 相应的,我们也要更改回收的方法:
1 destroy: function () { 2 return this.each(function () { 3 $(window).unbind('.jDraw'); 4 data.jDraw.remove(); 5 $this.removeData('jDraw'); 6 if (isPad) { 7 $(window).unbind('touchstart.jDraw', methods.touchstart); 8 $(window).unbind('touchenter.jDraw', methods.touchenter); 9 $(window).unbind('touchmove.jDraw', methods.touchmove); 10 $(window).unbind('touchend.jDraw', methods.touchend); 11 } else { 12 $(window).unbind('mousemove.jDraw', methods.enter); 13 $(window).unbind('mousedown.jDraw', methods.mousedown); 14 $(window).unbind('mousemove.jDraw', methods.mousemove); 15 } 16 }) 17 }
6. 我们增加了 touchstart, touchenter, touchmove, touchend 四个方法来监控用户在移动设备上的触摸事件,下面为四个方法的具体实现:
1 touchstart: function (args) { 2 $this = $(this); 3 isDraw = true; 4 var event = args.originalEvent.targetTouches[0]; 5 var data = $this.data('jDraw').jDraw; 6 data.firstCoords.X = args.pageX; 7 data.firstCoords.Y = args.pageY; 8 data.lastCoords.X = args.offsetX; 9 data.lastCoords.Y = args.offsetY; 10 }, 11 touchenter: function (args) { 12 $this = $(this); 13 var event = args.originalEvent.targetTouches[0]; 14 var data = $this.data('jDraw').jDraw; 15 data.lastCoords.X = args.pageX; 16 data.lastCoords.Y = args.pageY; 17 }, 18 touchmove: function (args) { 19 var $this = $(this); 20 var data = $this.data('jDraw').jDraw; 21 var settings = $this.data('jDraw').settings; 22 var event = args.originalEvent.targetTouches[0]; 23 data.coords.X = args.offsetX; 24 data.coords.Y = args.offsetY; 25 } 26 data.lastCoords.X = data.coords.X; 27 data.lastCoords.Y = data.coords.Y; 28 }, 29 touchend: function (args) { 30 var event = args.originalEvent; 31 if (event.changedTouches) 32 isDraw = false; 33 }
7. 上面的 isDraw 是定义为全局的变量(全局变量是魔鬼。。。),用来判别移动设备上是否画上。
8. 上面提供的画图方法很多,这里提供个画线的方法,也就是实现methods中的pen这个方法:
1 pen: function (data) { 2 var $this = $(this); 3 var context = $this.get(0).getContext('2d'); 4 //实现铅笔代码... 5 context.strokeStyle = data.Color; 6 context.lineWidth = 5; 7 context.beginPath(); 8 context.moveTo(data.From.X, data.From.Y); 9 context.lineTo(data.To.X, data.To.Y); 10 context.fill(); 11 context.stroke(); 12 context.closePath(); 13 $this.trigger('pen.jDraw', data); 14 }
9. 其他方法的只要相应的实现就可以了,这里不再累赘。那什么时候执行 pen 这个方法呢? 是在鼠标按住并且移动的时候,那我们必须监控鼠标是否被按住,在jDraw.js中添加监控鼠标是否按住的方法:
1 //for PC 2 var leftButtonDown = false; 3 //for Pad or Mobile 4 var isDraw = false; 5 6 $(document).mousedown(function (e) { 7 if (e.which === 1) 8 leftButtonDown = true; 9 }); 10 $(document).mouseup(function (e) { 11 if (e.which === 1) 12 leftButtonDown = false; 13 }); 14 15 function tweakMouseMoveEvent(e) { 16 if ($.browser.msie && !(document.documentMode >= 9) && !event.button) { 17 leftButtonDown = false; 18 } 19 if (e.which === 1 && !leftButtonDown) 20 e.which = 0; 21 };
10. 在 mousemove 和 touchmove 中实现画图功能,(对于定点绘图,则分别实现在mousedown 和 touchenter 中):
1 mousemove: function (args) { 2 tweakMouseMoveEvent(args); 3 var $this = $(this); 4 var data = $this.data('jDraw').jDraw; 5 var settings = $this.data('jDraw').settings; 6 data.coords.X = args.offsetX; 7 data.coords.Y = args.offsetY; 8 //过滤掉定点绘图的方法 9 if (args.which == 1 && settings.drawType != 'text' && settings.drawType != 'pic') { 10 //drawType为各种方法名,如 pen, brush等 11 $this.jDraw(settings.drawType, { 12 From: { 13 X: data.lastCoords.X, 14 Y: data.lastCoords.Y 15 }, To: { 16 X: data.coords.X, 17 Y: data.coords.Y 18 }, First: { 19 X: data.firstCoords.X, 20 Y: data.firstCoords.Y 21 }, 22 Color: settings.lineColor, 23 DrawType: settings.drawType 24 }); 25 } 26 data.lastCoords.X = data.coords.X; 27 data.lastCoords.Y = data.coords.Y; 28 }
这样,就把各种绘图方法跟鼠标事件绑定。
12. 页面中如何使用该文件,首先,要引入 jquery.js 和 jDraw.js :
1 <script src="../Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> 2 <script src="../Scripts/jDraw.js" type="text/javascript"></script>
13. 页面中创建canvas对象:
1 <canvas id="whiteBoard"> 2 <p>Unsupported brower</p> 3 </canvas>
14. 简单的使用:
1 $('#whiteBoard').jDraw().bind('pen.jDraw', function (event, args) { 2 args.Color = drawColor; 3 args.DrawType = dt; 4 $('#whiteBoard').jDraw('pen', args); 5 });
下一篇将结合Singalr,实现多机协同画板等功能。
初接触HTML5,Javascript也算新手,难免很多地方写的不好及有些错误,请不吝指正,谢谢。
多聚旅游 聚游宝 学友网