使用HTML 5和Javascript設計繪圖程序
在本文中,將會介紹如何使用HTML5和Javascript去設計一個簡單的繪圖程序。HTML5的一個新的特性是canvas畫布功能,通過canvas畫布的強大功能可以實現繪畫不少圖形和其他絢麗的功能。在本文中,讀者將學習到如下幾個知識點:
1) 如何動態在canvas畫布上繪畫圖形
2) HTML 5 canvas的前景特性探討
3) 目前瀏覽器對HTML5的兼容情況
本文的讀者對象為,對HTML 5 Canvas有初步認識及熟悉Javascript的讀者。
設計目標
首先,我們來設計下這個繪圖程序將會擁有什么功能。在這個簡單的繪圖程序中,首先要有的是一塊能給用戶涂鴉的畫布區域,上面有一只可愛的小鴨,然后我們準備了4種不同顏色的蠟筆,可以給用戶給這只小鴨上色,同時也要提供橡皮擦的功能,以方便隨時擦除這個小鴨。而除了蠟筆外,也提供了普通的油畫筆的效果,當然也指定了每次繪畫時筆觸范圍的大小,這里設定了4個選擇。設計好后的繪圖應用,效果如下圖:
在這個應用中,用戶點左邊的四種顏色筆,就可以在指定的矩形框中隨便涂鴉,也可而已點右面兩種不同的筆觸效果(crayon蠟筆)和普通筆,也可以使用橡皮擦,也可以使用右下角四種不同的筆觸大小。
開始使用Canvas畫布
首先,要聲明一個canvas畫布,使用如下代碼聲明:
目前,對canvas支持的最好的瀏覽器依然是FireFox,Chrome等非IE的瀏覽器,在本文的這個例子中,也兼顧了對IE瀏覽器的支持,使用的是一個開源的JS文件,其中提供了一些對canvas的基本支持腳本(在附件下載中包含了該腳本,名稱為excanvas.js)。因此,我們可以同時也為了兼顧IE,所以這里改用了
的方式,如下代碼:
接下來,為了要使用canvas畫布的功能,必須如下調用:
- context = document.getElementById('canvasInAPerfectWorld').getContext("2d");
然而,同樣為了兼顧在IE下的使用,我們改用以下的代碼段實現:
- var canvasDiv = document.getElementById('canvasDiv');
- canvas = document.createElement('canvas');
- canvas.setAttribute('width', canvasWidth);
- canvas.setAttribute('height', canvasHeight);
- canvas.setAttribute('id', 'canvas');
- canvasDiv.appendChild(canvas);
- if(typeof G_vmlCanvasManager != 'undefined') {
- canvas = G_vmlCanvasManager.initElement(canvas);
- }
- context = canvas.getContext("2d");
可以看到,在上面的代碼中,通過document.createElement創建了一個標簽元素canvas,然后再用setAttribute方法設置了畫布的高度和寬度等屬性(這些都可以通過設置常量屬性值進行設置)。然后通過
- canvasDiv.appendChild(canvas);
為canvasDiv增加了一個子元素canvas。然后利用excanvas.js這個專門為IE擴展的canvas元素包中提供的處理方法initElement進行相應的判斷處理,即:
- if(typeof G_vmlCanvasManager != 'undefined') {
- canvas = G_vmlCanvasManager.initElement(canvas);
- }
最后,要使用canvas的繪圖功能的話,必須調用canvas的上下文,這里使用的語句是:
- context = canvas.getContext("2d");
在畫布上繪畫圖形
接下來,我們開始在canvas上繪制圖形。這里我們要對4個鼠標的相關事件進行編碼,并且要編寫兩個相關的方法addClick和redraw。addClick方法記錄鼠標移動的點,而redraw方法則將已記錄的數據點在canvas畫布中繪畫出來。
先來看下鼠標按下時的mouse down事件,代碼如下:
- $('#canvas').mousedown(function(e){
- var mouseX = e.pageX - this.offsetLeft;
- var mouseY = e.pageY - this.offsetTop;
- paint = true;
- addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
- redraw();
- });
其中設置的變量paint為true時,表明當前正在繪制圖形,patint為false時,表示鼠標已經松開。
再看下鼠標移動時的事件,代碼如下:
- $('#canvas').mousemove(function(e){
- if(paint){//是不是按下了鼠標
- addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
- redraw();
- }
- });
鼠標松開時的事件代碼為:
- $('#canvas').mouseup(function(e){
- paint = false;
- });
鼠標移開的事件代碼為:
- $('#canvas').mouseleave(function(e){
- paint = false;
- });
下面是addClick方法的代碼如下:
- var clickX = new Array();
- var clickY = new Array();
- var clickDrag = new Array();
- var paint;
- function addClick(x, y, dragging)
- {
- clickX.push(x);
- clickY.push(y);
- clickDrag.push(dragging);
- }
可以看到,這里分別用三個數組clickX,clickY及clickDrag記錄了鼠標移動的點的X,Y坐標,以及判斷是否鼠標松開的標志。
再來看下redraw這個方法,其作用為每次都清空畫板,然后重新把所有的點都畫過,效率不高,但作為本例子來說還是可以接受,代碼如下:
- function redraw(){
- canvas.width = canvas.width; // Clears the canvas
- context.strokeStyle = "#df4b26";
- context.lineJoin = "round";
- context.lineWidth = 5;
- for(var i=0; i < clickX.length; i++)
- {
- context.beginPath();
- if(clickDrag[i] && i){//當是拖動而且i!=0時,從上一個點開始畫線。
- context.moveTo(clickX[i-1], clickY[i-1]);
- }else{
- context.moveTo(clickX[i]-1, clickY[i]);
- }
- context.lineTo(clickX[i], clickY[i]);
- context.closePath();
- context.stroke();
- }
- }
接下來,再定義四種不同的顏色:紫色,綠色,棕色和黃色,分別用四個不同的變量表示,并且用變量curColor保存當前正在使用的顏色,并且也用一個數組clickColor來記錄用戶每次選擇的顏色。代碼如下:
- var colorPurple = "#cb3594";
- var colorGreen = "#659b41";
- var colorYellow = "#ffcf33";
- var colorBrown = "#986928";
- var curColor = colorPurple;
- var clickColor = new Array();
同樣,在addClick方法中,也必須加入對用戶每次選擇顏色的記錄,所以更新后的addclick代碼如下:
- function addClick(x, y, dragging)
- {
- clickX.push(x);
- clickY.push(y);
- clickDrag.push(dragging);
- clickColor.push(curColor);
- }
而在redraw的方法中,我們去掉context.strokeStyle一句,將繪畫筆的顏色設置到for循環中去設置,更新后的redraw代碼如下:
- function redraw(){
- /* context.strokeStyle = "#df4b26"; */
- context.lineJoin = "round";
- context.lineWidth = 5;
- for(var i=0; i < clickX.length; i++)
- {
- context.beginPath();
- if(clickDrag[i] && i){
- contex.moveTo(clickX[i-1], clickY[i-1]);
- }else{
- context.moveTo(clickX[i]-1, clickY[i]);
- }
- context.lineTo(clickX[i], clickY[i]);
- context.closePath();
- context.strokeStyle = clickColor[i];
- context.stroke();
- }
- }
我們再設置畫筆每次繪畫筆觸范圍的大小,同樣,有四種選擇,分別為小,中,大和很大,并用clickSize數組記錄用戶的選擇,默認的筆觸范圍大小用curSize進行記錄。并且也要更新redraw方法,更新后的addClick,redraw代碼如下:
- function addClick(x, y, dragging)
- {
- clickX.push(x);
- clickY.push(y);
- clickDrag.push(dragging);
- clickColor.push(curColor);
- clickSize.push(curSize);
- }
- var radius;
- var i = 0;
- for(; i < clickX.length; i++)
- {
- if(clickSize[i] == "small"){
- radius = 2;
- }else if(clickSize[i] == "normal"){
- radius = 5;
- }else if(clickSize[i] == "large"){
- radius = 10;
- }else if(clickSize[i] == "huge"){
- radius = 20;
- }else{
- alert("Error: Radius is zero for click " + i);
- radius = 0;
- }
- function redraw(){
- ........
- context.strokeStyle = clickColor[i];
- context.lineWidth = radius;
- context.stroke();
- }
- }
最后,我們設置不同筆的繪畫效果,分別是蠟筆和普通筆以及橡皮擦功能。用clickTool記錄用戶選擇的工具種類,curTool則為當前用戶選擇的工具,addClick的方法如下:
- function addClick(x, y, dragging)
- {
- clickX.push(x);
- clickY.push(y);
- clickDrag.push(dragging);
- if(curTool == "eraser"){
- clickColor.push("white");
- }else{
- clickColor.push(curColor);
- }
- clickColor.push(curColor);
- clickSize.push(curSize);
- }
注意,這里判斷如果用戶選擇的工具是橡皮擦,則將白色加入到clickColor數組中。同樣要在redraw的方法中對新的兩個繪圖工具進行處理,代碼如下:
- function redraw(){
- context.lineJoin = "round";
- for(var i=0; i < clickX.length; i++)
- {
- context.beginPath();
- if(clickDrag[i] && i){
- context.moveTo(clickX[i-1], clickY[i-1]);
- }else{
- context.moveTo(clickX[i]-1, clickY[i]);
- }
- context.lineTo(clickX[i], clickY[i]);
- context.closePath();
- context.strokeStyle = clickColor[i];
- context.lineWidth = radius;
- context.stroke();
- }
- if(curTool == "crayon") {
- context.globalAlpha = 0.4;
- context.drawImage(crayonTextureImage, 0, 0, canvasWidth, canvasHeight);
- }
- context.globalAlpha = 1;
- }
這里針對當用戶選擇“crazyon”蠟筆效果時,對繪畫的效果進行了透明度的處理。
最后,我們要把小鴨子的圖在畫布中畫上,首先要聲明一個圖片對象如下:
- var outlineImage = new Image();
然后在prepareCanvas()方法中加載事先準備好的圖片:
- function prepareCanvas(){
- ...
- outlineImage.src = "images/watermelon-duck-outline.png";
- }
最后在redraw的繪畫方法中,要使用canvas畫布的drawImage方法進行繪畫,代碼為:
- function redraw(){
- ...
- context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
- }
其中drawingAreaX, drawingAreaY為要在哪個具體位置繪畫圖形,drawingAreaWidth和
drawingAreaHeight則為具體圖片的寬度和高度。
我們還要把繪圖的區域限制在一個矩形框里,這要用到畫布的save和clip方法。其中save用來保存Canvas的狀態,而clip方法則是指定一個區域進行剪裁,規定了繪畫的區域,代碼如下:
- function redraw()
- {
- ...
- context.save();
- context.beginPath();
- context.rect(drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
- context.clip(); //剪裁出指定的繪畫區域
- var radius;
- var i = 0;
- for(; i < clickX.length; i++)
- {
- ...
- }
- context.restore(); //使用restore方法,恢復每次保存的canvas狀態
- ...
- }
總結
本文中只是對如何使用HTML5和javascript繪制小繪圖應用進行了思路和基本技術點的分析,其中著重介紹了畫布canvas的各種使用方法,完整的代碼請到這里下載
(http://www.williammalone.com/articles/create-html5-canvas-javascript-drawing-app/downloads/html5-canvas-drawing-app.zip ),代碼中完成實現了相關的各種功能,并加入了一些邏輯判斷等操作,由于篇幅關系,不再在文中詳細描述。
原文:http://tech.it168.com/a2011/1104/1269/000001269250_all.shtml
【編輯推薦】