以下為本站文章分類清單

  1. AJAXspacer
  2. ASPspacer
  3. CSSspacer
  4. Javascriptspacer
  5. Windows 應用程式spacer
  6. 網頁設計
  7. 評論、短文、雜文spacer
  8. 版主spacer
  9. 最新回應spacer

以下為本頁本文內容

HTML5 Canvas 簡易手繪板

8/23 15' icon

Photo by www.williammalone.com/

HTML5 Canvas 提供了一塊畫布與眾多可用方法,使得在網頁應用程式中,設計繪圖板功能變得容易。這裡介紹一個簡易繪圖板製作。

HTML5 Canvas 所需事件

以桌上型瀏覽器來說,製作一個繪圖板程式,需要三個事件,首先,當滑鼠左鍵被按下時(onmousedown),這時要把目前滑鼠游標位置存下來,其次,若當滑鼠拖曳時(onmousemove),依照滑鼠游標軌跡由上一點繪製直線到下一點,造成手繪效果。最後放開滑鼠後(onmouseup),收捨善後。

這三個事件,在觸控裝置上則變成 onmouseover -> ontouchstart,onmousemove -> ontouchmove,onmouseup -> ontouchend 等對應事件名稱。

成品如下(功能多一點的成品在 http://audi.tw/pad)

開始製作

首先,定義一塊 canvas,使用 canvas 標籤


<canvas id="myCanvas" width="360" height="360" style="border:#000 1px solid;"></canvas>

接著為這塊畫布加上前述三個事件控制。如下,為畫布加上控制事件,其中 document.querySelector 是內建語法,用來選取物件,相當於 jQuery 的 $

使用 addEventListener 為物件加上事件控制,語法是:


obj.addEventListener(event,function)

傳入的參數一 event 請把前綴字 on 去掉,例如要設定 onmousedown,只要寫 mousedown 即可。

window.addEventListener('load',function(){
    var canvas=document.querySelector('#myCanvas');

    canvas.addEventListener('mousedown',mouseDown);
    canvas.addEventListener('mousemove',mouseMove);
    canvas.addEventListener('mouseup',mouseUp);

    canvas.addEventListener('touchstart',touchStart);
    canvas.addEventListener('touchmove',touchMove);
    canvas.addEventListener('touchend',touchEnd);
});

mouseDown,touchStart


function mouseDown(e){
    this.draw=true;
    this.ctx = this.getContext("2d");
    this.ctx.strokeStyle='#000000';
    this.ctx.lineWidth=2;

    var o=this;
    this.offsetX=this.offsetLeft;
    this.offsetY=this.offsetTop;

    while(o.offsetParent){
    	o=o.offsetParent;
    	this.offsetX+=o.offsetLeft;
    	this.offsetY+=o.offsetTop;
    }

    this.ctx.beginPath();
    this.ctx.moveTo(e.pageX-this.offsetX,e.pageY-this.offsetY);
}

function touchStart(e){
    this.draw=true;
    this.ctx=this.getContext("2d");
    this.touch=e.targetTouches[0];
    this.ctx.strokeStyle='#000000';
    this.ctx.lineWidth=2;

    var o=this;
    this.offsetX=this.offsetLeft;
    this.offsetY=this.offsetTop;

    while(o.offsetParent){
    	o=o.offsetParent;
    	this.offsetX+=o.offsetLeft;
    	this.offsetY+=o.offsetTop;
    }

    this.ctx.beginPath();
    this.ctx.moveTo(this.touch.pageX-this.offsetX,this.touch.pageY-this.offsetY);
    e.preventDefault();
}

由於事件是附加在物件上,所以可以廣泛使用 this 關鍵字建置不同參數或變數

設定 this.draw 來控制開啟繪製或結束繪製。當按下鼠鍵時,設為 true,反之在 mouseup 中應設為 false

接著 this.ctx 用來取得2D繪製功能,簡單使用 getContext("2d") 方法即可,這個方法原始模樣如下:


var canvas=document.querySelector('#myCanvas');
var ctx=canvas.getContext("2d");

在我的範例中,把事件加在物件本身,所以上述 canvas 就變成 this,匠子明白了吧

2D繪製有許多屬性及方法可用,詳見 MDN 網站,此處僅說明重要部份。

屬性 strokeStyle 用來指定畫筆顏色(由名稱看來,未來能指定的,應該不指顏色),用十六進位寫法最可告,例如 #000000,也可用文字,例如 blue, red

屬性 lineWidth 則為畫筆粗細,只需數值,不用單位

接下來,使用 beginPath() 方法開始繪製。beginPath() 是指,現在起,點移動到何處,線就連到何處。一般畫線,要有起點和終點,而 beginPath() 一旦啟動,就是由目前置往下一點繪製一條直線。所以,在 mousedown 事件最後,就是把起始點移到使用者點選的位置。

beginPath() 有個對應的方法,叫 closePath()。任何時間,呼叫 closePath() 方法後,會自動把線條連回起始點。

物件和鼠標的螢幕位置

環境變數回傳的數位 pageX 和 pageY 分別代表滑鼠游標目前的水平和垂直位置,這個位置以螢幕左上角為 0,0 原點。不管畫面有沒有捲動,數字不變。

而物件在整份文件中的位置,有可能目前停在畫面之外,必需要捲動畫面才能看到。例如螢幕畫面寬 1024 高 600,但整份文件總高達 3000 像素。目前就有些內容必需捲動畫面才能查看,例如您現在正在閱讀的文字,也是經過捲動畫面才看到的。所以這時物件實際位置就很重要,否則,繪製線條時,找不到合適的點連線。

取得物件位置的基本語法是 obj.offsetLeft 和 obj.offsetTop,但這兩個值回傳的是第一個父層物件的 position:relative 時,相對於父層物件,如下圖:

A
B
C

區塊 A,B,C 的 position 屬性都是 relative,而 C 取回的 怎麼看都不是距離畫面左側的值吧?原因就是回傳值是找父層 position 屬性是不是 relative,是的話就回傳值,不是的話再往上層找物件。

所以最保險的方法,是不斷往父層找值,一直找到沒有父層為止。


    var o=this;
    this.offsetX=this.offsetLeft;
    this.offsetY=this.offsetTop;

    while(o.offsetParent){
    	o=o.offsetParent;
    	this.offsetX+=o.offsetLeft;
    	this.offsetY+=o.offsetTop;
    }
}

