代码改变世界

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

2017-07-05 17:19  tlnshuju  阅读(539)  评论(0编辑  收藏  举报

简单介绍

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

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

1. 能够绘制自由曲线、直线、矩形框和文字。

2. 能够依据须要定义线段和矩形框的颜色和宽度;

3. 你能够须要字体的大小、颜色、字体;

4. 支持undo、redo操作;

5. 支持橡皮擦功能。

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

源代码下载       1. 读者能够去我的GitHub jPainter项目下下载,

       2. 或者直接使用git 工具:https://github.com/LuanLouis/jPainter.git

       3. 或者 通过 http://download.csdn.net/detail/u010349169/7748093 下载

开发心得分享

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

1.  鼠标按下并移动 事件应该如何实现 

2. 如何实现所见即所得  的设计

3. undo redo 的实现原理

4. 画板信息另存为图片

鼠标按下并移动 事件应该如何实现

        假设我们在画板想画自由曲线,我们须要捕获鼠标按下并拖动的过程中 拖动的轨迹。

那么如何捕获这种事件呢? 熟悉javascript 事件的读者应该知道,鼠标移动事件的句柄是 onmousemove。有的读者可能觉得。能够直接为onmousemove 绑定事件处理函数。从event事件对象的button属性来推断是鼠标的哪一个键点击不即可了吗?代码例如以下:

$(function() {
    $(document).mousemove(function(e){
		console.log(e.button+"  "+e.which);
	})
});
而实际上,上述的代码执行时,当我们在页面上不管是点击鼠标的哪个键。都是输出例如以下的信息:

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

 原因是:  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 进行事件处理函数的绑定:

    //onmousemove 事件
    $("body").mousemove(function(e){
          if(flag)

          {
                // 鼠标被按下
          }

 })

//onmousedown事件
$("body").onmousedown(function(e){
     flag = true; 

        // 事件处理
})

//onmouseup事件
$("body").mouseup(function(e){
     flag = false;

         // 事件处理
})

            当然,假设读者有其它的实现方案。还请指教。共同学习!


如何实现所见即所得的设计

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

var c=document.getElementById("myCanvas");
var cxt=c.getContext("2d");
cxt.fillStyle="#FF0000";
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 的原理实际上非常easy。就是当每运行一次绘画,则将画板的内容转换成base64编码的字符串,存到缓存数组中去,然后在须要undo 的时候,将画板清空。再将缓存数组中的最后一次编辑的图片绘制到画板上就可以。相关的实现细节例如以下代码所看到的:

			      //undo redo
			      var history =new Array();
		    	  var cStep = -1;

				  			      /**
			       * put current canvas to cache
			       */
			      function historyPush()
			      {
			          cStep++;
    				  if (cStep < history.length) 
    				  { 
    						history.length = cStep; 
    				  }
					  
    				  history.push($("#myCanvas").get(0).toDataURL());
			      }
		    	  /**
		    	   * function: undo 
		    	   */
		    	  function undo()
		    	  {
		    		  if (cStep >= 0) 
		    		  {
		    			  cStep--;
		    			  var tempImage = new Image();
		    			  tempImage.src = history[cStep];
		    			  tempImage.onload = function () { ctx.drawImage(tempImage, 0, 0);};
		    		  }
		    		  
		    	  }
		    	  
                 
		    	  /**
		    	   * function:  redo
		    	   */
				  function redo()
				  {
		    		  if (cStep <history.length-1) 
		    		  {
		    			  clearCanvas();
		    			  cStep++;
		    			  var tempImage = new Image();
		    			  tempImage.src = history[cStep];
		    			  tempImage.onload = function () { ctx.drawImage(tempImage, 0, 0); };
		    		  }
				  }

画板信息存为图片

代码例如以下:

				  /**
				   * save canvas content as image
				   */
				  function saveItAsImage()
				  {
					  var image = $("#myCanvas").get(0).toDataURL("image/png").replace("image/png", "image/octet-stream");
	    			  //locally save
					  window.location.href=image; 
				  }


源代码下载       1. 读者能够去我的GitHub jPainter项目下下载,

       2. 或者直接使用git 工具:https://github.com/LuanLouis/jPainter.git

       3. 或者 通过 http://download.csdn.net/detail/u010349169/7748093 下载



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

本文源自  http://blog.csdn.net/luanlouis/。如需转载。请注明出处,谢谢!