成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

學(xué)習(xí)HTML5 Canvas這一篇文章就夠了

Eidesen / 901人閱讀

摘要:本文作者利用一些簡(jiǎn)單的對(duì)進(jìn)行了系統(tǒng)的總結(jié),受益匪淺,毫不夸張的說,學(xué)習(xí)這一篇文章就夠了一簡(jiǎn)介是新增的,一個(gè)可以使用腳本通常為在其中繪制圖像的元素。

本文作者利用一些簡(jiǎn)單的 demo 對(duì) Canvas 進(jìn)行了系統(tǒng)的總結(jié),受益匪淺,毫不夸張的說,學(xué)習(xí) Canvas 這一篇文章就夠了!
一、canvas簡(jiǎn)介

? HTML5 新增的,一個(gè)可以使用腳本(通常為JavaScript)在其中繪制圖像的 HTML 元素。它可以用來(lái)制作照片集或者制作簡(jiǎn)單(也不是那么簡(jiǎn)單)的動(dòng)畫,甚至可以進(jìn)行實(shí)時(shí)視頻處理和渲染。

? 它最初由蘋果內(nèi)部使用自己MacOS X WebKit推出,供應(yīng)用程序使用像儀表盤的構(gòu)件和 Safari 瀏覽器使用。 后來(lái),有人通過Gecko內(nèi)核的瀏覽器 (尤其是MozillaFirefox),OperaChrome和超文本網(wǎng)絡(luò)應(yīng)用技術(shù)工作組建議為下一代的網(wǎng)絡(luò)技術(shù)使用該元素。

? Canvas是由HTML代碼配合高度和寬度屬性而定義出的可繪制區(qū)域。JavaScript代碼可以訪問該區(qū)域,類似于其他通用的二維API,通過一套完整的繪圖函數(shù)來(lái)動(dòng)態(tài)生成圖形。

? Mozilla 程序從 Gecko 1.8 (Firefox 1.5)開始支持 , Internet Explorer 從IE9開始 。Chrome和Opera 9+ 也支持

二、Canvas基本使用 2.1 元素

? 看起來(lái)和標(biāo)簽一樣,只是 只有兩個(gè)可選的屬性 width、heigth 屬性,而沒有 src、alt 屬性。

? 如果不給設(shè)置widht、height屬性時(shí),則默認(rèn) width為300、height為150,單位都是px。也可以使用css屬性來(lái)設(shè)置寬高,但是如寬高屬性和初始比例不一致,他會(huì)出現(xiàn)扭曲。所以,建議永遠(yuǎn)不要使用css屬性來(lái)設(shè)置的寬高。

替換內(nèi)容

? 由于某些較老的瀏覽器(尤其是IE9之前的IE瀏覽器)或者瀏覽器不支持HTML元素,在這些瀏覽器上你應(yīng)該總是能展示替代內(nèi)容。

? 支持的瀏覽器會(huì)只渲染標(biāo)簽,而忽略其中的替代內(nèi)容。不支持 的瀏覽器則 會(huì)直接渲染替代內(nèi)容。

用文本替換:

    你的瀏覽器不支持canvas,請(qǐng)升級(jí)你的瀏覽器

 替換:

     

結(jié)束標(biāo)簽不可省

元素不同,元素需要結(jié)束標(biāo)簽()。如果結(jié)束標(biāo)簽不存在,則文檔的其余部分會(huì)被認(rèn)為是替代內(nèi)容,將不會(huì)顯示出來(lái)。

2.2 渲染上下文(Thre Rending Context)

? 會(huì)創(chuàng)建一個(gè)固定大小的畫布,會(huì)公開一個(gè)或多個(gè) 渲染上下文(畫筆),使用 渲染上下文來(lái)繪制和處理要展示的內(nèi)容。

? 我們重點(diǎn)研究 2D渲染上下文。 其他的上下文我們暫不研究,比如, WebGL使用了基于OpenGL ES的3D上下文 (“experimental-webgl”) 。

var canvas = document.getElementById("tutorial");
//獲得 2d 上下文對(duì)象
var ctx = canvas.getContext("2d");
2.3 檢測(cè)支持性
var canvas = document.getElementById("tutorial");

if (canvas.getContext){
  var ctx = canvas.getContext("2d");
  // drawing code here
} else {
  // canvas-unsupported code here
}
2.4 代碼模板


    Canvas tutorial
    





2.5 一個(gè)簡(jiǎn)單的例子
繪制兩個(gè)長(zhǎng)方形。


    Canvas tutorial
    





三、繪制形狀 3.1 柵格(grid)和坐標(biāo)空間