這段程式碼,就是在找到畫布在整個畫面真正的位置,那麼,當使用者按下鼠標時,不管畫面有沒有捲動,對應的位置就是

水平:e.pageX-this.offsetX,垂直:e.pageY-this.offsetY

觸控裝置呢?和一般使用滑鼠的差別在於環境變數回傳值,在鼠標世界,回傳 e.pageX 和 e.pageY,在觸控世界,以陣列回傳 e.touches 或 e.targetTouches,因為可能不只一支手指在觸控。

無論使用者放幾支手指,只取第個觸碰的那根⋯⋯this.touch=e.targetTouches[0] 這相當於是鼠標了,觸控位置 X 回傳值則為 this.touch.pageX,Y 則為 this.touch.pageY。

最後,觸控裝置,有部份行為和鼠標不同,通常按鼠標=觸控,拖曳鼠標=滑動手指。但,滑動手指通常有其他用途,所以在觸控裝置,記得把預設用途關掉,使用 e.preventDefault() 方法即可。

mousemove, touchmove,mouseup

花了一些篇幅說明 mousedown 的設計,接下來的 mousemove 設計應該不用再說明了


function mouseMove(e){
    if (this.draw){
        this.ctx.lineTo(e.pageX-this.offsetX,e.pageY-this.offsetY);
        this.ctx.stroke();
    }
}

function touchMove(e){
    this.touch=e.targetTouches[0];
    if (this.draw){
        this.ctx.lineTo(this.touch.pageX-this.offsetX,this.touch.pageY-this.offsetY);
        this.ctx.stroke();
    }
    e.preventDefault();
}

function mouseUp(e){
    this.draw=false;
}

