基於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. 支持本地圖片保存功能。

源碼下載       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 的原理實際上很簡單,就是當每執行一次繪畫,則將畫板的內容轉換成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/,如需轉載,請註明出處,謝謝!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章