? 如下圖所示,canvas元素默認(rèn)被網(wǎng)格所覆蓋。通常來(lái)說網(wǎng)格中的一個(gè)單元相當(dāng)于canvas元素中的一像素。柵格的起點(diǎn)為左上角(坐標(biāo)為(0,0))。所有元素的位置都相對(duì)于原點(diǎn)來(lái)定位。所以圖中藍(lán)色方形左上角的坐標(biāo)為距離左邊(X軸)x像素,距離上邊(Y軸)y像素(坐標(biāo)為(x,y))。

? 后面我們會(huì)涉及到坐標(biāo)原點(diǎn)的平移、網(wǎng)格的旋轉(zhuǎn)以及縮放等。

3.2 繪制矩形

? 只支持一種原生的 圖形繪制:矩形。所有其他圖形都至少需要生成一種路徑(path)。不過,我們擁有眾多路徑生成的方法讓復(fù)雜圖形的繪制成為了可能。

canvast 提供了三種方法繪制矩形:

fillRect(x, y, width, height)

繪制一個(gè)填充的矩形

strockRect(x, y, width, height)

繪制一個(gè)矩形的邊框

clearRect(x, y, widh, height)

清除指定的矩形區(qū)域,然后這塊區(qū)域會(huì)變的完全透明。

說明:

? 這3個(gè)方法具有相同的參數(shù)。

? x, y:指的是矩形的左上角的坐標(biāo)。(相對(duì)于canvas的坐標(biāo)原點(diǎn))

? width, height:指的是繪制的矩形的寬和高。

function draw(){
    var canvas = document.getElementById("tutorial");
    if(!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.fillRect(10, 10, 100, 50);  //繪制矩形,填充的默認(rèn)顏色為黑色
    ctx.strokeRect(10, 70, 100, 50);  //繪制矩形邊框

}
draw();

ctx.clearRect(15, 15, 50, 25);

四、繪制路徑(path)

? 圖形的基本元素是路徑。

? 路徑是通過不同顏色和寬度的線段或曲線相連形成的不同形狀的點(diǎn)的集合。

? 一個(gè)路徑,甚至一個(gè)子路徑,都是閉合的。

使用路徑繪制圖形需要一些額外的步驟:

創(chuàng)建路徑起始點(diǎn)

調(diào)用繪制方法去繪制出路徑

把路徑封閉

一旦路徑生成,通過描邊或填充路徑區(qū)域來(lái)渲染圖形。

下面是需要用到的方法:

beginPath()

新建一條路徑,路徑一旦創(chuàng)建成功,圖形繪制命令被指向到路徑上生成路徑

moveTo(x, y)

把畫筆移動(dòng)到指定的坐標(biāo)(x, y)。相當(dāng)于設(shè)置路徑的起始點(diǎn)坐標(biāo)。

closePath()

閉合路徑之后,圖形繪制命令又重新指向到上下文中

stroke()

通過線條來(lái)繪制圖形輪廓

fill()

通過填充路徑的內(nèi)容區(qū)域生成實(shí)心的圖形

4.1 繪制線段
function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath(); //新建一條path
    ctx.moveTo(50, 50); //把畫筆移動(dòng)到指定的坐標(biāo)
    ctx.lineTo(200, 50);  //繪制一條從當(dāng)前位置到指定坐標(biāo)(200, 50)的直線.
    //閉合路徑。會(huì)拉一條從當(dāng)前點(diǎn)到path起始點(diǎn)的直線。如果當(dāng)前點(diǎn)與起始點(diǎn)重合,則什么都不做
    ctx.closePath();
    ctx.stroke(); //繪制路徑。
}
draw();
4.2 繪制三角形邊框
function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(50, 50);
    ctx.lineTo(200, 50);
    ctx.lineTo(200, 200);
    ctx.closePath(); //雖然我們只繪制了兩條線段,但是closePath會(huì)closePath,仍然是一個(gè)3角形
    ctx.stroke(); //描邊。stroke不會(huì)自動(dòng)closePath()
}
draw();

4.3 填充三角形
function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(50, 50);
    ctx.lineTo(200, 50);
    ctx.lineTo(200, 200);

    ctx.fill(); //填充閉合區(qū)域。如果path沒有閉合,則fill()會(huì)自動(dòng)閉合路徑。
}
draw();

4.4 繪制圓弧
有兩個(gè)方法可以繪制圓?。?/pre>

arc(x, y, r, startAngle, endAngle, anticlockwise):

(x, y)為圓心,以r為半徑,從 startAngle弧度開始到endAngle弧度結(jié)束。anticlosewise是布爾值,true表示逆時(shí)針,false表示順時(shí)針。(默認(rèn)是順時(shí)針)

注意:

這里的度數(shù)都是弧度。

0弧度是指的x軸正方形

radians=(Math.PI/180)*degrees //角度轉(zhuǎn)換成弧度

