1. 程式人生 > >HTML Canvas基本概念

HTML Canvas基本概念

javascript canvas web

Canvas

Canvas元素是HTML5新家的元素,這個元素負責在頁面中設定一個區域,然後就可以通過Javascript動態地在這個區域中繪制圖形

基本用法

使用canvas元素時,必須先設置其width屬性和height屬性,指定繪圖區域的大小。出現在canvas標簽中的內容是後備信息,如果瀏覽器不支持canvas元素,就會顯示這些信息。

<canvas id="canvas" width="300" height="200">
您的瀏覽器不支持Canvas
</canvas>

要在這塊畫布上繪圖,就需要獲得其繪圖上下文,取得繪圖上下文對象的引用,需要調用getContext()

方法,這個方法接收一個參數,即上下文的名字,傳入2d,就可以獲得2D上下文對象,也可以傳入webgl獲得webgl上下文的對象。

var canvas = document.getElementById("canvas");
if (canvas.getContext) {
    var ctx = canvas.getContext(‘2d‘);
}
//在使用canvas元素之前,首先要檢測是否有getContext()方法,有些瀏覽器會將HTML規範之外的元素創建為默認的HTML元素對象,這種情況下,即使獲取了id為canvas的元素,也不一定是canvas元素,沒有getContext()方法。

使用toDataURL()方法,可以將canvas元素上繪制的圖像導出,這個方法接收一個參數,即圖像的MIME類型,而且適用於創建圖像的任何上下文。

var canvas = document.getElementById(‘canvas‘);
if (canvas.getContext) {
    //獲取圖像的數據URI
    var imgURL = canvas.toDataURL(‘img/png‘);

    //顯示圖像
    var image = document.createElement(‘img‘);
    image.src = imgURL;
    document.body.appendChild(image);
}

2D上下文

使用2D繪圖上下文提供的方法。可以繪制簡單的2D圖形,如矩形、弧線和路徑。2D上下文的坐標開始於canvas元素的左上角,坐標原點是(0,0),水平方向代表x軸,向右為正,豎直方向表示y軸,向下為正。

填充和描邊

填充就是用指定的樣式(顏色、漸變或圖像)填充圖形,這個操作可以使用strokeStyle屬性來指定樣式。
描邊就是在圖形的邊緣劃線,這個操作使用fillStyle屬性來指定樣式。
fillStylestrokeStyle屬性的值可以是字符串、漸變對象或模式對象,其默認值是#000000,如果使用表示顏色的字符串值,可以使用CSS中指定顏色值的任何形式,十六進制碼、rgb、rgba、hsl、hsla等。

ctx.strokeStyle = "red"; //指定描邊顏色
ctx.fillStyle = "#0000ff"; //指定填充顏色

繪制矩形

2D上下文對象可以直接繪制矩形,其方法有:

  • fillRect(x, y, width, height):繪制左上角坐標為(x,y), 寬為width,高為height的矩形,並按fillStyle指定的模式填充
  • strokeRect(x, y, width, height):繪制左上角坐標為(x, y), 寬為width,高為height的矩形,並按strokeStyle指定的模式描邊
  • clearRect(x, y, width, height):清除矩形區域,實際上是把一部分區域變得透明。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>繪制矩形</title>
</head>
<body>
    <canvas id="canvas" height="600" width="1200"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("canvas")
    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘)

        ctx.fillStyle = "#ff0000"
        ctx.strokeStyle = "#00ff00"
        ctx.fillRect(10,10,50,50)
        ctx.strokeRect(70,70,50,50)

        ctx.fillRect(200,200,300,300)
        ctx.fillStyle = "#0000ff"
        ctx.fillRect(300,300,300,300)
        ctx.clearRect(350,350,100,100)
    }
</script>
</html>

運行效果:
技術分享圖片
描邊線條的寬度可以使用lineWidth屬性來控制,其屬性值可以為任意的額整數,還可以使用lineCap屬性控制線條末端的形狀是平頭(butt)、圓頭(round)還是方頭(square),lineJoin屬性可以控制蕭條相交的方式是圓交(round)、斜交(bevel)還是斜接(miter)。

繪制路徑

