基于HTML5 Canvas和jQuery 的画图工具的实现

简介

    HTML5 提供了强大的Canvas元素,使用Canvas并结合Javascript 可以实现一些非常强大的功能。本文就介绍一下基于HTML5 Canvas 的画图工具的实现。废话少说,先看成品:

  该应用是遵循所见即所得(WYSIWYG, What you see is what you get)原则设计的,它具有以下功能:

1. 可以绘制自由曲线、直线、矩形框和文字;

2. 可以根据需要定义线段和矩形框的颜色和宽度;

3. 你可以需要字体的大小、颜色、字体;

4. 支持undo、redo操作;

5. 支持橡皮擦功能;

6. 支持本地图片保存功能。

源码下载        读者可以去我的GitHub jPainter 项目下下载,或者直接使用git 工具:https://github.com/LuanLouis/jPainter.git

开发心得分享

上述功能的实现,难点倒不是很多,值得一提的有以下几点:

1.  鼠标按下并移动 事件应该怎样实现 

2. 怎样实现所见即所得  的设计

3. undo redo 的实现原理

4. 画板信息另存为图片

鼠标按下并移动 事件应该怎样实现 

         如果我们在画板想画自由曲线,我们需要捕获鼠标按下并拖动的过程中 拖动的轨迹。那么怎样捕获这样的事件呢? 熟悉javascript 事件的读者应该知道,鼠标移动事件的句柄是 onmousemove,有的读者可能认为,可以直接为onmousemove 绑定事件处理函数,从event事件对象的button属性来判断是鼠标的哪一个键点击不就行了吗?代码如下:

[javascript]  view plain copy print ?
  1. $(function() {  
  2.     $(document).mousemove(function(e){  
  3.         console.log(e.button+"  "+e.which);  
  4.     })  
  5. });  
而实际上,上述的代码运行时,当我们在页面上无论是点击鼠标的哪个键,都是输出如下的信息:

从输出的结果可以看出,结果和我们预期的并不一样。这是为什么呢?

 原因是:  javascript的事件机制是这样的,当用户触发了事件之后,javascript宿主-浏览器会将事件封装成event对象,然后根据事件的类型对event属性进行赋值。然后根据event的类型,根据什么类型的事件来调用相应的事件处理函数。举例来说,如果我们在界面上按下了鼠标的右键,那么,浏览器会首先创建一个event对象,然后对event属性赋值,而相应的button会被置为2、which为3表示右键被按下;然后javascript 会将此event对象作为参数传递给相应的事件处理函数,执行事件处理函数。也就是说,event的button属性(以及jquery封装后的which属性)只有当 click、mousedown,mousup 对应的事件处理函数才有意义。

那么,我们怎样才能判断当鼠标移动时,鼠标键是否被按下呢?

解决方法:鼠标按下和松开是个过程,我们可以设置一个 flag,在鼠标按下的时候置为true,鼠标松开的时候置为false,然后在鼠标移动的事件处理函数中判断这个flag,进而可以区分鼠标是否被按下。

假设我们需要在<body> 元素上捕获 相应的鼠标事件,以下是使用jquery 进行事件处理函数的绑定:

[javascript]  view plain copy print ?
  1.     //onmousemove 事件  
  2.     $("body").mousemove(function(e){  
  3.           if(flag)  
  4.   
  5.           {  
  6.                 // 鼠标被按下  
  7.           }  
  8.   
  9.  })  
  10.   
  11. //onmousedown事件  
  12. $("body").onmousedown(function(e){  
  13.      flag = true;   
  14.   
  15.         // 事件处理  
  16. })  
  17.   
  18. //onmouseup事件  
  19. $("body").mouseup(function(e){  
  20.      flag = false;  
  21.   
  22.          // 事件处理  
  23. })  

            当然,如果读者有其他的实现方案,还请不吝赐教,共同学习!

怎样实现所见即所得的设计

       使用Canvas绘图时,其绘图是通过javascript控制的,比如,我想绘制一个矩形,应该使用类似以下的代码:

