1. 程式人生 > >Canvas簡明教程(完整原始碼)

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>

寫得很亂,有待整理~~~