如何使用canvas進行2d繪圖


 canvas 的 2D context 可以繪制簡單的 2D 圖形。它的 2D context 坐標開始於 <canvas> 元素的左上角,原點坐標是(0,0)。所有的坐標值都基於這個原點,x 值越大表示越靠右,y 值越大表示越靠下。width 和 height 表示水平和垂直方向上可用的像素數。

1 填充和描邊

填充就是用指定的樣式填充圖形;而描邊就是給圖形的邊緣畫線。它們分別對應兩個屬性:fillStyle 和 strokeStyle。這兩個屬性的值可以是字符串、漸變對象或者模式對象。默認值都是 “#00000”。如果為它們指定表示顏色的字符串值,可以使用 CSS 中指定顏色值的任何格式(顏色名、十六進制碼、rgb、rgba、hsl 或 hsla):

var drawing = document.getElementById("drawing");

if (drawing.getContext) {//確定瀏覽器支持 canvas
    var context = drawing.getContext("2d");

    var context = drawing.getContext("2d");
    context.strokeStyle = "red";
    context.fillStyle = "#0000ff";
}

2 繪制矩形

矩形是唯一一種直接可以在 2D context 中繪制的圖形。它有 3 種方法:fillRect()、strokeRect() 和 clearRect()。它們都接收 4 個 參數:矩形的 x 坐標、y 坐標、矩形的寬度以及高度,這些參數的單位都是像素。

fillRect() 會為矩形填充指定的顏色,顏色是通過 fillStyle 屬性進行設置的:

<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        //繪制紅色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);

        //繪制半透明的藍色矩形
        context.fillStyle = "rgba(0,0,255,0.5)";
        context.fillRect(30, 30, 50, 50);
    }
</script>

因為第二個矩形是半透明的,所以你可以透過上面的藍色矩形看到下面的紅色矩形:

 

strokeRect() 會使用指定的顏色為矩形描邊,描邊的顏色是通過 strokeStyle 指定的:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        //繪制紅色描邊矩形
        context.strokeStyle = "#ff0000";
        context.strokeRect(10, 10, 50, 50);

        //繪制半透明的藍色描邊矩形
        context.strokeStyle = "rgba(0,0,255,0.5)";
        context.strokeRect(30, 30, 50, 50);
    }
</script>

 

注意: lineWidth 屬性控制着描邊線條的寬度,它可以是任意整數。lineCap 屬性可以控制線條末端的形狀(平頭【butt】、圓頭【round】或方頭【squre】)。lineJoin 控制線條相交的方式(圓交【round】、斜角【bevel】或斜接【miter】)。


clearRect() 可以清除畫布上的矩形區域。它是通過把某一矩形區域變透明來實現的。通過繪制形狀然后在清除指定區域后,會生成很有意思的效果:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        //繪制紅色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);

        //繪制半透明的藍色矩形
        context.fillStyle = "rgba(0,0,255,0.5)";
        context.fillRect(30, 30, 50, 50);

        //在兩個矩形重疊的地方清除一個小矩形
        context.clearRect(40,40,10,10);
    }
</script>

 

3 繪制路徑

使用路徑可以繪制出很復雜的形狀和線條。必須先調用 beginPath() 方法,然后再通過以下方法來繪制路徑:

方法 說明
arc(x, y, radius, startAngle, endAngle, counterclockwise) 以 (x,y) 為圓心繪制一條弧線,它的半徑是 radius。startAngle 是起始角度,endAngle 是結束角度,它們的單位都是弧度。counterclockwise 表示起始和結束角度是否按逆時針方向計算。
arcTo(x1, y1, x2, y2, radius) 從上一點開始繪制弧線,以給定的半徑(radius)穿過 (x1, y1),直到 (x2, y2) 為止。
bezierCurveTo(c1x, c1y, c2x, c2y, x, y) 從上一點開始繪制曲線,以 (c1x, c1y) 和 (c2x, c2y) 為控制點,開始繪制曲線。
lineTo(x, y) 從上一點開始繪制直線,到 (x, y) 為止。
moveTo(x, y) 將繪圖的游標移動到 (x, y) ,只是移動不畫線。
quadraticCurveTo(cx, cy, x, y) 從上一點開始繪制二次曲線,以 (cx, cy)作為控制點,到 (x, y) 為止。
rect(x, y, width, height) 從點(x, y) 開始繪制矩形,width 和 height 分別代表寬和高,它繪制的是矩形路徑,而不是我們之前說過的矩形形狀。