canvas使用一種基於狀態的方式來繪圖,意思就是,你繪圖的結果取決於你當前設置的狀態,我們上面使用了strokeStylefillStyle規定了描邊和填充的顏色,當我們再次給這兩個屬性賦予了新的值之後,再繪制的圖形的填充顏色和描邊顏色就會跟著發生改變。在繪制路徑時,可以先設置好一段路徑的屬性,比如上面提的strokeStylefillStylelineWidth等,然後開始繪制路線,最後決定以填充方式或者描線方式繪制該路徑,然後在規定新的路徑的屬性。
要繪制路徑,首先要調用beginPath()方法,表示開始繪制新路徑,然後使用下面的方法繪制該路徑:

  • arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)為圓心繪制一條弧線,弧線的半徑為radius,其實角度(用弧度表示)分別為startAngle和endAngle,最後一個參數表示是否用按逆時針方向計算,為false時表示按順時針計算。
  • arcTo(x1, y1, x2, y2, radius):從上一點開始繪制一條弧線,到(x2, y2)為止,並且給指定的半徑radius穿過點(x1, y1)。
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):從上一點開始繪制一條曲線,到(x, y)為止,並且經過(c1x, c1y)和(c2x, c2y)兩點。
  • lineTo(x, y):從上一點繪制一條直線,到(x, y)為止。
  • moveTo(x, y):將當前的畫筆移動到(x, y),不繪制路徑。
  • quadraticCurveTo(cx, cy, x, y):從上一點開始繪制一條二次曲線,到(x, y)為止,並經過(cx, cy)。
  • rect(x, y, width, height):從(x, y)開始繪制一個矩形,寬高分別為width和height。

路徑繪制結束後,使用closePath()方法結束繪制路徑。然後用stroke()fill()方法繪制線或者填充,也可以用‘clip()‘方法創建一個剪切區域。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>繪制路徑</title>
</head>
<body>
    <canvas id="canvas" width="1200" height="600"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById(‘canvas‘)

    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘)

        ctx.strokeStyle = ‘red‘
        ctx.beginPath()
        ctx.arc(100, 100, 100, 0, Math.PI / 2,true)
        ctx.stroke()
        ctx.closePath()

        ctx.strokeStyle = ‘green‘
        ctx.beginPath()
        ctx.moveTo(100,200)
        ctx.arcTo(200,300,100,400,100)
        ctx.stroke()
        ctx.closePath()

        ctx.strokeStyle = "yellow"
        ctx.beginPath()
        ctx.bezierCurveTo(100,200,300,200,400,400)
        ctx.stroke()
        ctx.closePath()

        ctx.strokeStyle = "blue"
        ctx.beginPath()
        ctx.moveTo(500,200)
        ctx.quadraticCurveTo(100,300,600,600)
        ctx.stroke()
        ctx.closePath()

        ctx.strokeStyle = "orange"
        ctx.beginPath()
        ctx.rect(200,200,200,300)
        ctx.stroke()
        ctx.closePath()
    }
</script>
</html>

結果:
技術分享圖片
*在這註意,arc()方法中,x的正方向,即水平向右方向的角度為0,然後順時針方向增加,y正方向,即垂直向下方向為90度,水平左方向為180度,垂直向上方向為270度,再次到水平向右方向時,是360度,所以,想創建一個整圓,可以這麽寫:`ctx.arc(100,100,100,0,Math.PI 2,true)`**

關於closePath(),還有另一作用,如果調用了closePath()之後再執行stroke(),圖形將自動閉合,否則不會閉合。如下面的例子所示:

ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI / 2, true);
ctx.closePath()
ctx.stroke()

結果:
技術分享圖片

繪制文本

2D上下文也提供了繪制文本的方法,繪制文本主要有兩個方法:

  • fillText(str, x, y, ?width)
  • strokeText(str, x, y, ?width)

這兩個方法都有四個參數:要繪制的文本的字符串,x坐標,y坐標,可選的參數,最大像素寬度。這兩個方法都以下面三個屬性為基礎:

  • font:表示文本樣式、大小及字體,可以使用css中指定字體的格式來指定,如"10px Arial"
  • textAlign:表示文本的對齊方式,可能的值有"start","end","left","right"和"center",其中"start"和"left","end"和"right"的效果一樣,但是建議前者。
  • textBaseline:表示文本的基線,可能的值有"top",“hanging”,"middle","alphabetic","ideographic"和"bottom"

實際上,textAligntextBaseline分別決定了文本的水平對齊方式和豎直對齊方式。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>繪制文本</title>
</head>
<body>
    <canvas id="canvas" width="300" height="300"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById(‘canvas‘)

    if (canvas.getContext){
        var ctx = canvas.getContext(‘2d‘)

        ctx.beginPath()
        ctx.moveTo(100,0)
        ctx.lineTo(100,100)
        ctx.closePath()
        ctx.stroke()

        ctx.font = "20px Times New Roman"
        ctx.textAlign = "start"
        ctx.textBaseline = "middle"
        ctx.fillText("canvas",100,10)

        ctx.textAlign = "end"
        ctx.fillText("canvas",100,25)

        ctx.textAlign = "center"
        ctx.fillText("canvas",100,40)
    }
</script>
</html>

運行結果:
技術分享圖片

變換