[javascript]  view plain copy print ?
  1. var c=document.getElementById("myCanvas");  
  2. var cxt=c.getContext("2d");  
  3. cxt.fillStyle="#FF0000";  
  4. cxt.fillRect(0,0,150,75);  
        但是对于对于可交互的用户界面,如果想创建一个矩形,应该是通过鼠标在画板上拖动,然后可以随时看到我将要画的矩形的大小、边框、颜色等等。怎样让用户可以看到动态的效果呢? 当然了,使用canvas 肯定是实现不了的,这里我想到了一个方法,就是 使用<DIV> 元素模拟我们需要绘制的矩形,当用户在拖动鼠标的过程中,使用DIV 显示矩形的信息,一旦用户松开鼠标,那么,将此DIV隐藏,根据鼠标的轨迹以及矩形配置,使用javascript绘制在对应的形状。

类似地,绘画直线和添加文字也是通过HTML伪装的逻辑:

绘画直线时,用户在画板上拖动并按下鼠标时,动态地显示出一条使用HTML伪装的直线,可以随着用户鼠标的移动而变化,当用户松开鼠标时,对应模拟直线的HTML元素隐藏,调用javavscript绘制真正的直线;

添加文字时,这里使用的<textarea>元素 进行模拟文本输入框,当用户在画板上添加文字时,可以拖动鼠标设置输入框的大小,然后输入文字,一旦输入框失去焦点,则隐藏此<textarea> 元素,然后使用javascript绘制相应的文字

undo redo 的实现原理

      在介绍 undo  redo 的实现之前,要先讲一下canvas的toDataURL()方法。toDataURL()方法将canvas上所绘制的内容转换成格式png格式图片,并将图片通过base64编码,转换成形如如:data:image/png;base64,iVBORw0KGg.......  的字符串,用来表示图片数据。(PS:对此比较困惑的读者可以自行查找关于HTML 图片 BASE64 存储的相关问题,这个知识点还是很重要的)

      undo redo 的原理实际上很简单,就是当每执行一次绘画,则将画板的内容转换成base64编码的字符串,存到缓存数组中去,然后在需要undo 的时候,将画板清空,再将缓存数组中的最后一次编辑的图片绘制到画板上即可。相关的实现细节如下代码所示:

[javascript]  view plain copy print ?
  1.    //undo redo  
  2.    var history =new Array();  
  3.       var cStep = -1;  
  4.   
  5.                   /** 
  6.     * put current canvas to cache 
  7.     */  
  8.    function historyPush()  
  9.    {  
  10.        cStep++;  
  11.           if (cStep < history.length)   
  12.           {   
  13.                 history.length = cStep;   
  14.           }  
  15.    
  16.           history.push($("#myCanvas").get(0).toDataURL());  
  17.    }  
  18.       /** 
  19.        * function: undo  
  20.        */  
  21.       function undo()  
  22.       {  
  23.           if (cStep >= 0)   
  24.           {  
  25.               cStep--;  
  26.               var tempImage = new Image();  
  27.               tempImage.src = history[cStep];  
  28.               tempImage.onload = function () { ctx.drawImage(tempImage, 0, 0);};  
  29.           }  
  30.             
  31.       }  
  32.         
  33.              
  34.       /** 
  35.        * function:  redo 
  36.        */  
  37. function redo()  
  38. {  
  39.           if (cStep <history.length-1)   
  40.           {  
  41.               clearCanvas();  
  42.               cStep++;  
  43.               var tempImage = new Image();  
  44.               tempImage.src = history[cStep];  
  45.               tempImage.onload = function () { ctx.drawImage(tempImage, 0, 0); };  
  46.           }  
  47. }  

画板信息存为图片

代码如下:

[javascript]  view plain copy print ?
  1. /** 
  2.  * save canvas content as image 
  3.  */  
  4. function saveItAsImage()  
  5. {  
  6.  var image = $("#myCanvas").get(0).toDataURL("image/png").replace("image/png""image/octet-stream");  
  7.           //locally save  
  8.  window.location.href=image;   
  9. }  


源码下载        读者可以去我的GitHub jPainter 项目下下载,或者直接使用git 工具:https://github.com/LuanLouis/jPainter.git



-----------------------------------------------------------------------------------------------------------------------------------------

本文源自  http://blog.csdn.net/luanlouis/,如需转载,请注明出处,谢谢!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值