欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

[轉帖]學習 HTML5 Canvas 這一篇文章就夠了

liguoquan
2023年11月28日 11:52 本文熱度 623
:學習 HTML5 Canvas 這一篇文章就夠了


一、canvas 簡介

<canvas>HTML5 新增的,一個可以使用腳本(通常為 Javascript) 在其中繪制圖像的 HTML 元素。它可以用來制作照片集或者制作簡單(也不是那么簡單)的動畫,甚至可以進行實時視頻處理和渲染。

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

Canvas 是由 HTML 代碼配合高度和寬度屬性而定義出的可繪制區域。Javascript 代碼可以訪問該區域,類似于其他通用的二維 API,通過一套完整的繪圖函數來動態生成圖形。

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

二、Canvas基本使用

<canvas id="tutorial" width="300" height="300"></canvas>

2.1 <canvas> 元素

<canvas> 看起來和 <img> 標簽一樣,只是 <canvas> 只有兩個可選的屬性 width、heigth 屬性,而沒有 src、alt 屬性。

如果不給 <canvas> 設置 widht、height 屬性時,則默認 width為300、height 為 150,單位都是 px。也可以使用 css 屬性來設置寬高,但是如寬高屬性和初始比例不一致,他會出現扭曲。所以,建議永遠不要使用 css 屬性來設置 <canvas> 的寬高。

替換內容

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

支持 <canvas> 的瀏覽器會只渲染 <canvas> 標簽,而忽略其中的替代內容。不支持 <canvas> 的瀏覽器則 會直接渲染替代內容。

用文本替換:

<canvas>
    你的瀏覽器不支持 canvas,請升級你的瀏覽器。
</canvas>

<img> 替換:

<canvas>
    <img decoding="async" src="./美女.jpg" alt=""> 
</canvas>

結束標簽 </canvas> 不可省略。

<img> 元素不同,<canvas> 元素需要結束標簽(</canvas>)。如果結束標簽不存在,則文檔的其余部分會被認為是替代內容,將不會顯示出來。

2.2 渲染上下文(Thre Rending Context)

<canvas> 會創建一個固定大小的畫布,會公開一個或多個渲染上下文(畫筆),使用渲染上下文來繪制和處理要展示的內容。

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

var canvas = document.getElementById('tutorial');
//獲得 2d 上下文對象
var ctx = canvas.getContext('2d');

2.3 檢測支持性

var canvas = document.getElementById('tutorial');
if (canvas.getContext){
  var ctx = canvas.getContext('2d');
  // drawing code here
} else {
  // canvas-unsupported code here
}

2.4 代碼模板

<html>
<head>
    <title>Canvas tutorial</title>
    <style type="text/css">
        canvas {
            border: 1px solid black;
        }
    </style>
</head>
<canvas id="tutorial" width="300" height="300"></canvas>
</body>
<script type="text/javascript">
    function draw(){
        var canvas = document.getElementById('tutorial');
        if(!canvas.getContext) return;
      	var ctx = canvas.getContext("2d");
      	//開始代碼
        
    }
    draw();
</script>
</html>

2.5 一個簡單的例子

以下實例繪制兩個長方形:

實例

<html>
<head>
    <title>Canvas tutorial</title>
    <style type="text/css">
        canvas {
            border: 1px solid black;
        }
    </style>