通過上下文的變換,可以將處理後的圖像繪制到畫布上,創建繪制上下文時,會以默認值初始化變換矩陣,使用變換時,會使用不同的變換矩陣來做處理,產生不同的效果。
可以使用以下方法來修改變換矩陣:

  • rotate(angle):圍繞原點旋轉angle弧度
  • scale(scaleX, scaleY):縮放圖像,在x方向乘以scaleX,在y方向乘以scaleY
  • translate(x,y):將坐標原點移動到(x,y)
  • transform(m1_1,m1_2,m2_1,m2_2,dx,dy):直接修改變換矩陣,方式是乘以以下矩陣:\begin{bmatrix} m1_1 & m1_2 & dx\m2_1 & m2_2 & dy \ 0 & 0 & 1 \end{bmatrix}
  • setTranform(m1_1,m1_2,m2_1,m2_2,dx,dy):將變換矩陣重置為默認值,然後調用transform()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>變換</title>
</head>
<body>
    <canvas id="canvas" width="1200" height="600"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("canvas")

    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘)

        ctx.strokeStyle = "red"
        ctx.rotate(-Math.PI/6)
        ctx.beginPath()
        ctx.rect(200,400,200,100)
        ctx.stroke()
        ctx.closePath()

        ctx.strokeStyle = "blue"
        ctx.rotate(Math.PI/6)//將上面的30度恢復原狀
        ctx.scale(1,2)
        ctx.beginPath()
        ctx.rect(100,100,200,100)
        ctx.stroke()
        ctx.closePath()

        ctx.strokeStyle = "green"
        ctx.setTransform(1,0,2,1,0,0)//對-45度對稱
        ctx.beginPath()
        ctx.rect(100,100,100,100)
        ctx.stroke()
        ctx.closePath()
    }
</script>
</html>

運行結果:
技術分享圖片

繪制圖像

2D上下文對象提供了對圖像的支持,如果想在畫布上繪制一幅圖像,可以使用drawImage()方法,這個方法的參數根據需要,有幾種可能。

  1. 傳入一個<img>元素,以及繪制該圖像的起點的x和y坐標

    var image = document.images[0]
    ctx.drawImage(image,10,10)
  2. img元素,圖像起點x,y,目標圖像寬度和高度
    ctx.drawImage(image, 50, 10 20 30)

  3. 要繪制的圖像、源圖像的x坐標、源圖像的y坐標、源圖像的寬度、源圖像的高度、目標圖像的x坐標、目標圖像的y坐標、目標圖像的寬度、目標圖像的高度。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>繪制圖像</title>
<style type="text/css">
    img{display: block; padding: 5px;border: 1px solid black;margin-bottom: 15px;}
</style>
</head>
<body>
    <img src="cat.jpg">
    <canvas id="canvas" width="600" height="600"></canvas>
</body>
<script type="text/javascript">
    var img = document.images[0]
    var canvas = document.getElementById("canvas")

    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘)

        ctx.drawImage(img, 0, 0)
        ctx.drawImage(img, 300, 0, 120, 100)
        ctx.drawImage(img,40,40,150,150,450,0,160,80)
    }
</script>
</html>

運行結果:
技術分享圖片

陰影

2D上下文會根據以下幾個屬性的值,自動為形狀或路徑繪制出陰影。

  • shadowColor:用CSS顏色格式表示的陰影顏色,默認為黑色
  • shadowOffsetX:形狀或路徑x軸方向的陰影偏移量,默認為0
  • shadowOffsetY:形狀或路徑y軸方向的陰影偏移量,默認為0
  • shadowBlur:模糊的像素數,默認為0
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>陰影</title>
</head>
<body>
    <canvas id="canvas" width="1200" height="600"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("canvas")

    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘)

        ctx.shadowOffsetX = 5
        ctx.shadowOffsetY = 5
        ctx.shadowBlur    = 5
        ctx.shadowColor   = "rgba(0,0,0,0.5)"

        ctx.fillStyle = "#ff0000"
        ctx.fillRect(10,10,50,50)
    }
</script>
</html>

運行結果
技術分享圖片

漸變

