小白上學のcanvas零基礎

<canvas> 元素

<canvas> 看起來和 <img> 元素很相像,惟一的不一樣就是它並無 src 和 alt 屬性。實際上,<canvas> 標籤只有兩個屬性—— width和height。當沒有設置寬度和高度的時候,canvas會初始化寬度爲300像素和高度爲150像素。該元素可使用CSS來定義大小,但在繪製時圖像會伸縮以適應它的框架尺寸:若是CSS的尺寸與初始畫布的比例不一致,它會出現扭曲
<canvas> 元素有一個作 getContext() 的方法,這個方法是用來得到渲染上下文和它的繪畫功能。
咱們這裏只作2d的繪畫功能。javascript

<html>
  <head>
    <title>Canvas tutorial</title>
    <style type="text/css">
      canvas { border: 1px solid black; }
    </style>
    <body onload="draw();">
    <canvas id="tutorial" width="150" height="150">您的瀏覽器不支持canvas</canvas>
  </body>
    <script type="text/javascript">
      function draw(){
        var canvas = document.getElementById('tutorial');
        if (canvas.getContext){
          var ctx = canvas.getContext('2d');
        }
      }
    </script>
  
  </head>
  
</html>

模板看起來會是這樣。如這裏所示,它最初是空白的。
clipboard.png
一個簡單例子
一開始,讓咱們來看個簡單的例子,咱們繪製了兩個有趣的長方形,其中的一個有着alpha透明度。咱們將在接下來的例子裏深刻探索一下這是如何工做的。css

<html>
 <head>
  <script type="application/javascript">
    function draw() {
      var canvas = document.getElementById("canvas");
      if (canvas.getContext) {
        var ctx = canvas.getContext("2d");

        ctx.fillStyle = "rgb(200,0,0)";
        ctx.fillRect (10, 10, 55, 50);

        ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
        ctx.fillRect (30, 30, 55, 50);
      }
    }
  </script>
 </head>
 <body onload="draw();">
   <canvas id="canvas" width="150" height="150"></canvas>
 </body>
</html>

效果
clipboard.pnghtml

柵格

在咱們開始畫圖以前,咱們須要瞭解一下畫布柵格(canvas grid)以及座標空間。上一頁中的HTML模板中有個寬150px, 高150px的canvas元素。如右圖所示,canvas元素默認被網格所覆蓋。一般來講網格中的一個單元至關於canvas元素中的一像素。柵格的起點爲左上角(座標爲(0,0))。全部元素的位置都相對於原點定位。因此圖中藍色方形左上角的座標爲距離左邊(Y軸)x像素,距離上邊(X軸)y像素(座標爲(x,y))。在課程的最後咱們會平移原點到不一樣的座標上,旋轉網格以及縮放。如今咱們仍是使用原來的設置。java

clipboard.png
HTML中的元素canvas只支持一種原生的圖形繪製:矩形。全部其餘的圖形的繪製都至少須要生成一條路徑。不過,咱們擁有衆多路徑生成的方法讓複雜圖形的繪製成爲了可能。canvas

首先,咱們回到矩形的繪製中。canvas提供了三種方法繪製矩形:
fillRect(x, y, width, height)
繪製一個填充的矩形
strokeRect(x, y, width, height)
繪製一個矩形的邊框
clearRect(x, y, width, height)
清除指定矩形區域,讓清除部分徹底透明,例如一個鏤空的矩形。
上面提供的方法之中每個都包含了相同的參數。x與y指定了在canvas畫布上所繪製的矩形的左上角(相對於原點)的座標。width和height設置矩形的尺寸。瀏覽器

下面的draw() 函數是前面中取得的,如今就來使用上面的三個函數。app

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.fillRect(25,25,100,100);
    ctx.clearRect(45,45,60,60);
    ctx.strokeRect(50,50,50,50);
  }
}

效果
clipboard.png
fillRect()函數繪製了一個邊長爲100px的黑色正方形。clearRect()函數從正方形的中心開始擦除了一個6060px的正方形,接着strokeRect()在清除區域內生成一個5050的正方形邊框。
繪製路徑
圖形的基本元素是路徑。路徑是經過不一樣顏色和寬度的線段或曲線相連造成的不一樣形狀的點的集合。一個路徑,甚至一個子路徑,都是閉合的。使用路徑繪製圖形須要一些額外的步驟。框架

首先,你須要建立路徑起始點。
而後你使用畫圖命令去畫出路徑。
以後你把路徑封閉。
一旦路徑生成,你就能經過描邊或填充路徑區域來渲染圖形。
如下是所要用到的函數:
beginPath()
新建一條路徑,生成以後,圖形繪製命令被指向到路徑上生成路徑。
closePath()
閉合路徑以後圖形繪製命令又從新指向到上下文中。
stroke()
經過線條來繪製圖形輪廓。
fill()
經過填充路徑的內容區域生成實心的圖形。
生成路徑:
第一步叫作beginPath()。本質上,路徑是由不少子路徑構成,這些子路徑都是在一個列表中,全部的子路徑(線、弧形、等等)構成圖形。而每次這個方法調用以後,列表清空重置,而後咱們就能夠從新繪製新的圖形。
第二步就是調用函數指定繪製路徑,本文稍後咱們就能看到了。函數

第三,就是閉合路徑closePath(),不是必需的。這個方法會經過繪製一條從當前點到開始點的直線來閉合圖形。若是圖形是已經閉合了的,即當前點爲開始點,該函數什麼也不作。
繪製一個三角形spa

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.moveTo(75,50);
    ctx.lineTo(100,75);
    ctx.lineTo(100,25);
    ctx.fill();
  }
}

效果
clipboard.png
移動筆觸

一個很是有用的函數,而這個函數實際上並不能畫出任何東西,也是上面所描述的路徑列表的一部分,這個函數就是moveTo()。或者你能夠想象一下在紙上做業,一支鋼筆或者鉛筆的筆尖從一個點到另外一個點的移動過程。

moveTo(x, y)
將筆觸移動到指定的座標x以及y上。
當canvas初始化或者beginPath()調用後,你一般會使用moveTo()函數設置起點。咱們也可以使用moveTo()繪製一些不連續的路徑。看一下下面的笑臉例子。我將用到moveTo()方法(紅線處)的地方標記了。

你能夠嘗試一下,使用下邊的代碼片。只須要將其複製到以前的draw()函數便可。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.arc(75,75,50,0,Math.PI*2,true); // 繪製
    ctx.moveTo(110,75);
    ctx.arc(75,75,35,0,Math.PI,false);   // 口(順時針)
    ctx.moveTo(65,65);
    ctx.arc(60,65,5,0,Math.PI*2,true);  // 左眼
    ctx.moveTo(95,65);
    ctx.arc(90,65,5,0,Math.PI*2,true);  // 右眼
    ctx.stroke();
  }
}

效果

clipboard.png
arc()函數介紹:

clipboard.png
因爲canvas中全部於角有關的API,都須要以弧度(R)來指定該角的值。三角函數也都採用弧度制。因此須要記好如下公式:
180度=π弧度
1弧度=(π/180)×度
1度=(180/π)×弧度
π=3.14,因此45度等於(3.14/180)×45度得0.7853弧度

clipboard.png
若是你想看到連續的線,你能夠移除調用的moveTo()。

繪製直線,須要用到的方法lineTo()。

lineTo(x, y)
繪製一條從當前位置到指定x以及y位置的直線。
該方法有兩個參數:x以及y ,表明座標系中直線結束的點。開始點和以前的繪製路徑有關,以前路徑的結束點就是接下來的開始點,等等。。。開始點也能夠經過moveTo()函數改變。

下面的例子繪製兩個三角形,一個是填充的,另外一個是描邊的。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    // 填充三角形
    ctx.beginPath();
    ctx.moveTo(25,25);
    ctx.lineTo(105,25);
    ctx.lineTo(25,105);
    ctx.fill();

    // 描邊三角形
    ctx.beginPath();
    ctx.moveTo(125,125);
    ctx.lineTo(125,45);
    ctx.lineTo(45,125);
    ctx.closePath();
    ctx.stroke();
  }
}

這裏從調用beginPath()函數準備繪製一個新的形狀路徑開始。而後使用moveTo()函數移動到目標位置上。而後下面,兩條線段繪製後構成三角形的兩條邊。

clipboard.png
你會注意到填充與描邊三角形步驟有所不一樣。正如上面所提到的,由於路徑使用填充(filled)時,路徑自動閉合,使用描邊(stroked)則不會閉合路徑。若是沒有添加閉合路徑closePath()到描述三角形函數中,則只繪製了兩條線段,並非一個完整的三角形。

圓弧

繪製圓弧或者圓,咱們使用arc()方法。固然可使用arcTo(),不過這個的現實並非那麼的可靠,因此咱們這裏不做介紹。

arc(x, y, radius, startAngle, endAngle, anticlockwise)
畫一個以(x,y)爲圓心的以radius爲半徑的圓弧(圓),從startAngle開始到endAngle結束,按照anticlockwise給定的方向(默認爲順時針)來生成。
arcTo(x1, y1, x2, y2, radius)
根據給定的控制點和半徑畫一段圓弧,再以直線鏈接兩個控制點。
該方法有五個參數:x,y爲繪製圓弧所在圓上的圓心座標。radius爲半徑。startAngle以及endAngle參數用弧度定義了開始以及結束的弧度。這些都是以x軸爲基準。參數anticlockwise 爲一個布爾值。爲true時,是逆時針方向,不然順時針方向。
下面的例子比上面的要複雜一下,下面繪製了12個不一樣的角度以及填充的圓弧。

下面兩個for循環,生成圓弧的行列(x,y)座標。每一段圓弧的開始都調用beginPath()。代碼中,每一個圓弧的參數都是可變的,實際生活中,咱們並不須要這樣作。

x,y座標是可變的。半徑(radius)和開始角度(startAngle)都是固定的。結束角度(endAngle)在第一列開始時是180度(半圓)而後每列增長90度。最後一列造成一個完整的圓。

clockwise 語句做用於第1、三行是順時針的圓弧,anticlockwise做用於2、四行爲逆時針圓弧。if 語句讓1、二行描邊圓弧,下面兩行填充路徑。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    for(var i=0;i<4;i++){
      for(var j=0;j<3;j++){
        ctx.beginPath();
        var x              = 25+j*50;               // x 座標值
        var y              = 25+i*50;               // y 座標值
        var radius         = 20;                    // 圓弧半徑
        var startAngle     = 0;                     // 開始點
        var endAngle       = Math.PI+(Math.PI*j)/2; // 結束點
        var anticlockwise  = i%2==0 ? false : true; // 順時針或逆時針

        ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

        if (i>1){
          ctx.fill();
        } else {
          ctx.stroke();
        }
      }
    }
  }
}

效果

clipboard.png
貝塞爾(bezier)以及二次貝塞爾

下一個十分有用的路徑類型就是 貝塞爾曲線。二次以及三次貝塞爾曲線都十分有用,通常用來繪製複雜有規律的圖形。

quadraticCurveTo(cp1x, cp1y, x, y)
繪製二次貝塞爾曲線,x,y爲結束點,cp1x,cp1y爲控制點。
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
繪製三次貝塞爾曲線,x,y爲結束點,cp1x,cp1y爲控制點一,cp2x,cp2y爲控制點二。
下邊的圖可以很好的描述二者的關係,二次貝塞爾曲線有一個開始、結束點(藍色)以及一個控制點(紅色),而三次貝塞爾曲線使用兩個控制點。

參數x、y在這兩個方法中都是結束點座標。cp1x,cp1y爲座標中的第一個控制點,cp2x,cp2y爲座標中的第二個控制點。

使用二次以及三次貝塞爾曲線是有必定的難度的,由於不一樣於像Adobe Illustrators這樣的矢量軟件,咱們所繪製的曲線沒有直接的視覺反饋給咱們。這讓繪製複雜的圖形十分的困難。在下面的例子中,咱們會繪製一些簡單有規律的圖形,若是你有時間,以及更多的耐心不少複雜的圖形你均可以繪製出來。

clipboard.png能夠看我本身寫的一個實際項目例子,在個人文章裏有。今天就先寫到這了。後面再慢慢給你們寫,我也是剛剛學這個。不足之處多諒解。關注我哦^_^!

相關文章
相關標籤/搜索