創建路徑后,有這些選擇:

  • 調用 closePath() 可以繪制一條連接到路徑起點的線條。
  • 調用 fill() 可以填充路徑(fillStyle 指定的值)。
  • 調用 stroke() 對路徑進行描邊(strokeStyle 指定的值)。
  • 調用 clip() 在路徑上創建一個剪貼區域。

現在我們繪制一個不帶數字的鍾:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        //開始路徑
        context.beginPath();

        //繪制外圓
        context.arc(100,100,99,0,2*Math.PI,false);

        //繪制內圓
        context.moveTo(194,100);//避免出現從外圓移動到內圓,造成的多余線條
        context.arc(100,100,94,0,2*Math.PI,false);

        //繪制分針
        context.moveTo(100,100);
        context.lineTo(100,15);

        //繪制時鍾
        context.moveTo(100,100);
        context.lineTo(35,100);

        //描邊路徑
        context.stroke();//實際畫出路徑

    }
</script>

路徑是一種主要的繪圖方式,因為它能為要繪制的圖形進行更多的控制。

isPointInPath() 接收 x 和 y 坐標作為參數,可以用來判斷某一點是否位於路徑上。

可以利用路徑的 API 繪制出非常復雜的圖形。

4 繪制文本

繪制文本 有 fillText() 和 strokeText() 這兩個方法,它們可以接收 4 個參數:要繪制的文本字符串、x 坐標、y 坐標和最大像素寬度(可選),它們都有以下這些屬性:

屬性 說明
font 文本樣式、大小以及字體(CSS 的字體格式)
textAlign 文本對齊方式,有這些值:start、end、left、right 和 center。建議使用 start(從左到右) 和 end(從右到左)。
textBaseline 文本的基線,有這些值:top、hanging、middle、alphabetic、ideographic 和 bottom。

 

這些屬性都有默認值。fillText() 使用 fillStyle 來繪制文本,strokeText() 使用 strokeStyle 來為文本描邊。fillText() 的頻率會更多,因為它模仿了在網頁中顯示的文本方式。現在我們在之前的鍾上繪制數字:

//繪制文本
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);

如果把 textAlign 設置為 start,表示 x 坐標是在文本左端的位置;如果設置為 end,則表示 x 坐標是在文本右端的位置:

/**
 * 繪制文本
 */
//正常
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);

//起點對齊
context.textAlign="start";
context.fillText("12",100,40);


//終點對齊
context.textAlign="end";
context.fillText("12",100,60);

meansureText() 可以確定文本的大小,它接受一個參數,即要繪制的文本,它會返回 TextMetrics 對象。這個對象有一個 width 屬性。

meansureText() 會根據 font、textAlign 和 textBaseline 的值來計算指定文本的合適大小:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d"),fontSize=50, i,len;

        //draw a white rectangle
        context.strokeWidth=1;
        context.strokeStyle="#000000";
        context.strokeRect(10,10,150,30);

        //default font setting
        context.font = fontSize + "px Arial";
        context.textBaseline="top";

        while (context.measureText("Hello world!").width > 140) {
            fontSize--;
            context.font = fontSize + "px Arial";
        }

        context.fillText("Hello world!", 10, 10);
        context.fillText("Font size is " + fontSize + "px", 10, 50);
    }
</script>

5 變換

通過變換,可以把變換后的圖像繪制到畫布上。創建繪制上下文時,會以默認值初始化變換矩陣。有這些方法:

方法 說明
rotate(angle) 圍繞原點旋轉圖像 angle 弧度。
scale(scaleX, scaleY) 縮放圖像,x 方向上乘以 scaleX,y 方向上乘以 scaleY。參數的默認值都是 1.0。
translate(x, y) 坐標原點(0,0)移動到(x,y)。
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) 將矩陣重置為默認狀態,然后再調用 transform()。
transform(m1_1, m1_2, m2_1, m2_2, dx, dy) 修改變換矩陣,即乘上底下這樣的矩陣:

 