</head>
<canvas id="tutorial" width="300" height="300"></canvas>
</body>
<script type="text/javascript">
    function draw(){
        var canvas = document.getElementById('tutorial');
        if(!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.fillStyle = "rgb(200,0,0)";
      	//繪制矩形
        ctx.fillRect (10, 10, 55, 50);
        ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
        ctx.fillRect (30, 30, 55, 50);
    }
    draw();
</script>
</html>

三、繪制形狀

3.1 柵格 (grid) 和坐標空間

如下圖所示,canvas 元素默認被網格所覆蓋。通常來說網格中的一個單元相當于 canvas 元素中的一像素。柵格的起點為左上角,坐標為 (0,0) 。所有元素的位置都相對于原點來定位。所以圖中藍色方形左上角的坐標為距離左邊(X 軸)x 像素,距離上邊(Y 軸)y 像素,坐標為 (x,y)。

后面我們會涉及到坐標原點的平移、網格的旋轉以及縮放等。



3.2 繪制矩形

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

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

  • 1、fillRect(x, y, width, height):繪制一個填充的矩形。

  • 2、strokeRect(x, y, width, height):繪制一個矩形的邊框。

  • 3、clearRect(x, y, widh, height):清除指定的矩形區域,然后這塊區域會變的完全透明。

說明:這 3 個方法具有相同的參數。

  • x, y:指的是矩形的左上角的坐標。(相對于canvas的坐標原點)

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

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




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




四、繪制路徑 (path)

圖形的基本元素是路徑。

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

一個路徑,甚至一個子路徑,都是閉合的。

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

  1. 創建路徑起始點

  2. 調用繪制方法去繪制出路徑

  3. 把路徑封閉

  4. 一旦路徑生成,通過描邊或填充路徑區域來渲染圖形。

下面是需要用到的方法:

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

  2. moveTo(x, y)
    把畫筆移動到指定的坐標(x, y)。相當于設置路徑的起始點坐標。

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

  4. stroke()
    通過線條來繪制圖形輪廓

  5. fill()
    通過填充路徑的內容區域生成實心的圖形

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); //把畫筆移動到指定的坐標
    ctx.lineTo(200, 50);  //繪制一條從當前位置到指定坐標(200, 50)的直線.
    //閉合路徑。會拉一條從當前點到path起始點的直線。如果當前點與起始點重合,則什么都不做
    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會closePath,仍然是一個3角形
    ctx.stroke(); //描邊。stroke不會自動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(); //填充閉合區域。如果path沒有閉合,則fill()會自動閉合路徑。
}
draw();



4.4 繪制圓弧

有兩個方法可以繪制圓?。?/p>

1、arc(x, y, r, startAngle, endAngle, anticlockwise): 以(x, y) 為圓心,以r 為半徑,從 startAngle 弧度開始到endAngle弧度結束。anticlosewise 是布爾值,true 表示逆時針,false 表示順時針(默認是順時針)。

注意:

  1. 這里的度數都是弧度。

  2. 0 弧度是指的 x 軸正方向。
    radians=(Math.PI/180)*degrees   //角度轉換成弧度

2、arcTo(x1, y1, x2, y2, radius): 根據給定的控制點和半徑畫一段圓弧,最后再以直線連接兩個控制點。

圓弧案例 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);
  	//參數1、2:控制點1坐標   參數3、4:控制點2坐標  參數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 方法的說明:

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

第 1 條切線:起始點和控制點1決定的直線。

第 2 條切線:控制點1 和控制點2決定的直線。

其實繪制的圓弧就是與這兩條直線相切的圓弧。

4.5 繪制貝塞爾曲線

4.5.1 什么是貝塞爾曲線


貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用于二維圖形應用程序的數學曲線。

一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段與節點組成,節點是可拖動的支點,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種矢量曲線的。

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

貝塞爾曲線于 1962,由法國工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發表,他運用貝塞爾曲線來為汽車的主體進行設計。貝塞爾曲線最初由Paul de Casteljau 于 1959 年運用 de Casteljau 演算法開發,以穩定數值的方法求出貝茲曲線。

一次貝塞爾曲線其實是一條直線


動圖封面


二次貝塞爾曲線


動圖封面




三次貝塞爾曲線


動圖封面




4.5.2 繪制貝塞爾曲線

繪制二次貝塞爾曲線:

quadraticCurveTo(cp1x, cp1y, x, y)

說明:

  • 參數 1 和 2:控制點坐標

  • 參數 3 和 4:結束點坐標

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(10, 200); //起始點
    var cp1x = 40, cp1y = 100;  //控制點
    var x = 200, y = 200; // 結束點
    //繪制二次貝塞爾曲線
    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)

說明:

  • 參數 1 和 2:控制點 1 的坐標

  • 參數 3 和 4:控制點 2 的坐標

  • 參數 5 和 6:結束點的坐標

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(40, 200); //起始點
    var cp1x = 20, cp1y = 100;  //控制點1
    var cp2x = 100, cp2y = 120;  //控制點2
    var x = 200, y = 200; // 結束點
    //繪制二次貝塞爾曲線
    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();




五、添加樣式和顏色

在前面的繪制矩形章節中,只用到了默認的線條和顏色。

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

  1. fillStyle = color 設置圖形的填充顏色

  2. strokeStyle = color 設置圖形輪廓的顏色

