要建立一個canvas,其實只要在HTML中添加標籤:<canvas></canvas>
就好了。 如果考慮瀏覽器的兼容問題,只需在標籤中加上一行文字:javascript
<canvas>
您的瀏覽器不支持canvas
</canvas>
複製代碼
便可達到「 友好提示用戶 」的效果。html
若是要「畫東西」,也就是所謂的「操縱canvas元素」,則必要藉助於DOM事件:java
//獲取canvas
var canvas=document.querySelector('canvas標籤中的id/class名');
//獲取「上下文對象「
var ctx=canvas.getContext("2d");
複製代碼
其中「上下文對象」你能夠理解爲是「繪圖的環境(參數)」,而「2d」表明「要繪製2d(平面)圖形」 —— 一樣的,「3d」表示「繪製3d(立體)圖形」。canvas
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元素前要先dom
下面的一些demo就省去這兩行代碼了。。。函數
首先,你要畫好比一條線/一個圖的話,假如canvas如今是你手中的一杆畫筆,那你就要先「提筆」 —— 從哪開始畫:字體
ctx.moveTo(0,0); //移動到【畫布的】(0,0)座標處「落筆」
複製代碼
moveTo的兩個參數分別是:起始座標X、Y。 而後 如果畫直線,能夠調用lineTo - API:動畫
ctx.lineTo(100,100); //從畫布的(0,0)處「畫」到(100,100)處
複製代碼
而後其實能夠繼續lineTo()...ui
ctx.lineTo(100,200); //從畫布的(100,100)處「畫」到(100,200)處
複製代碼
這時,這些線條還只是在【內存】中,要其真正顯示到頁面上,則需調用stroke():
ctx.stroke();
複製代碼
ctx坑二: 若要再畫一條線,很多初學者可能會將以上「繪製」部分代碼再CV一遍,改變座標即「大功告成」,可是真是這樣的嗎? 經檢驗,第一條線要「深色」一些:這是由於整段代碼有兩個stroke() —— 即第一條線被「畫」了兩次。
其實若要畫多個圖形,只要先把moveTo、lineTo...所有完成,再調用一次 ctx.stroke();
便可。 但這樣一來又有一個問題:如果就想讓兩條線顏色不同怎麼辦? canvas API提供了下面的函數:
ctx.beginPath(); //開啓一條「新的」內存路徑
複製代碼
只要把這個函數加到「第二條繪製線」的moveTo函數前便可。
上面是畫線,那麼諸如圓、長方形...這些圖形怎麼畫?
圓形:ctx.arc(參數1,參2,參3,起始弧度,終止弧度,順時針/逆時針畫);
ctx.arc(300,300,50,0,2*Math.PI,true);
ctx.stroke();
複製代碼
矩形:ctx.strokeRect(左上角X,左上角Y,寬,高);
(由於是strokeRect這種stroke前綴的函數其實都是通過stroke()封裝過的,因此能夠直接顯示在屏幕上)
其實,矩形還有兩種畫法:
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);
複製代碼
上面的圖形畫着是挺爽的,就是顏色未免太單一了一些: 咱們能夠經過 ctx.fill()
填充函數填充整個圖形(內部)爲「黑色」(默認顏色)(視覺上看「自動閉合了路徑」)emmmmmmm,這樣所有都變成黑色了,不過我能夠在前面用 ctx.fillStyle="顏色值"
來改變整個圖形的顏色。
如果要只改變圖形邊框的顏色呢?其實上面說的一個函數自己就有「描邊」的功能:ctx.stroke()
。 你固然能夠理解爲「只有爲圖形邊框添加了顏色,才能顯示出來」,毫無疑問,它默認也是黑色的。不過咱們也能夠用API:ctx.strokeStyle="顏色值"
來改變圖形邊框的顏色。 咱們還能夠經過 ctx.lineWidth=數字值;
來改變邊框的寬度。
canvas中容許「邊框設置」和「填充設置」同時出現。
如上面「畫線」所說:
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()函數以前的環境)的「包裹」中。
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做爲一個「特殊的結構」,其圖片的展現方式確定也不一樣尋常:
//加載圖片對象
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中【背景圖片】的展現也很相似:
ctx.shadowOffsetX=數字值;
(數字值相對於圖形)ctx.shadowOffsetY=數字值;
(數字值相對與圖形)ctx.shadowColor='顏色值如:rgba(0,0,0,0.2)';
ctx.shadowBlur=數字值;
陰影會做用於其下全部設置的canvas上(文本、圖形、圖片...)
這個在大加載量、頻繁JS動畫 and DOM重繪量巨大的場景下應用極廣。它基於這樣的原理:把涉及大量DOM重繪、頻繁加載的元素(好比小球運動場景下的背景格的樣式改變)單獨拿出來放在某位置地方(display:none;
)本身加載,在觸發操做後,經過:
真實canvas元素上下文對象.drawImage(離屏canvas元素, 起始位置X, 起始位置Y, 真實canvas元素寬, 真實canvas元素高,起始位置X, 起始位置Y, 離屏canvas元素寬,離屏canvas元素高);
複製代碼
將元素的「樣子」刻畫到主要顯示的canvas上!
要記得「適當地」擦乾畫布:
canvas元素上下文對象.clearRect()
代碼較多,已打包到百度網盤,可直接免費下載:
連接 | 提取碼 |
---|---|
pan.baidu.com/s/1EIJp0MNA… | xqwk |
本文首發於@csdn:yunxiaomeng.blog.csdn.net/article/det…