arcTo(x1, y1, x2, y2, radius):

根據(jù)給定的控制點(diǎn)和半徑畫一段圓弧,最后再以直線連接兩個(gè)控制點(diǎn)。

圓弧案例1:
function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
    ctx.stroke();
}
draw();

圓弧案例2:
function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
    ctx.stroke();

    ctx.beginPath();
    ctx.arc(150, 50, 40, 0, -Math.PI / 2, true);
    ctx.closePath();
    ctx.stroke();

    ctx.beginPath();
    ctx.arc(50, 150, 40, -Math.PI / 2, Math.PI / 2, false);
    ctx.fill();

    ctx.beginPath();
    ctx.arc(150, 150, 40, 0, Math.PI, false);
    ctx.fill();

}
draw();

圓弧案例3:
function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(50, 50);
    //參數(shù)1、2:控制點(diǎn)1坐標(biāo)   參數(shù)3、4:控制點(diǎn)2坐標(biāo)  參數(shù)4:圓弧半徑
    ctx.arcTo(200, 50, 200, 200, 100);
    ctx.lineTo(200, 200)
    ctx.stroke();

    ctx.beginPath();
    ctx.rect(50, 50, 10, 10);
    ctx.rect(200, 50, 10, 10)
    ctx.rect(200, 200, 10, 10)
    ctx.fill()
}
draw();

arcTo方法的說明:

? 這個(gè)方法可以這樣理解。繪制的弧形是由兩條切線所決定。

? 第 1 條切線:起始點(diǎn)和控制點(diǎn)1決定的直線。

? 第 2 條切線:控制點(diǎn)1 和控制點(diǎn)2決定的直線。

? 其實(shí)繪制的圓弧就是與這兩條直線相切的圓弧。

4.5 繪制貝塞爾曲線 4.5.1 什么是貝塞爾曲線

? 貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。

? 一般的矢量圖形軟件通過它來(lái)精確畫出曲線,貝茲曲線由線段與節(jié)點(diǎn)組成,節(jié)點(diǎn)是可拖動(dòng)的支點(diǎn),線段像可伸縮的皮筋,我們?cè)诶L圖工具上看到的鋼筆工具就是來(lái)做這種矢量曲線的。

? 貝塞爾曲線是計(jì)算機(jī)圖形學(xué)中相當(dāng)重要的參數(shù)曲線,在一些比較成熟的位圖軟件中也有貝塞爾曲線工具如PhotoShop等。在Flash4中還沒有完整的曲線工具,而在Flash5里面已經(jīng)提供出貝塞爾曲線工具。

? 貝塞爾曲線于1962,由法國(guó)工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發(fā)表,他運(yùn)用貝塞爾曲線來(lái)為汽車的主體進(jìn)行設(shè)計(jì)。貝塞爾曲線最初由Paul de Casteljau于1959年運(yùn)用de Casteljau演算法開發(fā),以穩(wěn)定數(shù)值的方法求出貝茲曲線。

一次貝塞爾曲線(線性貝塞爾曲線)

? 一次貝塞爾曲線其實(shí)是一條直線。

二次貝塞爾曲線

三次貝塞爾曲線

4.5.2 繪制貝塞爾曲線 繪制二次貝塞爾曲線

quadraticCurveTo(cp1x, cp1y, x, y):

說明:

? 參數(shù)1和2:控制點(diǎn)坐標(biāo)

? 參數(shù)3和4:結(jié)束點(diǎn)坐標(biāo)

function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(10, 200); //起始點(diǎn)
    var cp1x = 40, cp1y = 100;  //控制點(diǎn)
    var x = 200, y = 200; // 結(jié)束點(diǎn)
    //繪制二次貝塞爾曲線
    ctx.quadraticCurveTo(cp1x, cp1y, x, y);
    ctx.stroke();

    ctx.beginPath();
    ctx.rect(10, 200, 10, 10);
    ctx.rect(cp1x, cp1y, 10, 10);
    ctx.rect(x, y, 10, 10);
    ctx.fill();

}
draw();

繪制三次貝塞爾曲線

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

說明:

? 參數(shù)1和2:控制點(diǎn)1的坐標(biāo)

? 參數(shù)3和4:控制點(diǎn)2的坐標(biāo)

? 參數(shù)5和6:結(jié)束點(diǎn)的坐標(biāo)

function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(40, 200); //起始點(diǎn)
    var cp1x = 20, cp1y = 100;  //控制點(diǎn)1
    var cp2x = 100, cp2y = 120;  //控制點(diǎn)2
    var x = 200, y = 200; // 結(jié)束點(diǎn)
    //繪制二次貝塞爾曲線
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    ctx.stroke();

    ctx.beginPath();
    ctx.rect(40, 200, 10, 10);
    ctx.rect(cp1x, cp1y, 10, 10);
    ctx.rect(cp2x, cp2y, 10, 10);
    ctx.rect(x, y, 10, 10);
    ctx.fill();

}
draw();