現在我們把原點變換到表盤的中心,然后再繪制表針,這樣在同一方向上繪制線條就變成了一個簡單的數學問題咯(因為所有的的計算都是基於 (0,0)):

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        //開始路徑
        context.beginPath();

        //繪制外圓
        context.arc(100,100,99,0,2*Math.PI,false);

        //繪制內圓
        context.moveTo(194,100);//避免出現從外圓移動到內圓,造成的多余線條
        context.arc(100,100,94,0,2*Math.PI,false);

        //變換原點
        context.translate(100,100);

        //繪制分針
        context.moveTo(0,0);
        context.lineTo(0,-85);

        //繪制時鍾
        context.moveTo(0,0);
        context.lineTo(-65,0);

        //描邊路徑
        context.stroke();//實際畫出路徑

    }
</script>

還可以使用 rotate() 來旋轉時鍾的表針:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        //開始路徑
        context.beginPath();

        //繪制外圓
        context.arc(100,100,99,0,2*Math.PI,false);

        //繪制內圓
        context.moveTo(194,100);//避免出現從外圓移動到內圓,造成的多余線條
        context.arc(100,100,94,0,2*Math.PI,false);

        //變換原點
        context.translate(100,100);

        //旋轉表針
        context.rotate(1);

        //繪制分針
        context.moveTo(0,0);
        context.lineTo(0,-85);

        //繪制時鍾
        context.moveTo(0,0);
        context.lineTo(-65,0);

        //描邊路徑
        context.stroke();//實際畫出路徑

    }
</script>

 

有兩種方法可以跟蹤狀態變化。一個是 save() 方法,它會把當時的所有設置放入一個棧結構。如果想要回到之前的設置,可以調用另一個方法 restore() ,它會恢復之前的狀態(在棧結構中返回一級)。多次調用 save() 會把多個設置都保存到棧結構中,如果這時再連續調用 restore() 方法,則會一級一級地返回設置:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        context.fillStyle = "#ff0000";
        context.save();

        context.fillStyle = "#00ff00";
        context.translate(100, 100);
        context.save();

        context.fillStyle = "#0000ff";
        context.fillRect(0, 0, 100, 200);//從點(100,200)開始繪制藍色矩形

        context.restore();
        context.fillRect(10, 10, 100, 200);//從點(110,110)開始繪制綠色矩形

        context.restore();
        context.fillRect(0, 0, 100, 200);//從點(0,0)開始繪制紅色矩形


    }
</script>

注意:save() 只會保存繪圖上下文的設置和變換,但不會保存繪圖上下文的內容。

6 繪制圖像

使用 drawImage() 可以把圖像繪制到畫布中。可以傳入 HTML 的 <img> 元素,以及繪制該圖像的起點的 x 和 y 坐標;還可以再加上兩個參數(目標寬度和目標高度),這可以改變繪制后的圖像大小;實際上還可以把圖像的某個區域繪制到上下文中,這需要傳入 9 個參數:要繪制的圖像、源圖像的 x、y 坐標、源圖像的寬度和高度、目標圖像的 x、y 坐標、目標圖像的寬度和高度:

<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>
<img id="smiley" src="smile.gif" border="1" title="Image tag"/>
<script type="text/javascript">
    window.onload = function () {//必須在 onload 內運行才有效
        var drawing = document.getElementById("drawing");

        if (drawing.getContext) {//確定瀏覽器支持 canvas
            var context = drawing.getContext("2d");

            var image = document.getElementById("smiley");

            //draw regular size
            context.drawImage(image, 10, 10);

            //draw smaller size
            context.drawImage(image, 50, 10, 20, 30);

            //draw just part of the image
            context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);

        }
    };

</script>

還可以傳入另一個 <canvas> 元素作為 drawImage() 方法的第一個參數,這樣就可以把另一個畫布內容繪制到當前的畫布上。

drawImage() 的操作結果可以通過 toDataURL() 得到,但這個圖像不能來自其他域。還有,這個 toDataURL() 是 Canvas 對象上的方法!

# 7 陰影

有這些方法可以為形狀或路徑繪制陰影:

方法 說明
shadowColor 陰影顏色,CSS 的顏色格式,默認為黑色。
shadowOffsetX 形狀或路徑 x 軸方向上的陰影偏移量,默認為 0。
shadowOffsetY 形狀或路徑 y 軸方向上的陰影偏移量,默認為 0。
shadowBlur 模糊的像素數,默認為0,即不模糊。

它們都可以通過 context 對象進行修改,只要在繪制前為它們設置值,就能生成陰影:

