Canvas

介紹

SVG是構建XML樹的方式來達到繪製圖形的,canvas是經過調用相關的方法來繪製圖形的。
區別:SVG繪製圖形,經過移除或者更改DOM方式來而使用canvas須要把圖片重新擦除。
繪製的API在繪製上下文中定義。而不在畫布中定義。
須要得到上下文對象的時候,須要調用畫布的getContext方法,得到繪畫的上下文。css

畫布元素和上下文,屬於兩個不一樣的對象,其中畫布元素爲canvas畫布,而上下文對象爲繪製須要的上下文。html

關於3D圖形,即,webGL 爲封裝了基本的OPENGL,當調用webGL的時候,其瀏覽器會調用OpenGL相關的APIweb

繪製圓

<!DOCTYPE html>
<html lang="zh_CN" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>第一個園</br>
    <canvas id="square" width="10" height="100">
    </canvas>
</div>
<div>
    第二個園
    <canvas id="circle" width="10" height="10">
    </canvas>
</div>
<script src="./js/index.js" charset="UTF-8"></script>
</body>
</html>
// 獲取畫布元素
let canvas = document.getElementById("square");
// 獲取繪製2D元素上下文
let context = canvas.getContext("2d");
// 設置填充顏色爲紅色
context.fillStyle = "#f00";
// 填充一個正方形
context.fillRect(10,0,10,10);

繪製線段,填充多邊形

// 獲取畫布元素
let canvas = document.getElementById("square");
// 獲取繪製2D元素上下文
let context = canvas.getContext("2d");
// 開始一條路徑
context.beginPath();
// 從100,100 開始定義一條新的子路徑
context.moveTo(100,100);
// 從100 100 到 200 200 繪製一條線段
context.lineTo(200,200);
// 從200 200 到 100 200 繪製一條線段
context.lineTo(100,200);
// 從100 200 到 100 100 繪製一條路徑
context.lineTo(100,100);
// 繪製邊
context.stroke();
// 進行填充
context.fill();

繪製多邊形

以五邊形爲例子,canvas

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 繪製一個以100,100爲中心,半徑爲20的櫃子N變形,每一個定點均勻分佈在圓角上,第一個定點放置在最上下
// 偏轉角度爲0
// 開始定義一條子路徑
context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0));
// 計算兩個頂點之間夾角
// 其中2π爲一個園,除以邊數,獲得須要旋轉的角度
var delta = 2 * Math.PI/5;
console.log(delta);
// 循環剩餘每一個頂點
var angle = 0;
for(var i = 1; i < 5; i++){
    //  角度累加
    angle += delta;
    // 經過旋轉繪製下一個頂點,不斷的旋轉繪製
    context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle));
}
// 最後一個頂點和起點進行鏈接
context.closePath();
// 重新開始一條新路徑
context.stroke();
context.fill();

同理,畫圓

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 繪製一個以100,100爲中心,半徑爲20的櫃子N變形,每一個定點均勻分佈在圓角上,第一個定點放置在最上下
// 偏轉角度爲0
// 開始定義一條子路徑
context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0));
// 計算兩個頂點之間夾角
// 其中2π爲一個園,除以邊數,獲得須要旋轉的角度
var delta = 2 * Math.PI/500000;
console.log(delta);
// 循環剩餘每一個頂點
var angle = 0;
for(var i = 1; i < 500000; i++){
    //  角度累加
    angle += delta;
    // 經過旋轉繪製下一個頂點,不斷的旋轉繪製
    context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle));
}
// 最後一個頂點和起點進行鏈接
context.closePath();
// 重新開始一條新路徑
context.stroke();
context.fill();

非零繞數原則

要檢測一個點p是否在路徑內部,使用非零繞數原則,即,一條從點p出發沿着任意方向無限延伸,或者一直延伸到路徑所在的區域外某點的射線,如今從0開始初始化一個計數器,對穿過這條射線的路徑進行枚舉,每當一條路徑順時針方向穿過射線的時候,計數器加1,逆時針減1,最後,枚舉完全部路徑之後,若是計時器的值不是0,那麼就認爲p在路徑內,反過來,計數器的值爲0,p在路徑外。api

js根據非零繞數原則肯定那個在路徑內,那個在路徑外,用於進行填充。數組

圖形屬性

能夠經過設置畫布上下文的fillStyle等屬性,設置圖形的屬性,例如對畫布上下文的fillStyle的屬性進行設置,即,能夠設置出填充時的顏色,漸變,圖案等樣式。瀏覽器

對於canvas來講,每次獲取上下文對象的時候,都會返回同一個上下文對象,即,上下文對象爲單例的。app

還可使用save方法,把當前的狀態,壓入已經保存的棧中,調用restore方法,把狀態進行恢復,即彈棧。函數

畫布尺寸座標

畫布的默認的座標系爲左上角的座標原點(0,0),右邊數值大,下數值大,使用浮點數指定座標,但不會自動轉換爲整數,會用反鋸齒的方式,模擬填充部分元素。工具

畫布尺寸不能隨意改變,對任意屬性進行操做,都會清空整個畫布。

座標系變換

每個點的座標都會映射到css像素上,css像素會映射到一個或多個設備像素。
畫布中的特定操做,屬性使用默認座標系。
畫布還有當前變換矩陣。
畫布還有當前變換矩陣,當前變換矩陣做爲圖形狀態的一部分。矩陣定義了當前畫布的座標系。
畫布的操做會把該點映射到當前的座標系中。