五、添加樣式和顏色

? 在前面的繪制矩形章節(jié)中,只用到了默認(rèn)的線條和顏色。

? 如果想要給圖形上色,有兩個(gè)重要的屬性可以做到。

fillStyle = color

設(shè)置圖形的填充顏色

strokeStyle = color

設(shè)置圖形輪廓的顏色

備注:
1. `color` 可以是表示 `css` 顏色值的字符串、漸變對(duì)象或者圖案對(duì)象。
2. 默認(rèn)情況下,線條和填充顏色都是黑色。
3. 一旦您設(shè)置了 `strokeStyle` 或者 `fillStyle` 的值,那么這個(gè)新值就會(huì)成為新繪制的圖形的默認(rèn)值。如果你要給每個(gè)圖形上不同的顏色,你需要重新設(shè)置 `fillStyle` 或 `strokeStyle` 的值。

fillStyle
function draw(){
  var canvas = document.getElementById("tutorial");
  if (!canvas.getContext) return;
  var ctx = canvas.getContext("2d");
  for (var i = 0; i < 6; i++){
    for (var j = 0; j < 6; j++){
      ctx.fillStyle = "rgb(" + Math.floor(255 - 42.5 * i) + "," +
        Math.floor(255 - 42.5 * j) + ",0)";
      ctx.fillRect(j * 50, i * 50, 50, 50);
    }
  }
}
draw();

strokeStyle

Transparency(透明度)

globalAlpha = transparencyValue

? 這個(gè)屬性影響到 canvas 里所有圖形的透明度,有效的值范圍是 0.0 (完全透明)到 1.0(完全不透明),默認(rèn)是 1.0。

? globalAlpha 屬性在需要繪制大量擁有相同透明度的圖形時(shí)候相當(dāng)高效。不過,我認(rèn)為使用rgba()設(shè)置透明度更加好一些。

line style 1. lineWidth = value

線寬。只能是正值。默認(rèn)是1.0。

起始點(diǎn)和終點(diǎn)的連線為中心,上下各占線寬的一半

ctx.beginPath();  
ctx.moveTo(10, 10);  
ctx.lineTo(100, 10);  
ctx.lineWidth = 10;  
ctx.stroke();

ctx.beginPath();  
ctx.moveTo(110, 10);  
ctx.lineTo(160, 10)  
ctx.lineWidth = 20;  
ctx.stroke()  

2. lineCap = type

線條末端樣式。

共有3個(gè)值:

butt:線段末端以方形結(jié)束

round:線段末端以圓形結(jié)束

square:線段末端以方形結(jié)束,但是增加了一個(gè)寬度和線段相同,高度是線段厚度一半的矩形區(qū)域。

var lineCaps = ["butt", "round", "square"];

for (var i = 0; i < 3; i++){
   ctx.beginPath();
   ctx.moveTo(20 + 30 * i, 30);
   ctx.lineTo(20 + 30 * i, 100);
   ctx.lineWidth = 20;
   ctx.lineCap = lineCaps[i];
   ctx.stroke();
}

ctx.beginPath();
ctx.moveTo(0, 30);
ctx.lineTo(300, 30);

ctx.moveTo(0, 100);
ctx.lineTo(300, 100)

ctx.strokeStyle = "red";
ctx.lineWidth = 1;
ctx.stroke();

3. lineJoin = type

同一個(gè)path內(nèi),設(shè)定線條與線條間接合處的樣式。

共有3個(gè)值round, bevelmiter

round

通過填充一個(gè)額外的,圓心在相連部分末端的扇形,繪制拐角的形狀。 圓角的半徑是線段的寬度。

bevel

在相連部分的末端填充一個(gè)額外的以三角形為底的區(qū)域, 每個(gè)部分都有各自獨(dú)立的矩形拐角。

miter(默認(rèn))

通過延伸相連部分的外邊緣,使其相交于一點(diǎn),形成一個(gè)額外的菱形區(qū)域。

function draw(){

var canvas = document.getElementById("tutorial");
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d");

var lineJoin = ["round", "bevel", "miter"];
ctx.lineWidth = 20;

for (var i = 0; i < lineJoin.length; i++){
    ctx.lineJoin = lineJoin[i];
    ctx.beginPath();
    ctx.moveTo(50, 50 + i * 50);
    ctx.lineTo(100, 100 + i * 50);
    ctx.lineTo(150, 50 + i * 50);
    ctx.lineTo(200, 100 + i * 50);
    ctx.lineTo(250, 50 + i * 50);
    ctx.stroke();
}

}
draw();