“` 
A drawing of something.

var drawing = document.getElementById("drawing"); if (drawing.getContext) {//確定瀏覽器支持 canvas var context = drawing.getContext("2d"); //設置陰影 context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowBlur = 4; context.shadowColor = "rgba(0,0,0,0.5)"; //繪制紅色矩形 context.fillStyle = "#ff0000"; context.fillRect(10, 10, 50, 50); //繪制半透明的藍色矩形 context.fillStyle = "rgba(0,0,255,0.5)"; context.fillRect(30, 30, 50, 50); }

“`

 

8 漸變

使用 CanvasGradient 實例可以創建一個新的線性漸變,然后調用 createLinearGradient() ,它接收 4 個參數:起點的 x、y 坐標、終點的 x、y 坐標,它會創建一個指定大小的漸變,然后返回 CanvasGradient 實例。

創建漸變對象后,可以使用 addColorStop() 來指定色標。它接受 2 個參數:色標的位置(0 ~ 1)以及 CSS 顏色值。接着可以把 fillStyle 或 strokeStyle 設置為這個對象,使用漸變來繪制形狀或者描邊:

<script type="text/javascript">
    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");


        //繪制紅色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);

        //創建漸變對象
        var gradient = context.createLinearGradient(30, 30, 70, 70);
        gradient.addColorStop(0, "white");
        gradient.addColorStop(1, "black");

        //繪制漸變矩形
        context.fillStyle = gradient;
        context.fillRect(30, 30, 50, 50);
    }
</script>

 

如果漸變矩形沒有繪制到恰當的位置,那就只會顯示部分漸變效果:

...
//繪制漸變矩形
context.fillStyle = gradient;
context.fillRect(50, 50, 50, 50);
...

 

所以要確保漸變一定要與形狀對齊,因此可以可以使用函數來確定坐標處於合適的位置:

<script type="text/javascript">
    function createRectLinearGradient(context, x, y, width, height) {
        return context.createLinearGradient(x, y, x + width, y + height);
    }

    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");


        //繪制紅色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);

        //創建漸變對象
        var gradient = createRectLinearGradient(context,30, 30, 50, 50);
        gradient.addColorStop(0, "white");
        gradient.addColorStop(1, "black");

        //繪制漸變矩形
        context.fillStyle = gradient;
        context.fillRect(30, 30, 50, 50);
    }
</script>

createRectLinearGradient() 函數是基於起點的 x 和 y 坐標以及寬度和高度來創建漸變對象的,這樣就可以在 fillRect() 中使用相同的值。

createRadialGradient() 可以創建徑向漸變,即放射漸變。它接受 6 個參數:對應兩個圓的圓心和半徑,即起點圓的圓心(x、y)和半徑,以及終點圓的圓心(x、y)和半徑。

如果要從某個形狀的中心點創建一個向外擴散的徑向漸變,就必須把這兩個圓定義為同心圓:

<script type="text/javascript">

    var drawing = document.getElementById("drawing");

    if (drawing.getContext) {//確定瀏覽器支持 canvas
        var context = drawing.getContext("2d");

        var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
        gradient.addColorStop(0, "white");
        gradient.addColorStop(1, "black");


        //繪制紅色矩形
        context.fillStyle = "#ff0000";
        context.fillRect(10, 10, 50, 50);

        //繪制漸變矩形
        context.fillStyle = gradient;
        context.fillRect(30, 30, 50, 50);
    }
</script>

 

9 模式

模式就是重復的圖像,可以利用模式來填充或者描邊圖形。createPattern() 會創建一個模式,它接受 2 個參數:一個 HTML 的 <img> 元素以及如何重復圖像(與 CSS 的 background-repeat 屬性值一致,即 repeat\repeat-x\repeat-y\no-repeat):

<script type="text/javascript">
    window.onload = function () {//放在這里,才有效
        var drawing = document.getElementById("drawing");

        if (drawing.getContext) {//確定瀏覽器支持 canvas
            var context = drawing.getContext("2d");

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

            //繪制矩形
            context.fillStyle = pattern;
            context.fillRect(10, 10, 150, 150);
        }
    };
</script>

 

 

createPattern() 的第一個參數也可以是 <video> 元素或者是 <canvas> 元素。

10 使用圖像數據

使用 getImageData() 可以取得原始的圖像數據。它接受 4 個參數:圖像區域的 x、y 坐標以及該區域的像素高度與寬度。它返回 ImageData 實例。

