- canvas元素本身是沒有繪圖能力的,所有的繪製工作必須在 JavaScript 內部完成。
var cv = document.getElementById("myCanvas");
var context = cv.getContext("2d"); //申請一個繪製2d動畫的環境
- 檢測瀏覽器是否支援:也可以用js指令碼檢查if(canvas.getContext)
在不支援時可以在canvas標籤文字中插入提示不支援資訊。<canvas>hey!你現在的瀏覽器不支援canvas畫布哦!請更新瀏覽器。</canvas> 複製程式碼
- 常規繪製例子
-
用canvas繪製直線
(a) context.moveTo(起點x,起點y)
(b) context.lineTo(終點x,終點y):從moveTo提供的起點開始,到lineTo的座標繪製一條直線;若沒有moveTo,則lineTo相當於moveTo。若在一個lineTo後再增設lineTo,即從上一lineTo的座標開始向下一lineTo座標延伸直線。
(c) context.stroke():延給定的座標畫一條直線,也可以指定繪製直線的樣式,顏色粗細等。 -
用canvas繪製矩形
(a) context.fillStyle = "color":填充顏色
(b) context.fillRect(起點x,起點y,寬,高):矩形起點和大小,或者繪製一個沒有填充顏色只有邊框的矩形 (a) context.strokeStyle = "color" :邊框顏色
(b) context.strokeRect(起點x,起點y,寬,高) :只描邊不填充 -
用canvas繪製圓形
(a) context.fillStyle = "color";
(b) context.beginPath():表示開始繪製
(c) context.arc(圓心座標x,圓心座標y,半徑,開始角度,結束角度,是否為按照給定的開始角度和結束角度的按順時針方向繪製)
其中:開始角度為0,結束角度為0.5 PI(正下方),1 PI和1.5 PI(正上方),為畫餅圖提供了扇形範圍的依據.第五個引數是弧長Math.PI*2就是整個圓,Math.PI是半圓
(d) context.closePath():表示結束繪製,會將結束點和開始點通過一點直線連在一起, 即將起點和終點封閉起來,有時可以不要
(e) context.fill():表示填充圖形,有時可以用context.stroke()代替
例子:
for(var i = 0;i<=15;i++){
context.beginPath();
context.arc(150,150,i*10,0,Math.PI*0.5,true); //在0開始,順時針Math.PI*0.5結束,即圓正下方結束
context.stroke(); //不填充而只畫邊框
}
複製程式碼
for(var i = 0;i<=15;i++){
context.beginPath();
context.arc(150,150,i*10,0,Math.PI*1,true);//在0開始,順時針Math.PI結束,即圓正下方半圓結束
context.stroke(); //不填充而只畫邊框
}
複製程式碼
for(var i = 0;i<=15;i++){
context.beginPath();
context.arc(150,150,i*10,0,Math.PI*1.5,true);//在0開始,順時針Math.PI*1.5結束,即圓正上方結束
context.stroke(); //不填充而只畫邊框
}
複製程式碼
for(var i = 0;i<=15;i++){
context.strokeStyle = "red"; //設定邊框顏色
context.beginPath();
context.arc(150,150,i*10,0,Math.PI*2,true);
context.stroke(); //不填充而只畫邊框
}
複製程式碼
- 用canvas繪製三角形
- //空心三角形
context.beginPath(); //開始繪製路徑
context.moveTo(100,100); //起點座標設為(100,100)
context.lineTo(150,150); //下一點的座標設為(150,150)
context.lineTo(50,150); //下一點的座標設為(50,150)
context.closePath();//連線起點與終點
context.stroke(); //繪畫線條
複製程式碼
- //實心三角形
context.fillStyle = "red"; //設定填充顏色
context.moveTo(150,50); //設定起點為(150,50)
context.lineTo(250,250);//下一點的座標設為(150,150)
context.lineTo(50,250);//下一點的座標設為(50,150)
context.fill(); //填充顏色,因為會整個影象填充,所以可以有closePath(),也可以沒有
複製程式碼
- //清除畫布[或某部分]
context.fillStyle = "red";
context.moveTo(150,50);
context.lineTo(250,250);
context.lineTo(50,250);
context.closePath();
context.fill();
var clearBtn = document.getElementById("clearCanvas");
clearBtn.onclick=function(){
context.clearRect(0,0,150,300); //清除某一部分畫布圖案
//context.clearRect(起點x,起點y,畫布寬,畫布高);若寬高和整個畫布大小一樣即清除整個畫布
};
複製程式碼
- 繪製二次方貝塞爾曲線(quadraticCurveTo)
context.strokeStyle = "black"; //設定線條顏色
context.beginPath(); //開始繪製
context.moveTo(0,200); //定義開始點,從(0,200)開始繪製
//context.quadraticCurveTo(控制點x,控制點y,結束點x,結束點y),
//控制點為與其與開始座標和結束座標連線的兩直線的交點 context.quadratciCurveTo(150,100,300,200);
context.stroke(); //繪製線條
context.globalCompositeOperation = "source-over";
//globalCompositeOperation 屬性一般用於圖形組合,設定如何將一個源(新)影象繪製到目標(已有)的影象上。
//源影象 = 您打算放置到畫布上的繪圖。目標影象 = 您已經放置在畫布上的繪圖。
//源影象:↓(二次貝塞爾曲線是根據直線部分畫出來的)
context.strokeStyle = "red";
context.beginPath();
context.moveTo(150,100);
context.lineTo(0,200);
context.moveTo(150,100);
context.lineTo(300,200);
context.stroke();
複製程式碼
- 繪製三次方貝塞爾曲線(bezierCurveTo)
參考理解:https://blog.csdn.net/cdnight/article/details/48468653
context.strokeStyle = "black";
context.beginPath(); //開始繪製
context.moveTo(0,200); //從(0,200)開始繪製
context.bezierCurveTo(25,50,75,50,300,200);
//context.bezierCurveTo(控制點1座標x,控制點1座標y,控制點2座標x,控制點2座標2,終點座標x,終點座標y)
context.bezierCurveTo(25,50,75,50,300,200);
context.stroke();
context.globalCompositeOperation = "source-over";
context.strokeStyle = "red";
context.beginPath();
//控制點1到開始點的直線
context.moveTo(25,50);
context.lineTo(0,200);
//控制點1到控制點2(三次貝塞爾曲線就是根據這條線畫出來的)
context.moveTo(25,50);
context.lineTo(75,50);
//控制點2到結束點直線
context.moveTo(75,50);
context.lineTo(300,200);
context.stroke();
複製程式碼
-
畫布的影象可以按照當前狀態以堆stack的方式儲存下來和按照上一次狀態恢復
A. save::用來儲存Canvas的狀態。save之後,可以呼叫Canvas的平移、放縮、旋轉、錯切、裁剪等操作.
B. restore:用來恢復Canvas之前儲存的狀態。防止save後對Canvas執行的操作對後續的繪製有影響.
注意:save表示儲存save函式之前的狀態,restore表示獲取save儲存的狀態例子:
//矩形一,填充色為橙色,邊框為紅色
context.fillStyle = "orange";
context.strokeStyle = "red";
context.fillRect(20,20,100,100);
context.strokeRect(20,20,100,100);
context.fill();
context.stroke();
//保持當前canvas狀態
context.save();
//繪製矩形二,填充色為黃色,邊框色為粉紅色
context.fillStyle="yellow";
context.strokeStyle="pink";
context.fillRect(150,20,100,100);
context.strokeRect(150,20,100,100);
context.fill();
context.stroke();
//恢復上一個矩形的狀態來進行繪畫
// context.restore();
context.fillRect(20,150,100,100);
context.strokeRect(20,150,100,100);
複製程式碼
無context.restore()時的畫面↓:儲存的是最後一次繪畫樣式
有context.restore()時的畫面↓:儲存的是context.save()的繪畫樣式
8. 移動座標空間,繪製漸變傘效果
畫布預設左上角為座標原點,向右為x軸正向,向下為y軸正向。座標空間的單位為畫素,在繪製影象時,可以使用translate來移動座標空間,使座標空間原點移動到指定位置。
例子:
var canvasMethod = {
drawTop:function(context,fillColor){
context.fillStyle = fillColor;
context.strokeStyle = fillColor;
context.beginPath();
//從座標0,0開始,畫一個半徑為30畫素的正半上方圓
context.arc(0,0,30,0,Math.PI,true);
context.closePath();
context.fill();
context.save();//儲存畫布當前狀態,移動位置,fillStyle,strokeStyle為fillColor
},
drawStick:function(context){
context.fillRect(-1.5,0,1,40);//繪製一個矩形,但這個矩形其實是向左偏移1.5畫素,寬為1高為40的一條直線,根據save的樣式進行填充
context.beginPath();
context.strokeStyle = "blue";
context.arc(-5,40,4,Math.PI,Math.PI*2,true);//圓心為(-5,40),半徑為4,順從從PI到2PI的方向,畫的下半圓,即終點在(-1,40)
context.restore();//採用save中的畫布樣式,即fillStyle,strokeStyle為fillColor
context.stroke();//根據save的樣式進行描邊
},
printUmbrella:function(){
var context = document.getElementById("canvas1").getContext("2d");
context.translate(80,80);//第一次移動座標原點到(80,80)
//繪製十把傘
for (var i = 0; i < 10; i++) {
context.save();//儲存畫布上一次狀態,移動位置,fillStyle,strokeStyle預設為黑
context.translate(60*i,0);//不斷改變座標原點,每次向右移60畫素(圓的直徑)
this.drawTop(context,"rgb("+(30*i)+","+(255-30*i)+",255)");//繪製半圓並改變填充色彩
this.drawStick(context);//繪製雨傘柄
context.restore();//採用畫布save的設定,移動位置,fillStyle,strokeStyle預設為黑
}
}
};
window.onload = function(){
canvasMethod.printUmbrella();
}
複製程式碼
9. 旋轉座標空間
利用rotate()方法指定一個角度,改變了畫布座標和Web瀏覽器中的Canvas元素的畫素之間的對映,使得任意後續繪圖在畫布中都顯示為旋轉的。但它並沒有旋轉Canvas元素本身。
只有一個引數,為旋轉的角度。
接著上一個雨傘例子,改變canvasMethod.printUmbrella()方法。
printUmbrella:function(){
var context = document.getElementById("canvas1").getContext("2d");
context.translate(150,150);//第一次移動座標原點到(150,150)
//繪製8把傘
for (var i = 0; i < 8; i++) {
context.save();//儲存畫布上一次的移動狀態
context.rotate(Math.PI*0.25*i); //2PI/8=0.25PI,每次旋轉0.25PI
context.translate(0,-100);//不斷改變座標原點,每次向上移100畫素
this.drawTop(context,"rgb("+(30*i)+","+(255-30*i)+",255)");//繪製半圓並改變填充色彩
this.drawStick(context);//繪製雨傘柄
context.restore();//採用畫布save的設定
}
}
複製程式碼
10. 縮放圖形
畫布通過scale()去改變canvas上下文物件(context)中橫縱方向的畫素數目來改變圖形的大小。
接收兩個引數分別是x軸方向縮放倍數和y軸方向縮放倍數,都必須為正數,若要比原來大則>1,比原來小則<1。
例如,傳遞一個值 2.0 和 0.5 將會導致繪圖路徑寬度變為原來的兩倍,而高度變為原來的 1/2。
例子:
function scaleCircle(context){
context.translate(250,20);
for (var i = 0; i < 80; i++) {
context.save(); //儲存上一次畫布的設定
context.translate(30,30);//每次迭代新的原點都移動到上一次原座標的(30,30)
context.scale(0.95,0.95);//每次迭代橫縱因子都縮小到原來的0.9倍
context.rotate(Math.PI/12)//旋轉
context.beginPath();//開始進行繪製
// context.fillStyle = "red";
// context.globalAlpha="0.4";//設定顏色透明度
context.fillStyle= "rgba(155, 187, 89, 0.7)";
context.arc(0,0,50,0,Math.PI*2,true);//繪製圓
context.closePath();
context.fill();
}
}
window.onload = function(){
scaleCircle(context);
}
複製程式碼
11. 矩陣變換
引用了理解網站內容:http://jo2.org/html5-canvas-transform/
canvas上下文物件(context)每次產生一個影象都會建立一個對應的矩陣物件,可直接對canvas變形矩陣作修改,可通過矩陣變換,使圖形產生移動、旋轉、切片、映象反射的效果。
那麼問題來了:圖形都有矩陣,那一個圖形的預設矩陣是什麼樣子的? 答案是:(1,0,0,1,0,0).
①為什麼不全為0?其中:一個圖形在沒有縮放,旋轉,位移什麼的時候,他也會有一個屬性會是1,就是縮放!因為在沒有縮放的情況下,圖形的縮放其實是原大小的1倍.所以,這個預設矩陣裡面才會有兩個1.
所以引數位置1上的1,是表示x軸上的縮放,引數位置4上的1是表示y軸上的縮放!
即:縮放可以根據:context.transform(scaleX,0,0,scaleY,0,0);來設定效果。
舉一反三:
②根據圖形預設矩陣,知矩陣中的最後兩位引數就是表示位移距離的數字(在沒有位移的情況下為0)。
即:移動可以根據:context.transform(scaleX,0,0,scaleY,transX,transY);來設定效果。
③那麼剩下的兩個數字(引數位置2,引數位置3)是不是表示旋轉呢?
不是,他們是表示斜切。什麼是斜切?把一個矩形的任一條邊用力一拉,變成平行四邊形,這就是斜切。
例子:
未進行斜切之前
ctx.arc(200,50,50,0,Math.PI*2)
.fillRect(200,100,50,50)
.stroke()
複製程式碼
斜切之後
ctx.transform(1,Math.tan(Math.PI/180*30),0,1,0,0)//矩形X軸產生了斜切效果
.arc(200,50,w/2,0,Math.PI*2)
.fillRect(200,100,50,50)
.stroke()
複製程式碼
程式碼中我們可以看到使用了一個tan函式,如果要用斜切,比如想斜切30度,那麼就必須用tan把30度包起來,x/y軸都是如此.
可以理解為圖形矩陣為ctx.transform(scaleX,skewX,skewY,scaleY,transX,transY);
新座標x' = (scaleX)x + (skewY)y + transX
新座標y' = (skewX)x + (scaleY)y + transY
④那怎麼用transform實現圖形轉換呢?
旋轉的效果要斜切配合縮放實現的。
比如,其他的都不變,只把圖形旋轉30度,程式碼:
var deg = Math.PI/180;
ctx.transform(Math.cos(30*deg),Math.sin(30*deg),-Math.sin(30*deg),Math.cos(30*deg),0,0)
.arc(200,50,50,0,Math.PI*2)
.fillRect(200,100,50,50)
.stroke()
複製程式碼
其中:
cos(30*deg),
sin(30*deg),
-sin(30*deg),
cos(30*deg)
複製程式碼
在使用transform方法實現旋轉時,旋轉N度時,N*deg不變,只要記住對應位置的對應三角函式cos,sin,-sin,cos就行。
原博主傳授的記憶方法:CS-SC=初三-上床,不要忘記負號.
注意:canvas也提供setTransform方法直接把矩陣設為你傳給他的值,會清空前面所有的transform造成的效果。
一個簡單的應用例子:
context.translate(200,20);
for (var i = 0; i < 80; i++) {
context.save();
context.transform(0.95,0,0,0.95,30,30); //縮至0.95倍,移動至(30,30)
context.rotate(Math.PI/12);
context.beginPath();
context.fillStyle = "red";
context.globalAlpha="0.4";//設定顏色透明度
//其中可以利用globalAlpha()為設定透明度,也可以利用fillStyle=rgva()設定透明度
context.arc(0,0,50,0,Math.PI*2,true);
// context.closePath();
context.fill();
}
context.setTransform(1,0,0,1,10,10); //清空之前的transform樣式,設定新的圖形位置
context.fillStyle = "yellow";
context.fillRect(0,0,50,50);
context.fill();
複製程式碼
12. 圖形組合
預設情況下,兩個圖形有重疊部分時,另外一個圖形會將另一個圖形覆蓋掉。
可以通過globalCompositeOperation屬性設定。
懶得敲之屬性展示系列:
-
裁切路徑
使用clip(),:一旦剪下了某個區域,則所有之後的繪圖都會被限制在被剪下的區域內(不能訪問畫布上的其他區域).
或者可以理解為,在使用clip()之後,只看到clip之前資訊,而clip之後的只能顯示在clip所選定的區域中的圖形部分,而其他會被隱藏起來。
參考理解網址:https://www.w3cplus.com/canvas/clip.html -
應用不同的線型
利用lineWidth、lineGap、lineJoin、miterLimit設定不同線形樣式。
lineWidth:線粗細,預設為1
lineGap:線端點樣式,預設為butt,還有round,square可選
lineJoin:線段連線的樣式,預設為round(圓形),還有bevel(斜角), miter(垂直矩形)可選
miterLimit:線段相交交叉點的粗細,越大lineJoin所選的樣式越明顯 -
繪製線性漸變
一般用到createLinearGradient()建立線性的漸變物件, 再用addColorStop對線性漸變物件分段新增不同顏色達到漸變效果.
例子:
// createLinearGradient(漸變起始點x,漸變起始點y,漸變結束點x,漸變結束點y)
var shadow = context.createLinearGradient(0,0,200,0); //也可以理解為漸變的方向的座標
shadow.addColorStop(0,'#ff0000');
shadow.addColorStop(1/7,'#ff9900');
shadow.addColorStop(2/7,'#ffff00');
shadow.addColorStop(3/7,'#00ff00');
shadow.addColorStop(4/7,'#00ffff');
shadow.addColorStop(5/7,'#0000ff');
shadow.addColorStop(6/7,'#ff00ff');
shadow.addColorStop(1,"#ff0000");
context.fillStyle =shadow;
context.strokeStyle = shadow;
context.fillRect(10,10,200,200);
複製程式碼
16. 繪製徑向漸變
利用createRadialGradient()建立徑向漸變物件,
再用addColorStop對徑向漸變物件發射狀新增不同顏色達到徑向漸變效果.
例子:
// createRadialGradient(漸變開始圓座標x0.漸變開始圓座標y0,開始圓半徑r0,漸變結束圓座標x1,漸變結束圓座標y1,結束圓半徑r1)
var shadow = context.createRadialGradient(85,85,3,100,100,100);
shadow.addColorStop(0,"white");
shadow.addColorStop(1,"orange");
context.fillStyle= shadow;
context.fillRect(10,10,200,200);
複製程式碼
17. 繪製圖案
A.context.createPattern(image,"repeat|repeat-x|repeat-y|no-repeat")
方法在指定的方向內重複指定的元素.
和設定圖片背景有點類似,先new Image()物件,再將img物件傳進createPattern(img,type),再將其賦予給fillStyle,即可達到填充圖片的效果。
例子:
var img = new Image(); //建立新的Image物件
img.src = "https://www.easyicon.net/api/resizeApi.php?id=1209623&size=128"; //設定影象路徑
img.onload = function(){ //載入影象
//建立圖案
var pattern = context.createPattern(img,'repeat');
context.fillStyle = pattern;
context.fillRect(0,0,380,190);
}
複製程式碼
B.drawImage()方法
①在畫布上定點陣圖像:context.drawImage(img,x,y);
②畫布上定點陣圖像,並規定影象的寬度和高度:context.drawImage(img,x,y,width,height);
③剪下影象,並在畫布上定位被剪下的部分:context.drawImage(img,開始剪下座標位置x,開始剪下座標位置y,被剪下影象寬度swidth,被剪下影象高度sheight,圖片位置x,圖片位置y,顯示圖片寬度width,顯示圖片高度height);
var img = new Image(); //建立新的Image物件
img.src = "https://www.easyicon.net/api/resizeApi.php?id=1209623&size=128"; //設定影象路徑
img.onload = function(){ //載入影象
//建立圖案
context.drawImage(img,0,0);
context.font = "nomal 100px SimHei";
context.shadowOffsetX = 3;
context.shadowOffsetY = 3;
context.shadowBlur = 3;
context.shadowColor = "pink";
context.createPattern(img,'repeat');
context.fillStyle = "white";
context.fillText("wowww",50,165);
}
複製程式碼
18. 建立陰影
例子:
//設定陰影
context.shadowOffsetX =3; //x軸方向的陰影偏移量,負數為向右偏移量
context.shadowOffsetY =3; //y軸方向的陰影偏移量,負數為向上偏移量
context.shadowBlur = 2;//陰影模糊強度
context.shadowColor = "pink";
//繪製矩形
context.fillStyle = "orange";
context.fillRect(20,20,300,80);
//繪製文字
context.font = "nomal 45px SimHei"; //設定文字字型樣式
context.fillStyle = "white"; //設定文字顏色,填充顏色
context.fillText("HTML5/CSS3" ,30,64)//設定文字內容和文字位置
複製程式碼
注意:在設定了陰影后,文字和矩形都會有陰影。
- 繪製填充/輪廓文字
A.context.fillText(文字內容,位置x,位置y[,最大寬度]),若文字內容長度超過最大寬度,文字會自動被壓縮
//繪製填充文字
context.font = "nomal 45px SimHei"; //設定文字字型樣式
context.fillStyle = "white"; //設定文字填充顏色
context.fillText("HTML5/CSS3" ,30,64)//設定文字內容和文字位置
複製程式碼
B.context.strokeText(文字內容,位置x,位置y[,最大寬度]),若文字內容長度超過最大寬度,文字會自動被壓縮
//繪製輪廓文字
context.font = "nomal 45px SimHei"; //設定文字字型樣式
context.strokeStyle = "white"; //設定文字輪廓顏色
var text = "HTML5/CSS3";
context.strokeText(text, ,30,64)//設定文字內容和文字位置
複製程式碼
其中:可以通過context.measureText(text)來獲取對應text的寬度.
小白第一次在掘金寫學習總結,從自己理解的角度記錄筆記,可能對某些方法理解存在錯誤,歡迎指出!持續學習更新中....