4. 虛線

setLineDash 方法和 lineDashOffset 屬性來(lái)制定虛線樣式. setLineDash 方法接受一個(gè)數(shù)組,來(lái)指定線段與間隙的交替;lineDashOffset屬性設(shè)置起始偏移量.

function draw(){
    var canvas = document.getElementById("tutorial");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");

    ctx.setLineDash([20, 5]);  // [實(shí)線長(zhǎng)度, 間隙長(zhǎng)度]
    ctx.lineDashOffset = -0;
    ctx.strokeRect(50, 50, 210, 210);
}
draw();

備注:

? getLineDash():返回一個(gè)包含當(dāng)前虛線樣式,長(zhǎng)度為非負(fù)偶數(shù)的數(shù)組。

六、繪制文本 繪制文本的兩個(gè)方法

canvas 提供了兩種方法來(lái)渲染文本:

fillText(text, x, y [, maxWidth])

在指定的(x,y)位置填充指定的文本,繪制的最大寬度是可選的.

strokeText(text, x, y [, maxWidth])

在指定的(x,y)位置繪制文本邊框,繪制的最大寬度是可選的.

var ctx;
function draw(){

var canvas = document.getElementById("tutorial");
if (!canvas.getContext) return;
ctx = canvas.getContext("2d");
ctx.font = "100px sans-serif"
ctx.fillText("天若有情", 10, 100);
ctx.strokeText("天若有情", 10, 200)

}
draw();

給文本添加樣式

font = value

當(dāng)前我們用來(lái)繪制文本的樣式。這個(gè)字符串使用和 CSS font屬性相同的語(yǔ)法. 默認(rèn)的字體是 10px sans-serif。

textAlign = value

文本對(duì)齊選項(xiàng). 可選的值包括:start, end, left, right or center. 默認(rèn)值是 start。

textBaseline = value

基線對(duì)齊選項(xiàng),可選的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默認(rèn)值是 alphabetic。

direction = value

文本方向??赡艿闹蛋ǎ?b>ltr, rtl, inherit。默認(rèn)值是 inherit。

七、繪制圖片

? 我們也可以在canvas上直接繪制圖片。

7.1 由零開始創(chuàng)建圖片 創(chuàng)建元素
var img = new Image();   // 創(chuàng)建一個(gè)元素
img.src = "myImage.png"; // 設(shè)置圖片源地址

腳本執(zhí)行后圖片開始裝載

繪制img
//參數(shù)1:要繪制的img  參數(shù)2、3:繪制的img在canvas中的坐標(biāo)
ctx.drawImage(img,0,0); 

注意:

? 考慮到圖片是從網(wǎng)絡(luò)加載,如果 drawImage 的時(shí)候圖片還沒有完全加載完成,則什么都不做,個(gè)別瀏覽器會(huì)拋異常。所以我們應(yīng)該保證在 img 繪制完成之后再 drawImage。

var img = new Image();   // 創(chuàng)建img元素
img.onload = function(){
  ctx.drawImage(img, 0, 0)
}
img.src = "myImage.png"; // 設(shè)置圖片源地址
7.2 繪制 img 標(biāo)簽元素中的圖片

? img 可以 new 也可以來(lái)源于我們頁(yè)面的 標(biāo)簽


第一張圖片就是頁(yè)面中的標(biāo)簽

7.3 縮放圖片

drawImage() 也可以再添加兩個(gè)參數(shù):

? drawImage(image, x, y, width, height)

? 這個(gè)方法多了2個(gè)參數(shù):widthheight,這兩個(gè)參數(shù)用來(lái)控制 當(dāng)像canvas畫入時(shí)應(yīng)該縮放的大小。

ctx.drawImage(img, 0, 0, 400, 200)

7.4 切片(slice)

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

? 第一個(gè)參數(shù)和其它的是相同的,都是一個(gè)圖像或者另一個(gè) canvas 的引用。

其他8個(gè)參數(shù):

? 前4個(gè)是定義圖像源的切片位置和大小,

? 后4個(gè)則是定義切片的目標(biāo)顯示位置和大小。

八、狀態(tài)的保存和恢復(fù)

Saving and restoring state是繪制復(fù)雜圖形時(shí)必不可少的操作。

save()和restore()

? saverestore 方法是用來(lái)保存和恢復(fù) canvas 狀態(tài)的,都沒有參數(shù)。

? Canvas 的狀態(tài)就是當(dāng)前畫面應(yīng)用的所有樣式和變形的一個(gè)快照。

關(guān)于 save()

Canvas狀態(tài)存儲(chǔ)在棧中,每當(dāng)save()方法被調(diào)用后,當(dāng)前的狀態(tài)就被推送到棧中保存。一個(gè)繪畫狀態(tài)包括:

當(dāng)前應(yīng)用的變形(即移動(dòng),旋轉(zhuǎn)和縮放)

strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值

當(dāng)前的裁切路徑(clipping path

?

**可以調(diào)用任意多次 `save`方法。**(類似數(shù)組的`push()`)

關(guān)于restore()

每一次調(diào)用 restore 方法,上一個(gè)保存的狀態(tài)就從棧中彈出,所有設(shè)定都恢復(fù)。(類似數(shù)組的pop())

var ctx;
function draw(){

var canvas = document.getElementById("tutorial");
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d");

ctx.fillRect(0, 0, 150, 150);   // 使用默認(rèn)設(shè)置繪制一個(gè)矩形
ctx.save();                  // 保存默認(rèn)狀態(tài)

ctx.fillStyle = "red"       // 在原有配置基礎(chǔ)上對(duì)顏色做改變
ctx.fillRect(15, 15, 120, 120); // 使用新的設(shè)置繪制一個(gè)矩形

ctx.save();                  // 保存當(dāng)前狀態(tài)
ctx.fillStyle = "#FFF"       // 再次改變顏色配置
ctx.fillRect(30, 30, 90, 90);   // 使用新的配置繪制一個(gè)矩形

ctx.restore();               // 重新加載之前的顏色狀態(tài)
ctx.fillRect(45, 45, 60, 60);   // 使用上一次的配置繪制一個(gè)矩形

ctx.restore();               // 加載默認(rèn)顏色配置
ctx.fillRect(60, 60, 30, 30);   // 使用加載的配置繪制一個(gè)矩形

}
draw();

九、變形 9.1 translate

translate(x, y)

? 用來(lái)移動(dòng) canvas原點(diǎn)到指定的位置

? translate方法接受兩個(gè)參數(shù)。x 是左右偏移量,y 是上下偏移量,如右圖所示。

在做變形之前先保存狀態(tài)是一個(gè)良好的習(xí)慣。大多數(shù)情況下,調(diào)用 restore 方法比手動(dòng)恢復(fù)原先的狀態(tài)要簡(jiǎn)單得多。又如果你是在一個(gè)循環(huán)中做位移但沒有保存和恢復(fù)canvas 的狀態(tài),很可能到最后會(huì)發(fā)現(xiàn)怎么有些東西不見了,那是因?yàn)樗芸赡芤呀?jīng)超出 canvas 范圍以外了。

? 注意:translate移動(dòng)的是canvas的坐標(biāo)原點(diǎn)。(坐標(biāo)變換)

?

var ctx;
function draw(){
    var canvas = document.getElementById("tutorial1");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.save(); //保存坐原點(diǎn)平移之前的狀態(tài)
    ctx.translate(100, 100);
    ctx.strokeRect(0, 0, 100, 100)
    ctx.restore(); //恢復(fù)到最初狀態(tài)
    ctx.translate(220, 220);
    ctx.fillRect(0, 0, 100, 100)
}
draw();

9.2 rotate

rotate(angle)

? 旋轉(zhuǎn)坐標(biāo)軸。

? 這個(gè)方法只接受一個(gè)參數(shù):旋轉(zhuǎn)的角度(angle),它是順時(shí)針方向的,以弧度為單位的值。

? 旋轉(zhuǎn)的中心是坐標(biāo)原點(diǎn)。

var ctx;
function draw(){
  var canvas = document.getElementById("tutorial1");
  if (!canvas.getContext) return;
  var ctx = canvas.getContext("2d");

  ctx.fillStyle = "red";
  ctx.save();

  ctx.translate(100, 100);
  ctx.rotate(Math.PI / 180 * 45);
  ctx.fillStyle = "blue";
  ctx.fillRect(0, 0, 100, 100);
  ctx.restore();

  ctx.save();
  ctx.translate(0, 0);
  ctx.fillRect(0, 0, 50, 50)
  ctx.restore();
}
draw();

9.3 scale

scale(x, y)

? 我們用它來(lái)增減圖形在 canvas 中的像素?cái)?shù)目,對(duì)形狀,位圖進(jìn)行縮小或者放大。

? scale方法接受兩個(gè)參數(shù)。x,y分別是橫軸和縱軸的縮放因子,它們都必須是正值。值比 1.0 小表示縮 小,比 1.0 大則表示放大,值為 1.0 時(shí)什么效果都沒有。

? 默認(rèn)情況下,canvas 的 1 單位就是 1 個(gè)像素。舉例說,如果我們?cè)O(shè)置縮放因子是 0.5,1 個(gè)單位就變成對(duì)應(yīng) 0.5 個(gè)像素,這樣繪制出來(lái)的形狀就會(huì)是原先的一半。同理,設(shè)置為 2.0 時(shí),1 個(gè)單位就對(duì)應(yīng)變成了 2 像素,繪制的結(jié)果就是圖形放大了 2 倍。

9.4 transform(變形矩陣)

transform(a, b, c, d, e, f)

a (m11)

? Horizontal scaling.

b (m12)

? Horizontal skewing.

c (m21)

? Vertical skewing.

d (m22)

? Vertical scaling.

e (dx)

? Horizontal moving.

f (dy)

? Vertical moving.

var ctx;
function draw(){
    var canvas = document.getElementById("tutorial1");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.transform(1, 1, 0, 1, 0, 0);
    ctx.fillRect(0, 0, 100, 100);
}
draw();

十、合成

? 在前面的所有例子中、,我們總是將一個(gè)圖形畫在另一個(gè)之上,對(duì)于其他更多的情況,僅僅這樣是遠(yuǎn)遠(yuǎn)不夠的。比如,對(duì)合成的圖形來(lái)說,繪制順序會(huì)有限制。不過,我們可以利用 globalCompositeOperation 屬性來(lái)改變這種狀況。

globalCompositeOperation = type

    var ctx;
    function draw(){
        var canvas = document.getElementById("tutorial1");
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");

        ctx.fillStyle = "blue";
        ctx.fillRect(0, 0, 200, 200);

        ctx.globalCompositeOperation = "source-over"; //全局合成操作
        ctx.fillStyle = "red";
        ctx.fillRect(100, 100, 200, 200);
    }
    draw();


注:下面的展示中,藍(lán)色是原有的,紅色是新的。