最後,清空畫布的方法,就是 clear,清乾淨就可以。


function clearPad(){
    var canvas=document.querySelector('#myCanvas');
    var ctx=canvas.getContext("2d");
    ctx.clearRect(0,0,canvas.width,canvas.height);
}

要再多點彈性嗎?例如畫筆粗細?顏色?加油!

最後全部整理一次所有 javascritp code




重要說明

如果 canvas 本身 position 屬性是 fixed(或父層,父父層之類的),那麼,當頁面捲動時,畫布是不動,但事實上,畫布在頁面位置的回傳值,仍是在非 fixed 的情況。這種時候,請修正 moveTo 的位置,加入捲軸的因素


this.ctx.moveTo(e.pageX-this.offsetX-window.scrollX,e.pageY-this.offsetY-window.scrollY);

觸控
this.ctx.moveTo(this.touch.pageX-this.offsetX-window.scrollX,this.touch.pageY-this.offsetY-window.scrollY);

 

以下為文章回應區

同意轉載,不過麻煩看一下轉載需知

tercio borlenghi jr   2017/11/13 下午 06:36:00

I was wondering if you ever considered changing the structure of your website?
Its very well written; I love what youve got to say.
But maybe you could a little more in the way of content so people could connect with it better.
Youve got an awful lot of text for only having 1 or
2 images. Maybe you could space it out better?

Georgia   2017/11/12 上午 04:52:00

Hey just wanted to give you a quick heads up. The text in your post seem to be running off the screen in Firefox.
I'm not sure if this is a format issue or something to do with web browser compatibility but I
figured I'd post to let you know. The style and design look great though!
Hope you get the problem resolved soon. Cheers

website design company   2017/11/11 上午 01:32:00

Great work! This is the type of info that are meant to be shared around the internet.
Shame on the search engines for not positioning this put up upper!
Come on over and talk over with my website . Thanks =)

Lelio Vieira Carneiro Junior   2017/11/10 上午 08:22:00

I like looking through a post that can make men and women think.
Also, many thanks for allowing me to comment!

   2017/8/4 上午 10:19:00

Hi there! I know this is somewhat off topic but I was
wondering which blog platform are you using for this site?
I'm getting fed up of Wordpress because I've had issues with hackers
and I'm looking at options for another platform. I would
be great if you could point me in the direction of a good platform.

How do you stretch your Achilles?   2017/7/31 下午 12:24:00

It's not my first time to visit this site, i am browsing this
site dailly and get fastidious data from here daily.

https://altheahartis.wordpress.com/   2017/7/31 上午 12:27:00

Hey there! Do you use Twitter? I'd like to follow you if that would be okay.

I'm absolutely enjoying your blog and look forward to new posts.

How did the Achilles tendon get it's name?   2017/7/28 上午 12:10:00

This paragraph will assist the internet viewers for creating
new website or even a weblog from start
to end.

How you can increase your height?   2017/7/21 下午 10:48:00

Hey there! This is my first visit to your blog! We are a group of
volunteers and starting a new project in a community in the same niche.
Your blog provided us valuable information to work on. You
have done a outstanding job!

diabetes an foot pain   2017/7/4 上午 01:29:00

Hello very cool web site!! Man .. Excellent ..
Superb .. I'll bookmark your website and take the feeds additionally?
I'm happy to find numerous useful information here in the submit, we need work out more strategies on this
regard, thanks for sharing. . . . . .

manicure   2017/5/4 上午 04:12:00

Greetings, I do think your website could possibly be having internet browser compatibility issues.
Whenever I take a look at your website in Safari, it looks fine however, when opening in Internet Explorer, it has some overlapping issues.
I merely wanted to give you a quick heads up! Besides that, fantastic website!

manicure   2017/4/11 下午 06:50:00

If you wish for to get a good deal from this piece of writing then you have to apply
such methods to your won webpage.

Eastpak   2016/11/11 下午 05:52:00

Thank you

給個回應
姓名:
佈落格網址:
  如果您是要發問問題, 最好有個問題測試的網址, 這樣比較容易找到您問題所在, 謝謝
內容: