亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > HTML5 > 正文

HTML5 Canvas標簽使用收錄

2024-09-05 07:19:41
字體:
來源:轉載
供稿:網友

 一、基本概念

什么是Canvas

<canvas> 是一個新的 HTML 元素,這個元素在 HTML5  中被定義。這個元素通??梢员挥脕碓?nbsp;HTML 頁面中通過 JavaScript 進行繪制圖形、合成圖像等等操作,也可以用來做一些動畫。當然,目前 HTML5 規范還在草稿階段,正式發布也許要等到2010年,不過現在已經有不少瀏覽器已經支持了部分 HTML5 規范。目前支持 canvas 元素的瀏覽器有 Firefox 3+、Safari 4、Chrome 2.0+ 等,因此,在運行本頁中的例子時,請確保你使用的是上述瀏覽器之一。

盡管在 Mozilla  已經有不少關于 Canvas 的教程,我還是決定把自己的學習過程記錄下來。如果覺得我寫的不夠明白,那么你可以在參考資料中找到 Mozilla 網站上 Canvas 教程的鏈接。

另外,可以在這里 找到一些有趣的 Canvas 示例

開始使用 Canvas

使用 Canvas 很簡單,與使用其他 HTML 元素一樣,只需要在頁面中添加一個 <canvas> 標簽即可:

代碼如下:

<canvas id="screen" width="400" height="400"></canvas>



當然,這樣只是簡單的創建了一個 Canvas 對象而已,并沒有對它進行任何操作,這個時候的 canvas 元素看上去與 div 元素是沒什么區別的,在頁面上什么都看不出來:)
另外,canvas 元素的大小可以通過 width 與 height 屬性來指定,這與 img 元素有點相似。

Canvas 的核心:Context
前面說到可以通過 JavaScript 來操作 Canvas 對象來進行繪制圖形、合成圖像等操作,這些操作并不是通過 Canvas 對象本身來進行的,而是通過 Canvas 對象的一個方法 getContext 獲取 Canvas 操作上下文來進行。也就是說,在后面我們使用 Canvas 對象的過程中,都是與 Canvas 對象的 Context 打交道,而 Canvas 對象本身可以用來獲取 Canvas 對象的大小等信息。
要獲取 Canvas 對象的 Context 很簡單,直接調用 canvas 元素的 getContext 方法即可,在調用的時候需要傳遞一個 Context 類型參數,目前可以用的并且是唯一可以用的類型值就是 2d:

<canvas id="screen" width="400" height="400"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");
</script>

Firefox 3.0.x 的尷尬

Firefox 3.0.x 雖然支持了 canvas 元素,但是并沒有完全按照規范來實現,規范中的 fillText、 measureText 兩個方法在 Firefox 3.0.x 中被幾個 Firefox 特有的方法代替,因此在 Firefox 3.0.x 中使用 Canvas 時需要先 fix 這個幾個方法在不同瀏覽器中的差別。

下面這代碼取自 Mozilla Bespin  項目,它修正了 Firefox 3.0.x 中 Canvas 的 Context 對象與 HTML5 規范不一致的地方:

function fixContext(ctx) {
// * upgrade Firefox 3.0.x text rendering to HTML 5 standard
if (!ctx.fillText && ctx.mozDrawText) {
ctx.fillText = function(textToDraw, x, y, maxWidth) {
ctx.translate(x, y);
ctx.mozTextStyle = ctx.font;
ctx.mozDrawText(textToDraw);
ctx.translate(-x, -y);
};
}
// * Setup measureText
if (!ctx.measureText && ctx.mozMeasureText) {
ctx.measureText = function(text) {
if (ctx.font) ctx.mozTextStyle = ctx.font;
var width = ctx.mozMeasureText(text);
return { width: width };
};
}
// * Setup html5MeasureText
if (ctx.measureText && !ctx.html5MeasureText) {
ctx.html5MeasureText = ctx.measureText;
ctx.measureText = function(text) {
var textMetrics = ctx.html5MeasureText(text);
// fake it 'til you make it
textMetrics.ascent = ctx.html5MeasureText("m").width;
return textMetrics;
};
}
// * for other browsers, no-op away
if (!ctx.fillText) {
ctx.fillText = function() {};
}
if (!ctx.measureText) {
ctx.measureText = function() { return 10; };
}
return ctx;
}

注意:到 Opera 9.5 為止,Opera 還不支持 HTML5 規范中 Canvas 對象的 fillText 以及其相關方法和屬性。

Hello, Canvas!

在對 Canvas 進行了一些初步了解后,開始來寫我們的第一個 Canvas 程序,聞名的 HelloWorld 的又一個分支“Hello, Canvas”:

<canvas id="screen" width="400" height="400"></canvas>
<script type="text/javascript">
(function() {
var canvas = document.getElementById("screen");
var ctx = fixContext(canvas.getContext("2d"));
ctx.font = "20pt Arial";
ctx.fillText("Hello, Canvas!", 20, 20);
ctx.fillText("www.xujiwei.com", 20, 50);
function fixContext(ctx) {
// * upgrade Firefox 3.0.x text rendering to HTML 5 standard
if (!ctx.fillText && ctx.mozDrawText) {
ctx.fillText = function(textToDraw, x, y, maxWidth) {
ctx.translate(x, y);
ctx.mozTextStyle = ctx.font;
ctx.mozDrawText(textToDraw);
ctx.translate(-x, -y);
};
}
// * Setup measureText
if (!ctx.measureText && ctx.mozMeasureText) {
ctx.measureText = function(text) {
if (ctx.font) ctx.mozTextStyle = ctx.font;
var width = ctx.mozMeasureText(text);
return { width: width };
};
}
// * Setup html5MeasureText
if (ctx.measureText && !ctx.html5MeasureText) {
ctx.html5MeasureText = ctx.measureText;
ctx.measureText = function(text) {
var textMetrics = ctx.html5MeasureText(text);
// fake it 'til you make it
textMetrics.ascent = ctx.html5MeasureText("m").width;
return textMetrics;
};
}
// * for other browsers, no-op away
if (!ctx.fillText) {
ctx.fillText = function() {};
}
if (!ctx.measureText) {
ctx.measureText = function() { return 10; };
}
return ctx;
}
})();
</script>

運行示例,Canvas 對象所在區域顯示出“Hello, World!”,這正是代碼中 ctx.fillText("Hello, World!", 20, 20); 的作用。

fillText 以及相關屬性

fillText 方法用來在 Canvas 中顯示文字,它可以接受四個參數,其中最后一個是可選的:

void fillText(in DOMString text, in float x, in float y, [Optional] in float maxWidth);

其中 maxWidth 表示顯示文字時最大的寬度,可以防止文字溢出,不過我在測試中發現在 Firefox 與 Chomre 中指定了 maxWidth 時也沒有任何效果。

在使用 fillText 方法之前,可以通過設置 Context 的 font 屬性來調整顯示文字的字體,在上面的示例中我使用了“20pt Arial”來作為顯示文字的字體,你可以自己設置不同的值來看具體的效果。

二、路徑

圖形的基礎 - 路徑

在 Canvas 中,所有基本圖形都是以路徑為基礎的,也就是說,我們在調用 2dContext 的 lineTo、rect 等方法時,其實就是往已經的 context 路徑集合中再添加一些路徑點,在最后使用 fill 或 stroke 方法進行繪制時,都是依據這些路徑點來進行填充或畫線。

在每次開始繪制路徑前,都應該使用 context.beginPath() 方法來告訴 Context 對象開始繪制一個新的路徑,否則接下來繪制的路徑會與之前繪制的路徑疊加,在填充或畫邊框時就會出現問題。在繪制完成路徑后,可以直接使用 context.closePath() 方法來關閉路徑,或者手動關閉路徑。另外,如果在填充時路徑沒有關閉,那么 Context 會自動調用 closePath 方法將路徑關閉。

基本路徑方法

1. beginPath, closePath

這兩個方法在前面已經介紹過,分別用來通知 Context 開始一個新的路徑和關閉當前的路徑。

在 Canvas 中使用路徑時,應該要保持一個良好的習慣,每次開始繪制路徑前都要調用一次 beginPath 方法,否則畫出來的效果難看不說,還會嚴重影響性能。