ImageData 實例有三個屬性:width、height 和 data。data 是數組,它保存着圖像中每一個像素的數據。每一個像素的數據包含 4 個元素它們是紅、綠、藍和透明度值。這些值都介於 0 到 255 之間。

可以修改圖像的數據,創建一個簡單的灰階過濾器:

<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

<img id="smiley" src="smile2.gif" border="1"
     title="Image tag">

<script type="text/javascript">

    window.onload = function () {
        var drawing = document.getElementById("drawing");

        if (drawing.getContext) {//確定瀏覽器支持 canvas
            var context = drawing.getContext("2d"),
                    image = document.images[0],
                    imageData, data,
                    i, len, average,
                    red, green, blue, alpha;

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

            //取得圖像數據
            imageData = context.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];

                //求得 rgb 平均值
                average = Math.floor((red + green + blue) / 3);

                //設置顏色值,透明度不變
                data[i] = average;
                data[i + 1] = average;
                data[i + 2] = average;
            }

            //回寫圖像數據並顯示結果
            imageData.data = data;
            context.putImageData(imageData, 0, 0);

        }
    };

</script>

注意上面的代碼必須運行於 web 服務器(如果是 chrome),而且只對 gif 圖像有效!

 

* 注意:* 只有在畫布中的圖像都是來源於同一個域時,才可以取得圖像數據!否則會報 JavaScript 錯誤。


11 合成

globalAlpha 屬性可以指定透明度,它的值介於 0 到 1,默認是 0.如果所有后續的操作都要基於同樣的透明度,那就可以先設置 globalAlpha 屬性,然后再繪制,最后再設置為默認值:

<script type="text/javascript">

    window.onload = function () {
        var drawing = document.getElementById("drawing");

        if (drawing.getContext) {//確定瀏覽器支持 canvas
            var context = drawing.getContext("2d");

            //繪制紅色矩形
            context.fillStyle = "#ff0000";
            context.fillRect(10, 10, 50, 50);

            //修改全局透明度
            context.globalAlpha = 0.5;

            //繪制藍色矩形
            context.fillStyle = "rgba(0,0,255,1)";
            context.fillRect(30, 30, 50, 50);

            //重置全局透明度
            context.globalAlpha = 0;
        }
    };

</script>

 

globalCompositionOperation 屬性用於指定后繪制的圖形與新繪制的圖形的結合方式,值是字符串,有這些:

屬性值 說明
source-over 后繪制的圖形在先繪制的圖形的上方,默認。
source-in 后繪制的圖形與先繪制的圖形重疊的部分可見,其他部分透明。
source-out 后繪制的圖形與先繪制的圖形不重疊的部分可見,先繪制的圖形透明。
source-atop 后繪制的圖形與先繪制的圖形重疊的部分可見,先繪制的圖形不受影響。
destination-over 后繪制的圖形在先繪制的圖形的下方,只有先繪制的圖形的透明下的部分才可見。
destination-in 后繪制的圖形在先繪制的圖形的下方,不重疊的部分透明。
destination-out 后繪制的圖形擦除先繪制圖形的重疊部分。
destination-atop 后繪制的圖形在先繪制的圖形的下方,不重疊的部分,先繪制的圖形透明。
lighter 后繪制的圖形與先繪制的圖形的重疊部分值相加,即變亮。
copy 后繪制的圖形完全代替先繪制的圖形的重疊部分。
xor 后繪制的圖形與先繪制的圖形在重疊部分執行“異或”操作。
<script type="text/javascript">

    window.onload = function () {
        var drawing = document.getElementById("drawing");

        if (drawing.getContext) {//確定瀏覽器支持 canvas
            var context = drawing.getContext("2d");

            //繪制紅色矩形
            context.fillStyle = "#ff0000";
            context.fillRect(10, 10, 50, 50);

            //設置合成操作
            context.globalCompositeOperation="destination-over";

            //繪制藍色矩形
            context.fillStyle = "rgba(0,0,255,1)";
            context.fillRect(30, 30, 50, 50);

            //重置全局透明度
            context.globalAlpha = 0;
        }
    };

</script>

 

使用 globalCompositionOperation 屬性時,請一定要多測試一些瀏覽器,因為不同的瀏覽器可能在實現這個屬性時存在較大的差異!

 

轉載自--csdn

覺得好就拿來了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM