要創建一個canvas,其實只要在HTML中添加標籤:<canvas></canvas>
就行了。
若是考慮瀏覽器的兼容問題,只需在標籤中加上一行文字:
<canvas>
您的瀏覽器不支持canvas
</canvas>
即可達到「 友好提示用戶 」的效果。
如果要“畫東西”,也就是所謂的“操縱canvas元素”,則必要藉助於DOM事件:
//獲取canvas
var canvas=document.querySelector('canvas標籤中的id/class名');
//獲取“上下文對象“
var ctx=canvas.getContext("2d");
其中“上下文對象”你可以理解爲是“繪圖的環境(參數)”,而“2d”代表“要繪製2d(平面)圖形” —— 同樣的,“3d”表示“繪製3d(立體)圖形”。
canvas坑一:
若要改變canvas“畫布”的大小,最好在canvas標籤的style屬性中或在JS中動態進行。若通過class/id-style中修改(執行),會造成“整體縮放”——包括後面說到的lineTo線條也是這樣。
//style
.canvas{
border: 1px solid red;
width: 200px;
height: 200px;
}
//html
<canvas class="canvas">
您的瀏覽器不支持canvas
</canvas>
//JS
var canvas=document.querySelector('.canvas');
var ctx=canvas.getContext("2d");
console.log(canvas.width,canvas.height); //canvas中可以直接操作canvas所用到屬性的各個CSS,這個後面還會提到
//下面三行先不必管
ctx.moveTo(0,0);
ctx.lineTo(200,200);
ctx.stroke()
JS操控canvas
上面說了,通過JS操作canvas元素前要先
- 得到元素
- 獲取環境(參數)
下面的一些demo就省去這兩行代碼了。。。
首先,你要畫比如一條線/一個圖的話,假如canvas現在是你手中的一杆畫筆,那你就要先“提筆” —— 從哪開始畫:
ctx.moveTo(0,0); //移動到【畫布的】(0,0)座標處“落筆”
moveTo的兩個參數分別是:起始座標X、Y。
然後
若是畫直線,可以調用lineTo - API:
ctx.lineTo(100,100); //從畫布的(0,0)處“畫”到(100,100)處
然後其實可以繼續lineTo()…
ctx.lineTo(100,200); //從畫布的(100,100)處“畫”到(100,200)處
這時,這些線條還只是在【內存】中,要其真正顯示到頁面上,則需調用stroke():
ctx.stroke();
ctx坑二:
若要再畫一條線,不少初學者可能會將以上“繪製”部分代碼再CV一遍,改變座標即“大功告成”,但是真是這樣的嗎?
經檢驗,第一條線要“深色”一些:這是因爲整段代碼有兩個stroke() —— 即第一條線被“畫”了兩次。
其實若要畫多個圖形,只要先把moveTo、lineTo…全部完成,再調用一次 ctx.stroke();
即可。
但這樣一來又有一個問題:若是就想讓兩條線顏色不一樣怎麼辦?
canvas API提供了下面的函數:
ctx.beginPath(); //開啓一條“新的”內存路徑
只要把這個函數加到“第二條繪製線”的moveTo函數前即可。
canvas畫圖形
上面是畫線,那麼諸如圓、長方形…這些圖形怎麼畫?
圓形:ctx.arc(參數1,參2,參3,起始弧度,終止弧度,順時針/逆時針畫);
- 參1:圓心座標X
- 參2:圓心座標Y
- 參3:半徑r
- 最後一個參數:true代表“逆時針”,false爲“順時針”
ctx.arc(300,300,50,0,2*Math.PI,true);
ctx.stroke();
矩形:ctx.strokeRect(左上角X,左上角Y,寬,高);
(因爲是strokeRect這種stroke前綴的函數其實都是經過stroke()封裝過的,所以可以直接顯示在屏幕上)
其實,矩形還有兩種畫法:
- 通過lineTo畫四條線,最後一條的終點座標和第一條的起點座標相同
- 通過lineTo畫三條線,最後通過“閉合函數”:
ctx.closePath()
將圖形路徑閉合
曾經看到好多“圖片+JS雪花掉落效果”,其實這個用canvas也可以實現:
var circles = [];
setInterval(function() {
// 擦出畫布
animCtx.clearRect(0, 0, animCtx.canvas.width, animCtx.canvas.height); //animCtx是canvas元素上下文對象
// 繪製下落的圓形
for(var i=0; i<=10; i++) {
if(!circles[i]) { //保證每片“雪花”垂直下落
circles[i] = {};
circles[i].radius = Math.floor(Math.random() * 5) + 1;
circles[i].y = - circles[i].radius - Math.floor(Math.random() * 10);
circles[i].x = i * 60 + Math.floor(Math.random() * 10) - 5;
circles[i].vy = Math.floor(Math.random() * 5) + 1;
}
animCtx.beginPath();
animCtx.arc(circles[i].x, circles[i].y, circles[i].radius, 0, Math.PI * 2);
animCtx.fillStyle = "rgba(255, 255, 255, 0.5)";
animCtx.fill();
circles[i].y = circles[i].y + circles[i].vy;
if(circles[i].y > animCtx.canvas.height + circles[i].radius * 2) {
circles[i] = undefined;
}
}
}, 100);
JS填充canvas與canvas描邊
上面的圖形畫着是挺爽的,就是顏色未免太單一了一些:
我們可以通過 ctx.fill()
填充函數填充整個圖形(內部)爲“黑色”(默認顏色)(視覺上看“自動閉合了路徑”)emmmmmmm,這樣全部都變成黑色了,不過我可以在前面用 ctx.fillStyle="顏色值"
來改變整個圖形的顏色。
若是要只改變圖形邊框的顏色呢?其實上面說的一個函數本身就有“描邊”的功能:ctx.stroke()
。
你當然可以理解爲“只有爲圖形邊框添加了顏色,才能顯示出來”,毫無疑問,它默認也是黑色的。不過我們也可以用API:ctx.strokeStyle="顏色值"
來改變圖形邊框的顏色。
我們還可以通過 ctx.lineWidth=數字值;
來改變邊框的寬度。
canvas中允許“邊框設置”和“填充設置”同時出現。
JS圖形變換(平移、旋轉、縮放)
如上面“畫線”所說:
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.stroke();
平移:ctx.translate(X方向,Y方向);
大家可以試下分別將translate函數放在moveTo前、lineTo前、最後,分別有什麼效果!
旋轉:ctx.rotate(旋轉角度);
—— 以弧度爲單位:
//旋轉45°
ctx.rotate(Math.PI / 4);
縮放:ctx.scale(X軸縮放,Y軸縮放);
//X軸不縮放,Y軸變爲原來的1/2
ctx.scale(1,0.5);
圖形變換的效果也會“自上而下疊加”!
如果覺得疊加效果並不是想要的,可以將某個變換片段代碼放到 ctx.save()
【保存環境函數】和 ctx.restore()
【恢復環境函數】(恢復到save()函數之前的環境)的“包裹”中。
canvas文字
var str="hello world";
我們怎麼把展示到canvas畫布中呢?
ctx.fillText(str,0,100); //參數:文字,X座標,Y座標
//或
ctx.strokeText(str,0,200); //若有顏色,則上面的爲填充,這裏爲描邊(字體呈鏤空效果)
填充:
能不能改變他的樣式?
(開頭說了一句“canvas裏能直接改變元素CSS樣式值”不知道大家還記得不記得)
ctx.font="50px sans-serif"; //改變字體大小
並且加上strokeText函數:
也可以改變文字的位置,如:
ctx.textAlign="center"; //文字居中(水平)
ctx.textBaseline="middle"; //文字垂直居中
既然能控制大小和位置,肯定也能獲取一些自身信息:
let width=ctx.measureText(str).width; //獲取文本寬度
這樣,我們就能做一些有意義的事,比如文本X/Y座標是多少時設置Align才能讓水平居中、比如根據一個元素的width(文字字數)控制另一個元素的位置。。。這些都在末尾demo中有用到。
很遺憾的是,canvas並不支持獲取文本的“高度”
在canvas中展示圖片
canvas作爲一個“特殊的結構”,其圖片的展示方式肯定也不同尋常:
//加載圖片對象
let img=new Image();
//設置src屬性
img.src="xxx.xx";
//展示
ctx.drawImage(img,0,0); //ctx.drawImage(img對象,左上角X座標,左上角Y座標);
然後我們“自信滿滿地”打開圖片,發現…沒有東西!!!
這是因爲Image()的加載需要一定時間,而我們直接插入了src:切記!一定要在load中完成img的“展示”。(和H5的File()加載展示一樣的道理)
img.onload=function(){
ctx.drawImage(img,0,0);
}
這樣完成是完成了,但圖片樣式是固定的,不好看啊。
沒關係,我們有“第二種展示方法”,可以將其進行縮放:
ctx.drawImage(img對象,左上角X座標,左上角Y座標,寬,高);
然後我們又發現縮放後圖片中圖標是挺好看的,但文字太模糊了,難受的一批,於是我們想:怎麼把圖標單獨顯示出來呢?
沒關係,我們還有“第三種展示方法”:
ctx.drawImage(img對象,截取起點X座標,截取起點Y座標,截取終點X座標,截取終點Y座標,繪製位置X座標,繪製位置Y座標,寬,高);
其實“圖片”的展示還有一種方式 —— 圖形畫刷 ,它可以將圖片爲背景填充展示到canvas區域:
var pattern=ctx.createPattern(img對象,"模式");
ctx.fillStyle=pattern;
其中,“模式”和CSS中【背景圖片】的展示也很類似:
- no-repeat
- repeat
- repeat-x
- repeat-y
canvas陰影設置
- X軸偏移:
ctx.shadowOffsetX=數字值;
(數字值相對於圖形) - Y軸偏移:
ctx.shadowOffsetY=數字值;
(數字值相對與圖形) - 陰影顏色:
ctx.shadowColor='顏色值如:rgba(0,0,0,0.2)';
- 模糊半徑:
ctx.shadowBlur=數字值;
陰影會作用於其下所有設置的canvas上(文本、圖形、圖片…)
離屏canvas
這個在大加載量、頻繁JS動畫 and DOM重繪量巨大的場景下應用極廣。它基於這樣的原理:把涉及大量DOM重繪、頻繁加載的元素(比如小球運動場景下的背景格的樣式改變)單獨拿出來放在某位置地方(display:none;
)自己加載,在觸發操作後,通過:
真實canvas元素上下文對象.drawImage(離屏canvas元素, 起始位置X, 起始位置Y, 真實canvas元素寬, 真實canvas元素高,起始位置X, 起始位置Y, 離屏canvas元素寬,離屏canvas元素高);
將元素的“樣子”刻畫到主要顯示的canvas上!
要記得“適當地”擦乾畫布:
canvas元素上下文對象.clearRect()
canvas名片生成程序代碼
代碼較多,已打包到百度網盤,可直接免費下載:
鏈接 | 提取碼 |
---|---|
https://pan.baidu.com/s/1EIJp0MNAD4gvTsBRwkglLg | xqwk |