type `是下面 13 種字符串值之一:

1. source-over(default)

這是默認(rèn)設(shè)置,新圖像會(huì)覆蓋在原有圖像。

2. source-in

僅僅會(huì)出現(xiàn)新圖像與原來(lái)圖像重疊的部分,其他區(qū)域都變成透明的。(包括其他的老圖像區(qū)域也會(huì)透明)

3. source-out

僅僅顯示新圖像與老圖像沒有重疊的部分,其余部分全部透明。(老圖像也不顯示)

4. source-atop

新圖像僅僅顯示與老圖像重疊區(qū)域。老圖像仍然可以顯示。

5. destination-over

新圖像會(huì)在老圖像的下面。

6. destination-in

僅僅新老圖像重疊部分的老圖像被顯示,其他區(qū)域全部透明。

7. destination-out

僅僅老圖像與新圖像沒有重疊的部分。 注意顯示的是老圖像的部分區(qū)域。

8. destination-atop

老圖像僅僅僅僅顯示重疊部分,新圖像會(huì)顯示在老圖像的下面。

9. lighter

新老圖像都顯示,但是重疊區(qū)域的顏色做加處理

10. darken

保留重疊部分最黑的像素。(每個(gè)顏色位進(jìn)行比較,得到最小的)

blue: #0000ff

red: #ff0000

所以重疊部分的顏色:#000000

11. lighten

保證重疊部分最量的像素。(每個(gè)顏色位進(jìn)行比較,得到最大的)

blue: #0000ff

red: #ff0000

所以重疊部分的顏色:#ff00ff

12. xor

重疊部分會(huì)變成透明

13. copy

只有新圖像會(huì)被保留,其余的全部被清除(邊透明)

十一、裁剪路徑

clip()

? 把已經(jīng)創(chuàng)建的路徑轉(zhuǎn)換成裁剪路徑。

? 裁剪路徑的作用是遮罩。只顯示裁剪路徑內(nèi)的區(qū)域,裁剪路徑外的區(qū)域會(huì)被隱藏。

? 注意:clip()只能遮罩在這個(gè)方法調(diào)用之后繪制的圖像,如果是clip()方法調(diào)用之前繪制的圖像,則無(wú)法實(shí)現(xiàn)遮罩。

var ctx;
function draw(){
    var canvas = document.getElementById("tutorial1");
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");

    ctx.beginPath();
    ctx.arc(20,20, 100, 0, Math.PI * 2);
    ctx.clip();

    ctx.fillStyle = "pink";
    ctx.fillRect(20, 20, 100,100);
}
draw();
十二、動(dòng)畫 動(dòng)畫的基本步驟

清空canvas

再繪制每一幀動(dòng)畫之前,需要清空所有。清空所有最簡(jiǎn)單的做法就是clearRect()方法

保存canvas狀態(tài)

如果在繪制的過程中會(huì)更改canvas的狀態(tài)(顏色、移動(dòng)了坐標(biāo)原點(diǎn)等),又在繪制每一幀時(shí)都是原始狀態(tài)的話,則最好保存下canvas的狀態(tài)

繪制動(dòng)畫圖形

這一步才是真正的繪制動(dòng)畫幀

恢復(fù)canvas狀態(tài)

如果你前面保存了canvas狀態(tài),則應(yīng)該在繪制完成一幀之后恢復(fù)canvas狀態(tài)。

控制動(dòng)畫

我們可用通過canvas的方法或者自定義的方法把圖像會(huì)知道到canvas上。正常情況,我們能看到繪制的結(jié)果是在腳本執(zhí)行結(jié)束之后。例如,我們不可能在一個(gè) for 循環(huán)內(nèi)部完成動(dòng)畫。

也就是,為了執(zhí)行動(dòng)畫,我們需要一些可以定時(shí)執(zhí)行重繪的方法。

一般用到下面三個(gè)方法:

setInterval()

setTimeout()

requestAnimationFrame()

案例1:太陽(yáng)系
let sun;
let earth;
let moon;
let ctx;
function init(){
    sun = new Image();
    earth = new Image();
    moon = new Image();
    sun.src = "sun.png";
    earth.src = "earth.png";
    moon.src = "moon.png";

    let canvas = document.querySelector("#solar");
    ctx = canvas.getContext("2d");

    sun.onload = function (){
        draw()
    }

}
init();
function draw(){
    ctx.clearRect(0, 0, 300, 300); //清空所有的內(nèi)容
    /*繪制 太陽(yáng)*/
    ctx.drawImage(sun, 0, 0, 300, 300);

    ctx.save();
    ctx.translate(150, 150);

    //繪制earth軌道
    ctx.beginPath();
    ctx.strokeStyle = "rgba(255,255,0,0.5)";
    ctx.arc(0, 0, 100, 0, 2 * Math.PI)
    ctx.stroke()

    let time = new Date();
    //繪制地球
    ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds())
    ctx.translate(100, 0);
    ctx.drawImage(earth, -12, -12)

    //繪制月球軌道
    ctx.beginPath();
    ctx.strokeStyle = "rgba(255,255,255,.3)";
    ctx.arc(0, 0, 40, 0, 2 * Math.PI);
    ctx.stroke();

    //繪制月球
    ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds());
    ctx.translate(40, 0);
    ctx.drawImage(moon, -3.5, -3.5);
    ctx.restore();

    requestAnimationFrame(draw);
}

案例2:模擬時(shí)鐘



    
    Title
    






文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108239.html

相關(guān)文章

  • Scrapy詳解 爬蟲框架入門看這一夠了!

    摘要:目錄前言架構(gòu)安裝第一個(gè)爬蟲爬取有道翻譯創(chuàng)建項(xiàng)目創(chuàng)建創(chuàng)建解析運(yùn)行爬蟲爬取單詞釋義下載單詞語(yǔ)音文件前言學(xué)習(xí)有一段時(shí)間了,當(dāng)時(shí)想要獲取一下百度漢字的解析,又不想一個(gè)個(gè)漢字去搜,復(fù)制粘貼太費(fèi)勁,考慮到爬蟲的便利性,這篇文章是介紹一個(gè)爬蟲框架, 目錄 前言 架構(gòu) 安裝 第一個(gè)爬蟲:爬取有道翻譯 創(chuàng)建項(xiàng)目 創(chuàng)建Item 創(chuàng)建Spider 解析 運(yùn)行爬蟲-爬取單詞釋義 下載單詞語(yǔ)音文件 ...

    lordharrd 評(píng)論0 收藏0
  • 前端簡(jiǎn)單面部識(shí)別

    摘要:前言過年了,來(lái)點(diǎn)有趣的東西最近一直在嘗試通過如何視頻,怎么捕捉視頻的行為,給視頻加點(diǎn)好玩的東西比如給視頻加一個(gè)胡子以下記錄一下最近的玩具點(diǎn)擊這里看自己的效果需要允許攝像頭呀效果效果大概如下就是給視頻的臉上加個(gè)胡子我手機(jī)上有防藍(lán)光的膜,各位大 前言 過年了,來(lái)點(diǎn)有趣的東西 最近一直在嘗試通過web如何DIY視頻,怎么捕捉視頻的行為,給視頻加點(diǎn)好玩的東西,比如給視頻加一個(gè)胡子? 以下記錄一...

    econi 評(píng)論0 收藏0
  • WorkManager從入門到實(shí)踐,有這一夠了

    摘要:前言上一次我們對(duì)的應(yīng)用進(jìn)行了一次全面的分析,這一次我們來(lái)聊聊。 showImg(https://segmentfault.com/img/remote/1460000020077803?w=1280&h=853); 前言 上一次我們對(duì)Paging的應(yīng)用進(jìn)行了一次全面的分析,這一次我們來(lái)聊聊WorkManager。 如果你對(duì)Paging還未了解,推薦閱讀這篇文章: Paging在Recy...

    bingchen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<