備注:

  • 1. color 可以是表示 css 顏色值的字符串、漸變對象或者圖案對象。

  • 2. 默認情況下,線條和填充顏色都是黑色。

  • 3. 一旦您設置了 strokeStyle 或者 fillStyle 的值,那么這個新值就會成為新繪制的圖形的默認值。如果你要給每個圖形上不同的顏色,你需要重新設置 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

<script type="text/javascript">
    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.strokeStyle = `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
                ctx.strokeRect(j * 50, i * 50, 40, 40);
            }
        }
    }
    draw();
    /**
     作者:李振超      4 Jun 2017 12:12
     返回隨機的 [from, to] 之間的整數(包括from,也包括to)
     */
    function randomInt(from, to){
        return parseInt(Math.random() * (to - from + 1) + from);
    }
</script>



Transparency(透明度)

globalAlpha = transparencyValue: 這個屬性影響到 canvas 里所有圖形的透明度,有效的值范圍是 0.0 (完全透明)到 1.0(完全不透明),默認是 1.0。

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

1、line style

線寬。只能是正值。默認是 1.0。

起始點和終點的連線為中心,上下各占線寬的一半

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 個值:

  1. butt:線段末端以方形結束

  2. round:線段末端以圓形結束

  3. square:線段末端以方形結束,但是增加了一個寬度和線段相同,高度是線段厚度一半的矩形區域。

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
同一個 path 內,設定線條與線條間接合處的樣式。
共有 3 個值 round, bevelmiter

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

    2. bevel 在相連部分的末端填充一個額外的以三角形為底的區域, 每個部分都有各自獨立的矩形拐角。

    3. miter(默認) 通過延伸相連部分的外邊緣,使其相交于一點,形成一個額外的菱形區域。

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 屬性來制定虛線樣式。 setLineDash 方法接受一個數組,來指定線段與間隙的交替;lineDashOffset屬性設置起始偏移量。

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    
    ctx.setLineDash([20, 5]);  // [實線長度, 間隙長度]
    ctx.lineDashOffset = -0;
    ctx.strokeRect(50, 50, 210, 210);
}
draw();



備注: getLineDash() 返回一個包含當前虛線樣式,長度為非負偶數的數組。

六、繪制文本

繪制文本的兩個方法

canvas 提供了兩種方法來渲染文本:

      1. fillText(text, x, y [, maxWidth]) 在指定的 (x,y) 位置填充指定的文本,繪制的最大寬度是可選的。

      2. 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();



給文本添加樣式

        1. font = value 當前我們用來繪制文本的樣式。這個字符串使用和 CSS font 屬性相同的語法。 默認的字體是 10px sans-serif

        2. textAlign = value 文本對齊選項。 可選的值包括:start, end, left, right or center。 默認值是 start

        3. textBaseline = value 基線對齊選項,可選的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默認值是 alphabetic。。

        4. direction = value 文本方向??赡艿闹蛋ǎ?code>ltr, rtl, inherit。默認值是 inherit。

七、繪制圖片

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

7.1 由零開始創建圖片

創建<img>元素

var img = new Image();   // 創建一個<img>元素
img.src = 'myImage.png'; // 設置圖片源地址

腳本執行后圖片開始裝載。

繪制 img

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

注意:考慮到圖片是從網絡加載,如果 drawImage 的時候圖片還沒有完全加載完成,則什么都不做,個別瀏覽器會拋異常。所以我們應該保證在 img 繪制完成之后再 drawImage。

var img = new Image();   // 創建img元素
img.onload = function(){
  ctx.drawImage(img, 0, 0)
}
img.src = 'myImage.png'; // 設置圖片源地址

7.2 繪制 img 標簽元素中的圖片

img 可以 new 也可以來源于我們頁面的 <img>標簽。

<img src="./美女.jpg" alt="" width="300"><br>
<canvas id="tutorial" width="600" height="400"></canvas>
<script type="text/javascript">
    function draw(){
        var canvas = document.getElementById('tutorial');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        var img = document.queryselector("img");
        ctx.drawImage(img, 0, 0);
    }
    document.queryselector("img").onclick = function (){
        draw();
    }
</script>

第一張圖片就是頁面中的 <img> 標簽:



7.3 縮放圖片

drawImage() 也可以再添加兩個參數:

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

這個方法多了 2 個參數:widthheight,這兩個參數用來控制 當像 canvas 畫入時應該縮放的大小。

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



7.4 切片(slice)

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

第一個參數和其它的是相同的,都是一個圖像或者另一個 canvas 的引用。

其他 8 個參數:

前 4 個是定義圖像源的切片位置和大小,后 4 個則是定義切片的目標顯示位置和大小。



八、狀態的保存和恢復

Saving and restoring state 是繪制復雜圖形時必不可少的操作。

save()restore()

saverestore 方法是用來保存和恢復 canvas 狀態的,都沒有參數。

Canvas 的狀態就是當前畫面應用的所有樣式和變形的一個快照。

1、關于 save() :Canvas狀態存儲在棧中,每當save()方法被調用后,當前的狀態就被推送到棧中保存。

一個繪畫狀態包括:

        • 當前應用的變形(即移動,旋轉和縮放)

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

        • 當前的裁切路徑(clipping path

          可以調用任意多次 save方法(類似數組的 push())。

可以調用任意多次 save方法(類似數組的push())。

2、關于restore():每一次調用 restore 方法,上一個保存的狀態就從棧中彈出,所有設定都恢復(類似數組的 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);   // 使用默認設置繪制一個矩形
    ctx.save();                  // 保存默認狀態
    ctx.fillStyle = 'red'       // 在原有配置基礎上對顏色做改變
    ctx.fillRect(15, 15, 120, 120); // 使用新的設置繪制一個矩形
    ctx.save();                  // 保存當前狀態
    ctx.fillStyle = '#FFF'       // 再次改變顏色配置
    ctx.fillRect(30, 30, 90, 90);   // 使用新的配置繪制一個矩形
    ctx.restore();               // 重新加載之前的顏色狀態
    ctx.fillRect(45, 45, 60, 60);   // 使用上一次的配置繪制一個矩形
    ctx.restore();               // 加載默認顏色配置
    ctx.fillRect(60, 60, 30, 30);   // 使用加載的配置繪制一個矩形
}
draw();


九、變形

9.1 translate

translate(x, y)

用來移動 canvas原點到指定的位置

translate 方法接受兩個參數。x 是左右偏移量,y 是上下偏移量,如右圖所示。

在做變形之前先保存狀態是一個良好的習慣。大多數情況下,調用 restore 方法比手動恢復原先的狀態要簡單得多。又如果你是在一個循環中做位移但沒有保存和恢復 canvas 的狀態,很可能到最后會發現怎么有些東西不見了,那是因為它很可能已經超出 canvas 范圍以外了。

注意:translate 移動的是 canvas 的坐標原點(坐標變換)。



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



9.2 rotate

rotate(angle)


旋轉坐標軸。


這個方法只接受一個參數:旋轉的角度(angle),它是順時針方向的,以弧度為單位的值。

旋轉的中心是坐標原點。



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)

我們用它來增減圖形在 canvas 中的像素數目,對形狀,位圖進行縮小或者放大。

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

默認情況下,canvas 的 1 單位就是 1 個像素。舉例說,如果我們設置縮放因子是 0.5,1 個單位就變成對應 0.5 個像素,這樣繪制出來的形狀就會是原先的一半。同理,設置為 2.0 時,1 個單位就對應變成了 2 像素,繪制的結果就是圖形放大了 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();



十、合成


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

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();
</script>

:下面的展示中,藍色是原有的,紅色是新的。

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

1、這是默認設置,新圖像會覆蓋在原有圖像。




2. source-in

僅僅會出現新圖像與原來圖像重疊的部分,其他區域都變成透明的。(包括其他的老圖像區域也會透明)




3. source-out

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



4. source-atop

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



5. destination-over

新圖像會在老圖像的下面。



6. destination-in

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



7. destination-out

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



8. destination-atop

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



9. lighter

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



10. darken

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

blue: #0000ff
red: #ff0000

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



11. lighten

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

blue: #0000ff
red: #ff0000

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



12. xor

重疊部分會變成透明。



13. copy

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




十一、裁剪路徑

clip()


把已經創建的路徑轉換成裁剪路徑。


裁剪路徑的作用是遮罩。只顯示裁剪路徑內的區域,裁剪路徑外的區域會被隱藏。


注意:clip() 只能遮罩在這個方法調用之后繪制的圖像,如果是 clip() 方法調用之前繪制的圖像,則無法實現遮罩。



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();

十二、動畫

動畫的基本步驟

        1. 清空 canvas 再繪制每一幀動畫之前,需要清空所有。清空所有最簡單的做法就是 clearRect() 方法。

        2. 保存 canvas 狀態 如果在繪制的過程中會更改 canvas 的狀態(顏色、移動了坐標原點等),又在繪制每一幀時都是原始狀態的話,則最好保存下 canvas 的狀態

        3. 繪制動畫圖形這一步才是真正的繪制動畫幀

        4. 恢復 canvas 狀態如果你前面保存了 canvas 狀態,則應該在繪制完成一幀之后恢復 canvas 狀態。

控制動畫

我們可用通過 canvas 的方法或者自定義的方法把圖像會知道到 canvas 上。正常情況,我們能看到繪制的結果是在腳本執行結束之后。例如,我們不可能在一個 for 循環內部完成動畫。

也就是,為了執行動畫,我們需要一些可以定時執行重繪的方法。

一般用到下面三個方法:

        1. setInterval()

        2. setTimeout()

        3. requestAnimationFrame()

案例1:太陽系

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); //清空所有的內容
    /*繪制 太陽*/
    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:模擬時鐘

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            padding: 0;
            margin: 0;
            background-color: rgba(0, 0, 0, 0.1)
        }
        
        canvas {
            display: block;
            margin: 200px auto;
        }
    </style>
</head>
<body>
<canvas id="solar" width="300" height="300"></canvas>
<script>
    init();
    function init(){
        let canvas = document.queryselector("#solar");
        let ctx = canvas.getContext("2d");
        draw(ctx);
    }
    function draw(ctx){
        requestAnimationFrame(function step(){
            drawDial(ctx); //繪制表盤
            drawAllHands(ctx); //繪制時分秒針
            requestAnimationFrame(step);
        });
    }
    /*繪制時分秒針*/
    function drawAllHands(ctx){
        let time = new Date();
        let s = time.getSeconds();
        let m = time.getMinutes();
        let h = time.getHours();
        
        let pi = Math.PI;
        let secondAngle = pi / 180 * 6 * s;  //計算出來s針的弧度
        let minuteAngle = pi / 180 * 6 * m + secondAngle / 60;  //計算出來分針的弧度
        let hourAngle = pi / 180 * 30 * h + minuteAngle / 12;  //計算出來時針的弧度
        drawHand(hourAngle, 60, 6, "red", ctx);  //繪制時針
        drawHand(minuteAngle, 106, 4, "green", ctx);  //繪制分針
        drawHand(secondAngle, 129, 2, "blue", ctx);  //繪制秒針
    }
    /*繪制時針、或分針、或秒針
     * 參數1:要繪制的針的角度
     * 參數2:要繪制的針的長度
     * 參數3:要繪制的針的寬度
     * 參數4:要繪制的針的顏色
     * 參數4:ctx
     * */
    function drawHand(angle, len, width, color, ctx){
        ctx.save();
        ctx.translate(150, 150); //把坐標軸的遠點平移到原來的中心
        ctx.rotate(-Math.PI / 2 + angle);  //旋轉坐標軸。 x軸就是針的角度
        ctx.beginPath();
        ctx.moveTo(-4, 0);
        ctx.lineTo(len, 0);  // 沿著x軸繪制針
        ctx.lineWidth = width;
        ctx.strokeStyle = color;
        ctx.lineCap = "round";
        ctx.stroke();
        ctx.closePath();
        ctx.restore();
    }
    
    /*繪制表盤*/
    function drawDial(ctx){
        let pi = Math.PI;
        
        ctx.clearRect(0, 0, 300, 300); //清除所有內容
        ctx.save();
        ctx.translate(150, 150); //一定坐標原點到原來的中心
        ctx.beginPath();
        ctx.arc(0, 0, 148, 0, 2 * pi); //繪制圓周
        ctx.stroke();
        ctx.closePath();
        for (let i = 0; i < 60; i++){//繪制刻度。
            ctx.save();
            ctx.rotate(-pi / 2 + i * pi / 30);  //旋轉坐標軸。坐標軸x的正方形從 向上開始算起
            ctx.beginPath();
            ctx.moveTo(110, 0);
            ctx.lineTo(140, 0);
            ctx.lineWidth = i % 5 ? 2 : 4;
            ctx.strokeStyle = i % 5 ? "blue" : "red";
            ctx.stroke();
            ctx.closePath();
            ctx.restore();
        }
        ctx.restore();
    }
</script>
</body>
</html>
動圖封面




該文章在 2023/11/28 11:52:30 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved