HTML5 canvas基礎與「生成名片」應用程序

要創建一個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()

left

JS操控canvas

上面說了,通過JS操作canvas元素前要先

  1. 得到元素
  2. 獲取環境(參數)

下面的一些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);   //若有顏色,則上面的爲填充,這裏爲描邊(字體呈鏤空效果)

填充:
tc

能不能改變他的樣式?
(開頭說了一句“canvas裏能直接改變元素CSS樣式值”不知道大家還記得不記得)

ctx.font="50px sans-serif";   //改變字體大小

並且加上strokeText函數:
ys
也可以改變文字的位置,如:

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

canvas生成的圖形可以作爲圖片保存

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章