座標變換

當調用c.translate(dx,dy)方法的時候,會進行以下變換

translate會進行座標的上下移動

x' = x + dy;
y' = y + dy;

縮放
如要進行縮放,進行的是以下的變換

x' = sx * x;
y' = sy * y;

進行旋轉操做,進行的是以下變換

x' = x * cos(a) - y * sin(a);
y' = y * cos(a) - x * sin(a);

若是要先變換再伸縮,進行以下變換
須要先把現有座標系映射成爲座標系中的點x’, y' 而後再變換到x‘’ , y‘’

x'' = sx*x + dx;
y'' = sy*y + dy;

若是變換順序相反進行以下變換

x'' = sx*(x + dx);
y'' = sy*(y + dy);

這種變換稱爲仿射變換,而且仿射變換會修改點的距離和線段間的夾角。對於平行線來講,仿射變換也會保持平行。仿射變換用6個參數描述成爲以下表述

x' = ax + cy + e;
y' = bx + dy + f;

經過傳入參數實現仿射變換

對於座標變換來講,除非進行刷新,不然,已經繪製的圖形,不會進行消失,全部的變換,都不能對已經繪製的圖形進行更改。栗子以下

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 經過座標變換實現科赫雪花
// 開始一條路徑
context.beginPath();
// 開始繪製子路徑
context.moveTo(100,100);
// 繼續繪製
context.lineTo(200,200);
// 繼續繪製
context.lineTo(200,200);
// 進行繪製邊
context.stroke();
context.translate(200,200);
// 開始一條路徑
context.beginPath();
// 開始繪製子路徑
context.moveTo(100,100);
// 繼續繪製
context.lineTo(200,200);
// 繼續繪製
context.lineTo(200,200);
// 進行繪製邊
context.stroke();

已經繪製的圖形不會進行改變,改變的是已經繪製的圖形

科赫雪花

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 經過座標變換實現科赫雪花
// 當前狀態入棧
function leg(n) {
    // 保存狀態
    context.save();
    // 遞歸畫
    if(n == 0){
        context.lineTo(50, 0);
    }else{
        // 定義爲v字型
        context.scale(1/2,1/2);
        // 遞歸第一條
        context.rotate(60 * (Math.PI / 180));
        leg(n - 1);
        context.rotate(-120 * (Math.PI / 180));
        leg(n - 1);
    }
    // 座標恢復變換
    context.restore();
    // 恢復下一個座標爲0,0
    context.translate(50, 0);
}

context.save();
context.moveTo(50, 50);
// 繪製第一條
leg(1);
context.stroke();

繪製填充曲線

繪製一些常見的圖形

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 工具函數,角度轉弧度
function rads(x) {
    return Math.PI * x / 180;
}

// 繪製園
context.beginPath();
context.arc(100,100,40, 0, rads(360), false);
context.stroke();
context.fill();

同理繪製貝塞爾曲線也是同理。

顏色,透明度,漸變,圖案

繪製一個漸變
須要使用createLinearGradient獲取一個進行漸變的上下文,對這個上下文進行處理。而後其顏色設置爲這個漸變的上下文,即,fillStyle屬性。

線段繪製

封頂

對於線段,有三種封頂方式,即,butt,square,round
在繪製圖形之後,會參數尖角,圓角,平角,三種。
lineCap屬性

文本

和css相似,基線問題。

裁剪

直接調動clip便可,當前路徑也會被裁剪進入,路徑外的通通不會顯示。

陰影

設置shadow屬性便可

圖片

畫布API支持位圖圖片,同時也支持canvas導出成爲圖片。

// 建立一個img元素
let img = document.createElement("img");
// 設置src屬性
img.src = canvas.toDataURL();
// 追加到文檔後面
document.body.appendChild(img);

合成

一些api不在闡述

像素操做

調用getImageDate方法返回ImageDate對象
使用createImageDate()能夠建立像素容器
進行動態模糊先獲取像素的ImageDate對象,而後再獲取該對象的data屬性,該data爲一個數組。爲一個維數組。每四個元素表明紅色份量,綠色份量,藍色份量,透明度份量。(Alpha份量)
其色素直爲0-1,即,數組元素中保存的數組爲色素值。
每四個每四個元素遍歷。而後把其色素值的1/ n + 上一個色塊的m/n 而後賦值給新的色塊,代碼以下

// row爲行數
for(var row = 0; row < height; row++){
    // 得到每行第二個元素的偏移量,其中width爲行的色素塊。
    var i = row * width * 4;
    // 每4個的色素值進行處理
    for(var col = 1; col < width; col++, i+=4){
        // 對紅色份量處理
        data[i] = (data[i] + data[i - 4] * m) / n;
        // 對綠色份量處理
        data[i + 1] = (data[i + 1] + data[i + 1 - 4] * m) / n;
        // 對藍色份量處理
        data[i + 2] = (data[i + 2] + data[i + 2 - 4] * m) / n;
        // 對透明度份量處理
        data[i + 3] = (data[i + 3] + data[i + 3 - 4] * m) / n;
    }
}

而後把其色素塊進行復制回去便可。
其中每一個像素佔據一個字節,一個四個字節。

命中檢測

isPointInPath方法用來肯定一個點是否落在當前路徑中。
即命中檢測。

命中檢測能夠和鼠標事件相互轉化

可是座標須要進行轉換。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息