在下面這張圖中,左邊的圖形在每次繪制矩形前都調用了一次 beginPath 來清除之前的路徑并重新開始繪制新的路徑,而后面的圖形則就只在繪制所有圖形前調用了一次 beginPath 來清除路徑,因此,雖然這里是使用的邊框色是 #666,但是右邊的圖形顏色比左邊的深一些,因為每次使用 stroke 繪制邊框時,會把之前的路徑再次繪制一遍,疊加起來顏色就比原來深一些。

<canvas id="canvas" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "#666";
function useBeginPath() {
for (var i = 0; i < 5; ++i) {
ctx.beginPath();
ctx.rect(10 + i*20, 10 + i*20, 210 - i*40, 210 - i*40);
ctx.stroke();
}
}
function notUseBeginPath() {
ctx.beginPath();
for (var i = 0; i < 5; ++i) {
ctx.rect(240 + i*20, 10 + i*20, 210 - i*40, 210 - i*40);
ctx.stroke();
}
}
useBeginPath();
notUseBeginPath();
</script>

在 Context 中路徑數較少時,如果不考慮顯示效果,性能上還可以接受,但是如果 Context 中的路徑數很多時,在開始繪制新路徑前不使用 beginPath 的話,因為每次繪制都要將之前的路徑重新繪制一遍,這時性能會以指數下降。

因此,除非有特殊需要,每次開始繪制路徑前都要調用 beginPath 來開始新路徑。


2. 移動與直線 moveTo, lineTo, rect

<canvas id="canvas" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(110,110);
ctx.lineTo(10, 110);
ctx.lineTo(10, 10);
ctx.stroke();
ctx.beginPath();
ctx.rect(120, 10, 100, 100);
ctx.stroke();
</script>


void moveTo(in float x, in float y);

在 Canvas 中繪制路徑,一般是不需要指定起點的,默認的起點就是上一次繪制路徑的終點,因此,如果需要指定起點的話,就需要使用 moveTo 方法來指定要移動到的位置。

void lineTo(in float x, in float y);

lineTo 方法則是繪制一條直接路徑到指定的位置。在調用完 lineTo 方法后,Context 內部的繪制起點會移動到直線的終點。

void rect(in float x, in float y, in float w, in float h);

rect 方法用來繪制一個矩形路徑,通過參數指定左上角位置以及寬和高。在調用 rect 后,Context 的繪制起點會移動到 rect 繪制的矩形的左上角。

rect 方法與后面要介紹的 arc 方法與其他路徑方法有一點不同,它們是使用參數指定起點的,而不是使用 Context 內部維護的起點。

3. 曲線 arcTo, arc, quadraticCurveTo, bezierCurveTo

void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius);

按照 WHATWG 文檔的說明,這個方法是畫一個與兩條射線相切的的圓弧,兩條射線其中一條為穿過 Context 繪制起點,終點為 (x1, y1),另外一條為穿過 (x2, y2),終點為 (x1, y1),這條圓弧為最小的與這兩條射線相切的圓弧。在調用完 arcTo 方法后,將 圓弧與 射線 (x1, y1)-(x2, y2) 的切點添加到當前路徑中,做為下次繪制的起點。

在測試中發現,Firefox 和 Opera 目前對這個方法的支持并不好,只有 Chrome 和 Safari 4 能繪制出正確的路徑。

<canvas id="canvas" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "#000";
ctx.translate(200, 200);
ctx.moveTo(10, 10);
ctx.arcTo(110, 60, 10, 110, 30);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "#999";
ctx.moveTo(10, 6);
ctx.lineTo(114, 60);
ctx.lineTo(10, 114);
ctx.stroke();
</script>

void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise);

arc 方法用來繪制一段圓弧路徑,通過圓心位置、起始弧度、終止弧度來指定圓弧的位置和大小,這個方法也 依賴于 Context 維護的繪制起點。而在畫圓弧時的旋轉方向則由最后一個參數 anticlockwise 來指定,如果為 true 就是逆時針,false 則為順時針。

void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y);

quadraticCurveTo 方法用來繪制二次樣條曲線路徑,參數中 cpx 與 cpy 指定控制點的位置,x 和 y 指定終點的位置,起點則是由 Context 維護的繪制起點。

void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y);

bezierCurveTo 方法用來繪制貝塞爾曲線路徑,它與 quadraticCurveTo 相似,不過貝塞爾曲線有兩個控制點,因此參數中的 cp1x, cp1y, cp2x, cp2y 用來指定兩個控制點的位置,而 x 和 y 指定綹的位置。

<canvas id="canvas" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.translate(10, 10);
ctx.beginPath();
ctx.arc(50, 50, 50, 0, Math.PI, true);
ctx.stroke();
// quadraticCurveTo
ctx.beginPath();
ctx.strokeStyle = "#000";
ctx.moveTo(110, 50);
ctx.quadraticCurveTo(160, 0, 210, 50);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.moveTo(110, 50);
ctx.lineTo(160, 0);
ctx.lineTo(210, 50);
ctx.stroke();
// bezierCurveTo
ctx.beginPath();
ctx.strokeStyle = "#000";
ctx.moveTo(220, 50);
ctx.bezierCurveTo(250, 0, 280, 10, 320, 50);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.moveTo(220, 50);
ctx.lineTo(250, 0);
ctx.lineTo(280, 10);
ctx.lineTo(320, 50);
ctx.stroke();
</script>

4. fill, stroke, clip

fill 與 stroke 這兩個方法很好理解,分別用來填充路徑與繪制路徑線條。

clip 方法用來給 Canvas 設置一個剪輯區域,在調用 clip 方法之后的代碼只對這個設定的剪輯區域有效,不會影響其他地方,這個方法在要進行局部更新時很有用。默認情況下,剪輯區域是一個左上角在 (0, 0),寬和高分別等于 Canvas 元素的寬和高的矩形。

在畫這個圖時,雖然兩次都是使用 fillRect(0, 0, 100, 100) 填充了一個 100x100 大小矩形,但是顯示的結果卻是第二次填充的只是中間的一小塊,這是因為在兩次填充之間使用 clip 方法設定了剪輯區域,這樣第二次填充時只會影響到所設定的中間那一小部分區域。

<canvas id="canvas" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.translate(10, 10);
// fill a green rectangle
ctx.fillStyle = "green";
ctx.fillRect(0, 0, 100, 100);
// set the clipping region
ctx.beginPath();
ctx.rect(30, 30, 40, 40);
ctx.clip();
ctx.stroke();
// fill a yellow rectangle
ctx.fillStyle = "yellow";
ctx.fillRect(0, 0, 100, 100);
</script>

5. clearRect, fillRect, strokeRect

這三個方法并不是路徑方法,而是用來直接處理 Canvas 上的內容,相當于 Canvas 的背景,調用這三個方法也不會影響 Context 繪圖的起點。

要清除 Canvas 上的所有內容時,可以直接調用 context.clearRect(0, 0, width, height) 來直接清除,而不需要使用路徑方法繪制一個與 Canvas 同等大小的矩形路徑再使用 fill 方法去清除。

結語

通過 Canvas 的路徑方法,可以使用 Canvas 處理一些簡單的矢量圖形,這樣在縮放時也不會失真。不過 Canvas 的路徑方法也不是很強大,至少連個橢圓的路徑都沒有……