漸變由CanvasGradient實例表示,可以通過2D上下文來創建和修改。
創建線性漸變可以使用createLinearGradient()方法,這個方法有四個參數:起點的x坐標、起點的y坐標、終點的x坐標、終點的y坐標。
創建了漸變對象之後,可以使用addColorStop()方法來指定色標,這個方法接收兩個參數:色標位置和CSS顏色值,色標位置是一個0(開始的顏色)-1(結束的顏色)之間的數字。
最後,將fillStyle或strokeStyle設置為這個對象,從而使用漸變色來繪制形狀或描邊。
創建徑向漸變時,可以使用createRadialGradient()方法,這個方法接收6個參數,對應著兩個圓的圓心即半徑。前三個參數指定的是起點圓的圓心坐標x,y和半徑,後三個參數指終點圓的圓心坐標x,y即半徑。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>漸變</title>
</head>
<body>
    <canvas id="canvas" width="1200" height="600"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("canvas")
    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘)
        var linearGardient = ctx.createLinearGradient(30,30,70,70)
        var radialGardient = ctx.createRadialGradient(155,155,10,150,150,30)
        linearGardient.addColorStop(0,"red")
        linearGardient.addColorStop(1,"yellow")
        radialGardient.addColorStop(0,"blue")
        radialGardient.addColorStop(1,"green")

        ctx.fillStyle = "#ff0000"
        ctx.fillRect(10,10,50,50)
        ctx.fillStyle = linearGardient
        ctx.fillRect(30,30,50,50)
        ctx.fillRect(50,50,50,50)
        ctx.fillStyle = "#0000ff"
        ctx.fillRect(110,110,50,50)
        ctx.fillStyle = radialGardient
        ctx.fillRect(130,130,50,50)

    }
</script>
</html>

運行結果:
技術分享圖片

模式

模式就是重復的圖像,可以用來填充或者描邊推行。
創建新模式:createPattern(),參數有兩個:一個img元素,一個表示如何重復圖像的字符串,其中,第二個參數的值與css的background-repeat屬性值相同,包括repeatrepeat-xrepeat-yno-repeat

var image = document.images[0],
    pattern = ctx.createPattern(image, "repeat")

ctx.fillStyle = pattern
ctx.fillRect(10,10,150,150)

使用圖像數據

2D上下文可以使用getImageData()取得原始圖像的數據,這個方法接收4個參數:要取得其數據的畫圖區域的x和y坐標,以及該區域像素的高度和寬度。
var imageData = context.getImageData(10,5,150,150)
其返回對象是ImageData的實例,每個ImageData對象都有三個屬性:width,height和data,data是一個數組,保存著圖像中每一個像素的數據,在data數組中,每一個像素用4個元素來保存,分別表示紅綠藍和透明度值。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>獲取圖像數據</title>
<style type="text/css">
    img{border:1px solid black; display: block;margin-bottom: 15px;}
</style>
</head>
<body>
    <img src="cat.jpg">
    <canvas id="canvas" width="1200" height="600"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("canvas")
    if (canvas.getContext) {
        var ctx = canvas.getContext(‘2d‘),
            image = document.images[0],
            imageData, data,
            i, len, average,
            red, green, blue, alpha

        //繪制原始圖像
        ctx.drawImage(image, 0, 0)

        //取得圖像數據
        imageData = ctx.getImageData(0,0,image.width,image.height)
        data = imageData.data

        for (i = 0, len = data.length; i < len; i += 4) {
            red = data[i]
            green = data[i + 1]
            blue = data[i + 2]
            alpha = data[i + 3]

            average = Math.floor((red + green + blue) / 3)
            data[i] = average
            data[i + 1] = average
            data[i + 2] = average
        }

        imageData.data = data
        ctx.putImageData(imageData,300,0)
    }
</script>
</html>

運行結果
技術分享圖片

合成

還有兩個會應用到2D上下文中所有繪制操作的屬性

  • globalAlpha:一個介於0-1的值,用於指定所有繪制的透明度,默認為0,如果所有後續操作都要基於相同的透明度,就可以先把globalAlpha設置為適當的值,然後繪制,最後再把它設置成默認值0
  • globalCompositionOpreation:表示後繪制的圖形怎樣與先繪制的圖形結合,這個屬性的值是字符串,可能的值如下:
    • source-over:默認值,後繪制的圖形位於先繪制的圖形上方
    • source-in:後繪制的圖形與先繪制的圖形重疊部分課件,兩者其他部分全部透明
    • source-out:後繪制的圖形與先繪制的圖形不重疊的部分課件,兩者其他部分完全透明
    • source-atop:後繪制的圖形與先繪制的圖形重復部分可見,先繪制圖形不受影響
    • destination-over:後繪制的圖形位於先繪制的圖形下方,只有之前透明像素下的部分才可見
    • destination-in:後繪制的圖形位於先繪制的圖形下方,兩者不重疊的部分完全透明
    • destination-out:後繪制的圖形擦除與先繪制的圖形的重疊部分
    • destionation-atop:後繪制的圖形位於先繪制的圖形下方,兩個不重疊的地方,先繪制的圖形會完全透明
    • lighter:後繪制的圖形與先繪制的圖形重疊部分的值相加,使該部分變亮
    • copy:後繪制的圖形完全替代與之重疊的先繪制圖形
    • xor:後繪制的圖形與先繪制的圖形重疊的部分執行“異或”操作

HTML Canvas基本概念