使用HTML5和Javascript設計繪圖程序

2020-12-05 IT168

    【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),代碼中完成實現了相關的各種功能,並加入了一些邏輯判斷等操作,由於篇幅關係,不再在文中詳細描述。

相關焦點

  • 50個實用的JavaScript工具
    安全工具  AttackAPI  AttackAPI是一個基於Web的攻擊構造庫,它可以結合PHP、JavaScript及其他客戶端和伺服器端技術進行使用。JavaScriptMVC應用了模型-視圖-控制器架構模式,把業務邏輯和表示分離,使得代碼更加模塊化。  qooxdoo  是一個功能強大基於JavaScript GUI工包,它讓你可以用JavaScript來開發類似於VB/Delphi風格的具有Ajax功能的web2.0應用程式。
  • 用HTML5把Canvas緩衝區內容輸出到屏幕
    我會儘量簡要說明如何使用HTML5 canvas元素和JavaScript創建簡單的遊戲。本教程將省略一些代碼,但絕非故意。您可以隨時查看我的遊戲演示。  之前,我們使用使用HTML編寫網頁遊戲,現在卻在使用HTML5。那麼兩者有區別嗎?元素用來創建客戶端遊戲時非常方便。針對客戶端遊戲編程,Canvas和JavaScript使用起來非常簡單。
  • 在JavaScript中,使用replace()、test()和exec()方法匹配字符串
    使用字符串替換的核心JavaScript代碼如下:<script type="text/javascript">var str = "一都編程,每個知識就是一個案例。"06第六節:修飾符標誌在JavaScript中,在正則表達式上還可以使用了修飾符,也稱為標誌,共有3個,分別為:/i、/g、/m。這3個修飾符的含義和使用方法如下所述。6.1.
  • 電子工程師自學速成——單片機技術和電路繪圖設計
    linux、FPGA、仿真、培訓資料、CAN、007、通信、功放、51、tvs、wifi、程序」獲取更多資料包  】 內容包括單片機技術和Protel電路繪圖設計兩大部分,其中單片機技術部分的內容有單片機入門、單片機硬體原理、單片機的開發過程、單片機編程、中斷技術、定時器/計數器、串行通信技術和接口技術,Protel電路繪圖設計部分的內容有Protel軟體入門
  • JavaScript入門教程
    起源javascript前身叫做livescript,sun公司推出java,netspace公司引進java的概念,重新設計livescript,並更名javascript。發明者,布蘭登.艾克,表單驗證原先要經過伺服器,伺服器壓力大,等待時間長,js僅在客戶端就可完成。是什麼是一種腳本語言,是一種輕量級的程式語言。
  • html5中nav標籤(導航連結)的詳細介紹
    本篇將介紹html5中nav標籤(導航連結)的詳細用法,有興趣的朋友可以了解一下!在html5版本中,新增了很多語義標籤,比如:header標籤、footer標籤、aside標籤、nav標籤等等。這些語義標籤沒有實際的顯示效果,只是起到語義的作用。今天小編要介紹的就是其中一個,即nav標籤。
  • html5 canvas畫布繪製矩形和圓形
    html5為我們提供了非常有特色的標籤,canvas標籤為我們可以實現在網頁中畫畫提供了便利,接下來我們列舉他的常用操作。新建一個html5的文檔,建立一個canvas畫布,設置長寬,這裡需要特別注意,canvas標籤可以在標籤內設置width,height,也能通過css來設置,但是通過css來設置的標籤,當繪製圖形的時候會變形,所以我們建議直接在標籤內設置。
  • Javascript去除字符串中的點或其他符號
    在前端上使用javascript進行操作的。測試了兩次沒有好用,程序直接把整個字符串都進行了替換,在考慮這個是為什麼呢?javascript(請忽略此配圖)示例var ip = data.field.ip.replace(/.
  • 七天學會javascript第一天javascript介紹
    javascript介紹javascript數據類型javascript運算符javascript對象javascript Date對象javascript String對象JavaScript常用於實現一些前端效果。前些年流行的flash已經慢慢的被淘汰,js盛行起來。javascript :客戶端編程。javascript是由客戶端去解釋運行的。
  • AJAXRPC: javascript調用服務端方法
    它允許你使用Javascript調用服務端方法,基於JSON數據協議,開源授權(LGPL),可同步和異步調用。 使用AJAXRPC,您可以像開發傳統的C/S程序一樣,來開發WEB程序,讓WEB開發更簡單和高效。 支持服務端語言:Java、.Net、PHP。 支持瀏覽器:IE、FireFox、Opera、Safari、Chrome。
  • cad繪圖非常好用的小程序
    cad繪圖非常好用的小程序
  • HTML5調用攝像頭並拍照
    利用html5特性,調用攝像頭,並利用canvas拍照先簡單的添加需要的控制項<video id="video" autoplay=""style='width:640px;height:480px'></video><button id='picture
  • python的繪圖利器--海龜繪圖turtle
    我們之前提到Python是一種超級語言,因為其提供了極其豐富的庫,需要什麼拿來黏合一下就可以直接使用。就像現在的有些汽車工廠一樣,根本不用重新發明生產什麼,只需要買來相應部件等把它們組裝起來就好。作為你學習python的第一個程序,樹哥決定直接來一個實戰乾貨程序:利用海龜turtle來畫一個奧運五環。這樣就既可以理解庫的概念和使用,又可以理解程序的基本概念。
  • 一天一點JavaScript編程知識:Animation動畫
    JavaScript提供了以下兩個在動畫中經常使用的函數。setTimeout(function,duration) - 此函數從現在起持續幾毫秒後調用函數。setInterval(function,duration) - 該函數在每個持續時間毫秒後調用函數。
  • Adobe將在iPad推出設計繪圖應用Adobe Fresco
    IT之家6月18日消息 Adobe公司今天在其博客上宣布,Adobe即將推出的iPad繪圖和繪畫應用程式Adobe Fresco。該項目以前稱為Project Gemini,這款應用程式將在今年晚些時候發布。
  • 科普:什麼是程序,以及軟體與程序的區別
    我們用程序來描述這些計算任務所要處理的對象和處理規則。處理對象實際上是指計算任務中要處理的信息,當前計算機中能處理的是這些信息的載體—一數據,例如數字、文字、聲音、圖形、圖像以及影視數據等等,處理規則一般是指對數據進行處理的動作和步驟。程序是通過程序設計語言來實現的。
  • R語言中使用par函數在同一繪圖區中繪製多幅圖
    par函數概述在R繪圖時,有時我們想在一個繪圖區中同時繪製多幅圖。在R語言中可以有多個函數來實現此要求。這裡先介紹一下繪圖參數par函數的使用。R中的par()函數可以將繪圖區分割成規則的幾個部分。par設定的繪圖參數直至退出前都會有效,即使是在某個函數中使用par()設定的參數,也會影響全局的效果,所以如果在繪圖中需要恢復到初始狀態,可以設置臨時變量保存初始環境。在準備恢復時再使用par(臨時變量)的形式恢復到初始狀態。
  • 比例尺及其他繪圖工具的使用
    一、比例尺的使用
  • 從setTimeout(fn,0)函數剖析JavaScript的執行機制
    在zepto源碼中,$fn對象的ready函數有一句setTimeout(fn,0)的函數,如下圖所示:setTimeout(fn,time)作為一個延時函數,在很多時候都會使用,而time是相應的延時時間;如果time為0時,按道理說就要不延時而立即執行了,那為什麼需要特意將fn套在setTimeout裡面而不直接正常執行呢