參考資料
1. The Canvas Element, WHATWG

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美激情一区二区三区成人| 亚洲另类欧美自拍| 欧美综合国产精品久久丁香| 国产精品久久久久一区二区| 97色在线播放视频| 久久久精品久久| 69精品小视频| 成人激情在线播放| 日韩视频第一页| 欧美成人性色生活仑片| 欧美富婆性猛交| 国产精品18久久久久久首页狼| 欧美一级黄色网| 91亚洲精品一区| 亚洲夜晚福利在线观看| 欧美有码在线观看视频| 91精品国产自产91精品| 午夜精品一区二区三区视频免费看| 日本最新高清不卡中文字幕| 亚洲国产精品成人精品| 国产成人精品在线视频| 亚洲国产精品久久久久| 久久久久在线观看| 欧美激情va永久在线播放| 国内精品400部情侣激情| 久久婷婷国产麻豆91天堂| 亚洲精品videossex少妇| 黑人巨大精品欧美一区二区一视频| 国产精品久久久久久搜索| 在线日韩欧美视频| 亚洲第一综合天堂另类专| 亚洲一区美女视频在线观看免费| 中文字幕日韩欧美| 日韩美女写真福利在线观看| 国产一区二区三区高清在线观看| 国产精品精品视频一区二区三区| 色综合久久88色综合天天看泰| 国产一区二区三区三区在线观看| 欧美高清视频在线观看| 欧美精品在线观看91| 精品国产999| 精品亚洲国产成av人片传媒| 91中文精品字幕在线视频| 亚洲四色影视在线观看| 日韩av高清不卡| 91tv亚洲精品香蕉国产一区7ujn| 中文字幕亚洲专区| 中文字幕日韩视频| 亚洲精品美女视频| 欧美理论电影网| 情事1991在线| 亚洲成色777777在线观看影院| 欧美一级高清免费| 国产精品盗摄久久久| 成人在线国产精品| 久久夜色精品国产欧美乱| 亚洲欧美另类人妖| 亚洲视频一区二区三区| 91精品在线观| 亚洲少妇中文在线| 98视频在线噜噜噜国产| 萌白酱国产一区二区| 亚洲欧美日韩精品| 成人黄色午夜影院| 自拍视频国产精品| 日韩成人在线视频观看| 日本一区二区在线播放| 久久精品99国产精品酒店日本| 欧美成人精品h版在线观看| 一区二区欧美久久| 欧美黑人一级爽快片淫片高清| 5566日本婷婷色中文字幕97| 国产精品吹潮在线观看| 国产日韩在线播放| 亚洲老头同性xxxxx| 久久精品国产99国产精品澳门| 日韩欧美成人网| 亚洲欧美一区二区三区久久| 欧美亚洲日本网站| 久久夜色精品亚洲噜噜国产mv| 亚洲色图第三页| 久久夜精品va视频免费观看| 国产一区二区三区丝袜| 国产一区二区黑人欧美xxxx| 国产成人拍精品视频午夜网站| 综合网日日天干夜夜久久| 国模极品一区二区三区| 国产精品视频最多的网站| 亚洲色图35p| 亚洲一区免费网站| 性色av一区二区咪爱| 影音先锋欧美在线资源| 欧美日韩亚洲成人| 欧美老女人www| 91美女高潮出水| 亚洲黄色在线观看| 国产成人在线精品| 国产精品成人国产乱一区| 精品国产91久久久久久| 18久久久久久| 欧美高清无遮挡| 亚洲国产一区二区三区四区| 国产日韩欧美综合| 亚洲精品理论电影| 亚洲一区精品电影| 欧美专区国产专区| 一区二区三区四区视频| 国产精品成人av性教育| 欧美成人精品在线播放| 欧美夜福利tv在线| 欧美日韩成人在线视频| 爱福利视频一区| 亚洲免费成人av电影| 中国人与牲禽动交精品| 久久精品成人欧美大片| 色噜噜狠狠狠综合曰曰曰88av| 欧美日韩一二三四五区| 久久久久久久成人| 国产精品一二三视频| 日韩电影大全免费观看2023年上| 精品一区二区三区电影| 色噜噜久久综合伊人一本| 国产精品高清在线观看| 国产在线视频欧美| 欧美电影免费观看| 久久精品视频一| 亚洲精品国精品久久99热| 91人成网站www| 久久99久久99精品中文字幕| 亚洲91精品在线观看| 揄拍成人国产精品视频| 中文字幕日韩欧美在线| 国产成人精品久久二区二区| 亚洲成色777777女色窝| 亚洲国产成人精品一区二区| 最新国产成人av网站网址麻豆| 日韩中文字幕在线视频| 91福利视频在线观看| 国产97在线播放| 国产欧美日韩丝袜精品一区| 亚洲人成电影网站色| 国产视频久久久久久久| 欧美性生交xxxxx久久久| 欧美wwwwww| 大桥未久av一区二区三区| 欧美性videos高清精品| 日韩精品免费电影| 欧美一区在线直播| 亚洲第一中文字幕| 国产精品日韩一区| 久久精品中文字幕免费mv| 色综合伊人色综合网| 国产一区二区三区在线视频| 欧美在线激情视频| 黑人巨大精品欧美一区二区免费| 美女扒开尿口让男人操亚洲视频网站| 欧美在线观看一区二区三区| 97在线免费观看视频| 日韩中文字幕在线免费观看| 中文字幕亚洲一区二区三区五十路| 热久久99这里有精品| 国产欧美一区二区三区视频| 欧美成人中文字幕在线| 国产成人欧美在线观看|