Canvas簡明教程(完整原始碼)
部落格停更大半年,趁著聖誕更新了個人主頁,順便推一篇很亂的文章上來哈哈哈哈哈哈哈!!!
By anxpp
Canvas簡明教程
<canvas> 是 HTML5 新增的元素,可用於通過使用 JavaScript 中的指令碼來繪製圖形。例如,它可以用於繪製圖形,製作照片,建立動畫,甚至可以進行實時視訊處理或渲染。
本例包含個人主頁全部原始碼。
瀏覽器相容:
元素 | chrome | IE | firefox | Safari |
---|---|---|---|---|
Canvas | 4.0+ | 9.0+ | 2.0+ | 3.1+ |
Canvas 能幹什麼
- 圖表
- 小遊戲
- 活動頁
- 特效
- 背景等
獲取 Canvas 物件
方法:
- canvas.getContext(contextType, contextAttributes);
通常我們在建立好一個 Canvas 標籤的時候,我們要做的第一步就是要先獲取到這個 Canvas 的上下文昌物件。
上下文型別(contextType):
- 2d(本小冊所有的示例都是 2d 的):代表一個二維渲染上下文
- webgl(或”experimental-webgl”):代表一個三維渲染上下文
- webgl2(或”experimental-webgl2”):代表一個三維渲染上下文;這種情況下只能在瀏覽器實現 WebGL 版本2 (OpenGL ES 3.0)。
繪製路徑
請結合原始碼檢視效果
方法列表
熟悉有些什麼方法,能做什麼即可
方法 | 描述 |
---|---|
fill() | 填充路徑 |
stroke() | 描邊 |
arc() | 建立圓弧 |
rect() | 建立矩形 |
fillRect() | 繪製矩形路徑區域 |
strokeRect() | 繪製矩形路徑描邊 |
clearRect() | 在給定的矩形內清除指定的畫素 |
arcTo() | 建立兩切線之間的弧/曲線 |
beginPath() | 起始一條路徑,或重置當前路徑 |
moveTo() | 把路徑移動到畫布中的指定點,不建立線條 |
lineTo() | 新增一個新點,然後在畫布中建立從該點到最後指定點的線條 |
closePath() | 建立從當前點回到起始點的路徑 |
clip() | 從原始畫布剪下任意形狀和尺寸的區域 |
quadraticCurveTo() | 建立二次方貝塞爾曲線 |
bezierCurveTo() | 建立三次方貝塞爾曲線 |
isPointInPath() | 如果指定的點位於當前路徑中,則返回 true,否則返回 false |
方法介紹
該部分可以跳過,當參考手冊即可。
arc() 方法:建立弧/曲線(用於建立圓或部分圓)
context.arc(x,y,r,sAngle,eAngle,counterclockwise);
- x:圓的中心的 x 座標。
- y:圓的中心的 y 座標。
- r:圓的半徑
- sAngle:起始角,以弧度計。(弧的圓形的三點鐘位置是 0 度)。
- eAngle:結束角,以弧度計。
- counterclockwise:可選。規定應該逆時針還是順時針繪圖。False = 順時針,true = 逆時針。
moveTo(x,y):把路徑移動到畫布中的指定點,不建立線條
lineTo(x,y):新增一個新點,然後在畫布中建立從該點到最後指定點的線條
樣式:
- lineCap | 設定或返回線條的結束端點樣式
- lineJoin | 設定或返回兩條線相交時,所建立的拐角型別
- lineWidth | 設定或返回當前的線條寬度
- miterLimit | 設定或返回最大斜接長度
fillRect(x,y,width,heighr):繪製一個實心矩形
strokeRect(x,y,width,height):繪製一個空心矩形
畫一個點
var canvas4 = document.getElementById("canvas4");
var context4 = canvas4.getContext("2d");
canvas4.width = 400;
canvas4.height = 400;
context4.beginPath();
context4.arc(100, 100, 1, 0, Math.PI * 2, true);
context4.closePath();
context4.fillStyle = 'rgb(255,255,255)';
context4.fill();
繪製弧/曲線
var canvas5 = document.getElementById("canvas5");
var context5 = canvas5.getContext("2d");
canvas5.width = 400;
canvas5.height = 400;
context5.beginPath();
context5.arc(100, 100, 50, 0, Math.PI * 0.5, false);
context5.strokeStyle = "white";
context5.stroke();
繪製線條
- 直線:
var canvas6 = document.getElementById("canvas6");
var context6 = canvas6.getContext("2d");
canvas6.width = 400;
canvas6.height = 400;
context6.beginPath();
context6.moveTo(50,50);
context6.lineTo(100,100);
context6.strokeStyle = '#fff';
context6.stroke();
- 折線:
var canvas7 = document.getElementById("canvas7");
var context7 = canvas7.getContext("2d");
canvas7.width = 400;
canvas7.height = 400;
context7.beginPath();
context7.lineTo(200, 200);
context7.lineTo(200, 100);
context7.lineTo(100, 50);
context7.strokeStyle = '#fff';
context7.stroke();
- 新增樣式
var canvas8 = document.getElementById("canvas8");
var context8 = canvas8.getContext("2d");
canvas8.width = 400;
canvas8.height = 400;
context8.beginPath();
context8.moveTo(10,10);
context8.lineTo(100,100);
context8.lineWidth = 10;
context8.lineCap = 'round';
context8.strokeStyle = '#fff';
context8.stroke()
繪製矩形
var canvas9 = document.getElementById("canvas9");
var context9 = canvas9.getContext("2d");
canvas9.width = 400;
canvas9.height = 400;
context9.beginPath();
context9.fillStyle = '#fff';
context9.fillRect(10, 10, 100, 100);
context9.strokeStyle = '#fff';
context9.strokeRect(130, 10, 100, 100);
顏色、樣式和陰影
- fillStyle | 設定或返回用於填充繪畫的顏色、漸變或模式
- strokeStyle | 設定或返回用於筆觸的顏色、漸變或模式
- shadowColor | 設定或返回用於陰影的顏色
- shadowBlur | 設定或返回用於陰影的模糊級別
- shadowOffsetX | 設定或返回陰影距形狀的水平距離
- shadowOffsetY | 設定或返回陰影距形狀的垂直距離
陰影
var canvas10 = document.getElementById("canvas10");
var context10 = canvas10.getContext("2d");
canvas10.width = 400;
canvas10.height = 400;
context10.beginPath();
context10.arc(100,100,50,0,2*Math.PI,false);
context10.fillStyle = '#fff';
context10.shadowBlur = 20;
context10.shadowColor = '#fff';
context10.fill()
漸變
- createLinearGradient() 建立線性漸變(用在畫布內容上)
- createPattern() 在指定的方向上重複指定的元素
- createRadialGradient() 建立放射狀/環形的漸變(用在畫布內容上)
- addColorStop() 規定漸變物件中的顏色和停止位置
context.createLinearGradient(x0,y0,x1,y1):
- x0:開始漸變的 x 座標
- y0:開始漸變的 y 座標
- x1:結束漸變的 x 座標
- y1:結束漸變的 y 座標
gradient.addColorStop(stop,color):
- stop:介於 0.0 與 1.0 之間的值,表示漸變中開始與結束之間的位置。
- color:在結束位置顯示的 CSS 顏色值
粉色到白色的由上向下的漸變:
var canvas11 = document.getElementById("canvas11");
var context11 = canvas11.getContext("2d");
canvas11.width = 400;
canvas11.height = 400;
var grd11 = context11.createLinearGradient(100,100,100,200);
grd11.addColorStop(0,'pink');
grd11.addColorStop(1,'white');
context11.fillStyle = grd11;
context11.fillRect(100,100,200,200);
彩虹漸變:
var canvas12 = document.getElementById("canvas12");
var context12 = canvas12.getContext("2d");
canvas12.width = 400;
canvas12.height = 400;
var grd12 = context12.createLinearGradient(0,0,0,400);
grd12.addColorStop(0,'rgb(255, 0, 0)');
grd12.addColorStop(0.2,'rgb(255, 165, 0)');
grd12.addColorStop(0.3,'rgb(255, 255, 0)');
grd12.addColorStop(0.5,'rgb(0, 255, 0)');
grd12.addColorStop(0.7,'rgb(0, 127, 255)');
grd12.addColorStop(0.9,'rgb(0, 0, 255)');
grd12.addColorStop(1,'rgb(139, 0, 255)');
context12.fillStyle = grd12;
context12.fillRect(0,0,400,400);
圖形轉換
- scale() 縮放當前繪圖至更大或更小
- rotate() 旋轉當前繪圖
- translate() 重新對映畫布上的 (0,0) 位置
- transform() 替換繪圖的當前轉換矩陣
- setTransform() 將當前轉換重置為單位矩陣。然後執行 transform()
縮放
var canvas13 = document.getElementById("canvas13");
var context13 = canvas13.getContext("2d");
canvas13.width = 400;
canvas13.height = 400;
context13.strokeStyle = 'white';
context13.strokeRect(5, 5, 50, 25);
context13.scale(2, 2);
context13.strokeRect(5, 5, 50, 25);
context13.scale(2, 2);
context13.strokeRect(5, 5, 50, 25);
設定 scale() 方法之後在設定的矩形,無論是線條的寬度還是座標的位置,都被放大了。
並且 scale() 的效果是可以疊加的,也就是說,我們在上面的例子中使用了兩次 scale(2,2)。
那麼,最後一個矩形相對於第一個矩形長和寬,以及座標的位置就放大了 4 倍。
旋轉
context.rotate(angle)
angle : 旋轉角度,以弧度計。
如需將角度轉換為弧度,請使用 degrees*Math.PI/180 公式進行計算。
舉例:如需旋轉 5 度,可規定下面的公式:5*Math.PI/180。
var canvas14 = document.getElementById("canvas14");
var context14 = canvas14.getContext("2d");
canvas14.width = 400;
canvas14.height = 400;
context14.fillStyle = 'white';
context14.rotate(20*Math.PI/180);
context14.fillRect(70,30,200,100);
在進行圖形變換的時候,需要畫布旋轉,然後再繪製圖形。
這樣的結果是使用的圖形變換的方法都是作用在畫布上的,既然對畫布進行了變換,那麼在接下來繪製的圖形都會變換。
比如對畫布使用了 rotate(20*Math.PI/180) 方法,就是將畫布旋轉了 20°,然後之後繪製的圖形都會旋轉 20°。
影象繪製
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
- img:規定要使用的影象、畫布或視訊。
- sx:可選。開始剪下的 x 座標位置。
- sy:可選。開始剪下的 y 座標位置。
- swidth:可選。被剪下影象的寬度。
- sheight:可選。被剪下影象的高度。
- x:在畫布上放置影象的 x 座標位置。
- y:在畫布上放置影象的 y 座標位置。
- width:可選。要使用的影象的寬度。(伸展或縮小影象)
- height:可選。要使用的影象的高度。(伸展或縮小影象)
document.getElementById("tulip").onload = function () {
var canvas15 = document.getElementById("canvas15");
var context15 = canvas15.getContext("2d");
context15.width = 400;
context15.height = 400;
var img = document.getElementById("tulip");
context15.drawImage(img, 90, 130, 90, 80, 20, 20, 90, 80);
}
隨機粒子
- 建立粒子類
function Round_item(index,x,y) {
this.index = index;
this.x = x;
this.y = y;
this.r = Math.random() * 2 + 1;
var alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
this.color = "rgba(255,255,255," + alpha + ")";
}
- 定義粒子
Round_item.prototype.draw = function () {
content.fillStyle = this.color;
content.shadowBlur = this.r * 2;
content.beginPath();
content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
content.closePath();
content.fill();
};
- 初始化粒子
function init() {
for(var i = 0; i < initRoundPopulation; i++ ){
round[i] = new Round_item(i,Math.random() * WIDTH,Math.random() * HEIGHT);
round[i].draw();
}
}
- 完整程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>隨機粒子</title>
<style>
html, body {
margin: 0;
overflow: hidden;
width: 100%;
height: 100%;
/*cursor: none;*/
background: black;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var ctx = document.getElementById('canvas'),
content = ctx.getContext('2d'),
round = [],
WIDTH,
HEIGHT,
initRoundPopulation = 80;
WIDTH = document.documentElement.clientWidth;
HEIGHT = document.documentElement.clientHeight;
ctx.width = WIDTH;
ctx.height = HEIGHT;
function Round_item(index, x, y) {
this.index = index;
this.x = x;
this.y = y;
this.r = Math.random() * 2 + 1;
var alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
this.color = "rgba(255,255,255," + alpha + ")";
}
Round_item.prototype.draw = function () {
content.fillStyle = this.color;
content.shadowBlur = this.r * 2;
content.beginPath();
content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
content.closePath();
content.fill();
};
function init() {
for (var i = 0; i < initRoundPopulation; i++) {
round[i] = new Round_item(i, Math.random() * WIDTH, Math.random() * HEIGHT);
round[i].draw();
}
}
init();
</script>
</body>
</html>
動起來
- 定義粒子的運動
Round_item.prototype.move = function () {
this.y -= 0.15;
if (this.y <= -10)
this.y = HEIGHT + 10;
this.draw();
};
- 新增定時器
function animate() {
content.clearRect(0, 0, WIDTH, HEIGHT);
for (var i in round)
round[i].move();
requestAnimationFrame(animate)
}
- 完整程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
overflow: hidden;
width: 100%;
height: 100%;
/*cursor: none;*/
background: black;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var ctx = document.getElementById('canvas'),
content = ctx.getContext('2d'),
round = [],
WIDTH,
HEIGHT,
initRoundPopulation = 200;
WIDTH = document.documentElement.clientWidth;
HEIGHT = document.documentElement.clientHeight;
ctx.width = WIDTH;
ctx.height = HEIGHT;
function Round_item(index, x, y) {
this.index = index;
this.x = x;
this.y = y;
this.r = Math.random() * 2 + 1;
var alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
this.color = "rgba(255,255,255," + alpha + ")";
}
Round_item.prototype.draw = function () {
content.fillStyle = this.color;
content.shadowBlur = this.r * 2;
content.beginPath();
content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
content.closePath();
content.fill();
};
function animate() {
content.clearRect(0, 0, WIDTH, HEIGHT);
for (var i in round)
round[i].move();
requestAnimationFrame(animate)
}
Round_item.prototype.move = function () {
this.y -= 0.15;
if (this.y <= -10)
this.y = HEIGHT + 10;
this.draw();
};
function init() {
for (var i = 0; i < initRoundPopulation; i++) {
round[i] = new Round_item(i, Math.random() * WIDTH, Math.random() * HEIGHT);
round[i].draw();
}
animate();
}
init();
</script>
</body>
</html>
滑鼠
主要是監聽滑鼠移動事件:
window.onmousemove = function (event) {/*...*/}
其他都差不多了,一分完整的示例程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>滑鼠互動</title>
<style>
html, body {
margin: 0;
overflow: hidden;
width: 100%;
height: 100%;
/*cursor: none;*/
background: black;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
WIDTH = canvas.width = document.documentElement.clientWidth,
HEIGHT = canvas.height = document.documentElement.clientHeight,
para = {
num: 100,
color: false, // 顏色 如果是false 則是隨機漸變顏色
r: 0.9,
o: 0.09, // 判斷圓消失的條件,數值越大,消失的越快
a: 1
},
color,
color2,
round_arr = [];
window.onmousemove = function (event) {
mouseX = event.clientX;
mouseY = event.clientY;
round_arr.push({
mouseX: mouseX,
mouseY: mouseY,
r: para.r,
o: 1
})
};
// 判斷引數中是否設定了 color,如果設定了 color,就使用該值、
// 如果引數中的 color 為 false,那麼就使用隨機的顏色
if (para.color) color2 = para.color;
else color = Math.random() * 360;
function animate() {
if (!para.color) {
color += .1;
color2 = 'hsl(' + color + ',100%,80%)';
}
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < round_arr.length; i++) {
ctx.fillStyle = color2;
ctx.beginPath();
ctx.arc(round_arr[i].mouseX, round_arr[i].mouseY, round_arr[i].r, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
round_arr[i].r += para.r;
round_arr[i].o -= para.o;
if (round_arr[i].o <= 0) {
round_arr.splice(i, 1);
i--;
}
}
window.requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>
寫得很亂,有待整理~~~