【IT168 專稿】前言
在本文中,將會介紹如何使用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),代碼中完成實現了相關的各種功能,並加入了一些邏輯判斷等操作,由於篇幅關係,不再在文中詳細描述。