說說如何使用 canvas 進(jìn)行 2D 繪圖

canvas 的 2D context 可以繪制簡(jiǎn)單的 2D 圖形薄腻。它的 2D context 坐標(biāo)開始于 <canvas> 元素的左上角敌蚜,原點(diǎn)坐標(biāo)是(0,0)困食。所有的坐標(biāo)值都基于這個(gè)原點(diǎn),x 值越大表示越靠右奴艾,y 值越大表示越靠下。width 和 height 表示水平和垂直方向上可用的像素?cái)?shù)内斯。

1 填充和描邊

填充就是用指定的樣式填充圖形蕴潦;而描邊就是給圖形的邊緣畫線。它們分別對(duì)應(yīng)兩個(gè)屬性:fillStyle 和 strokeStyle俘闯。這兩個(gè)屬性的值可以是字符串潭苞、漸變對(duì)象或者模式對(duì)象。默認(rèn)值都是 “#00000”真朗。如果為它們指定表示顏色的字符串值此疹,可以使用 CSS 中指定顏色值的任何格式(顏色名、十六進(jìn)制碼遮婶、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 個(gè) 參數(shù):矩形的 x 坐標(biāo)臀防、y 坐標(biāo)眠菇、矩形的寬度以及高度,這些參數(shù)的單位都是像素袱衷。

fillRect() 會(huì)為矩形填充指定的顏色捎废,顏色是通過 fillStyle 屬性進(jìn)行設(shè)置的:

<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);

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

因?yàn)榈诙€(gè)矩形是半透明的,所以你可以透過上面的藍(lán)色矩形看到下面的紅色矩形:

fillRect
fillRect

strokeRect() 會(huì)使用指定的顏色為矩形描邊致燥,描邊的顏色是通過 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);

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

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


clearRect() 可以清除畫布上的矩形區(qū)域荷腊。它是通過把某一矩形區(qū)域變透明來實(shí)現(xiàn)的。通過繪制形狀然后在清除指定區(qū)域后急凰,會(huì)生成很有意思的效果:

<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);

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

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

3 繪制路徑

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

方法 說明
arc(x, y, radius, startAngle, endAngle, counterclockwise) 以 (x,y) 為圓心繪制一條弧線抡锈,它的半徑是 radius疾忍。startAngle 是起始角度,endAngle 是結(jié)束角度床三,它們的單位都是弧度一罩。counterclockwise 表示起始和結(jié)束角度是否按逆時(shí)針方向計(jì)算。
arcTo(x1, y1, x2, y2, radius) 從上一點(diǎn)開始繪制弧線撇簿,以給定的半徑(radius)穿過 (x1, y1)聂渊,直到 (x2, y2) 為止。
bezierCurveTo(c1x, c1y, c2x, c2y, x, y) 從上一點(diǎn)開始繪制曲線四瘫,以 (c1x, c1y) 和 (c2x, c2y) 為控制點(diǎn)汉嗽,開始繪制曲線。
lineTo(x, y) 從上一點(diǎn)開始繪制直線找蜜,到 (x, y) 為止饼暑。
moveTo(x, y) 將繪圖的游標(biāo)移動(dòng)到 (x, y) ,只是移動(dòng)不畫線洗做。
quadraticCurveTo(cx, cy, x, y) 從上一點(diǎn)開始繪制二次曲線弓叛,以 (cx, cy)作為控制點(diǎn),到 (x, y) 為止诚纸。
rect(x, y, width, height) 從點(diǎn)(x, y) 開始繪制矩形邪码,width 和 height 分別代表寬和高,它繪制的是矩形路徑咬清,而不是我們之前說過的矩形形狀闭专。

創(chuàng)建路徑后,有這些選擇:

  • 調(diào)用 closePath() 可以繪制一條連接到路徑起點(diǎn)的線條旧烧。
  • 調(diào)用 fill() 可以填充路徑(fillStyle 指定的值)影钉。
  • 調(diào)用 stroke() 對(duì)路徑進(jìn)行描邊(strokeStyle 指定的值)。
  • 調(diào)用 clip() 在路徑上創(chuàng)建一個(gè)剪貼區(qū)域掘剪。

現(xiàn)在我們繪制一個(gè)不帶數(shù)字的鐘:

<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);

        //繪制內(nèi)圓
        context.moveTo(194,100);//避免出現(xiàn)從外圓移動(dòng)到內(nèi)圓平委,造成的多余線條
        context.arc(100,100,94,0,2*Math.PI,false);

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

        //繪制時(shí)鐘
        context.moveTo(100,100);
        context.lineTo(35,100);

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

    }
</script>


不帶數(shù)字的鐘
不帶數(shù)字的鐘

路徑是一種主要的繪圖方式,因?yàn)樗転橐L制的圖形進(jìn)行更多的控制夺谁。

isPointInPath() 接收 x 和 y 坐標(biāo)作為參數(shù)廉赔,可以用來判斷某一點(diǎn)是否位于路徑上肉微。

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

4 繪制文本

繪制文本 有 fillText() 和 strokeText() 這兩個(gè)方法蜡塌,它們可以接收 4 個(gè)參數(shù):要繪制的文本字符串碉纳、x 坐標(biāo)、y 坐標(biāo)和最大像素寬度(可選)馏艾,它們都有以下這些屬性:

屬性 說明
font 文本樣式劳曹、大小以及字體(CSS 的字體格式)
textAlign 文本對(duì)齊方式,有這些值:start琅摩、end铁孵、left、right 和 center房资。建議使用 start(從左到右) 和 end(從右到左)蜕劝。
textBaseline 文本的基線,有這些值:top轰异、hanging熙宇、middle、alphabetic溉浙、ideographic 和 bottom烫止。

這些屬性都有默認(rèn)值。fillText() 使用 fillStyle 來繪制文本戳稽,strokeText() 使用 strokeStyle 來為文本描邊馆蠕。fillText() 的頻率會(huì)更多,因?yàn)樗7铝嗽诰W(wǎng)頁(yè)中顯示的文本方式【妫現(xiàn)在我們?cè)谥暗溺娚侠L制數(shù)字:

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

的鐘上繪制數(shù)字
的鐘上繪制數(shù)字

如果把 textAlign 設(shè)置為 start互躬,表示 x 坐標(biāo)是在文本左端的位置;如果設(shè)置為 end颂郎,則表示 x 坐標(biāo)是在文本右端的位置:

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

//起點(diǎn)對(duì)齊
context.textAlign="start";
context.fillText("12",100,40);


//終點(diǎn)對(duì)齊
context.textAlign="end";
context.fillText("12",100,60);

起點(diǎn)對(duì)齊/終點(diǎn)對(duì)齊
起點(diǎn)對(duì)齊/終點(diǎn)對(duì)齊

meansureText() 可以確定文本的大小吼渡,它接受一個(gè)參數(shù),即要繪制的文本乓序,它會(huì)返回 TextMetrics 對(duì)象寺酪。這個(gè)對(duì)象有一個(gè) width 屬性。

meansureText() 會(huì)根據(jù) font替劈、textAlign 和 textBaseline 的值來計(jì)算指定文本的合適大屑娜浮:

<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 變換

通過變換,可以把變換后的圖像繪制到畫布上陨献。創(chuàng)建繪制上下文時(shí)盒犹,會(huì)以默認(rèn)值初始化變換矩陣。有這些方法:

方法 說明
rotate(angle) 圍繞原點(diǎn)旋轉(zhuǎn)圖像 angle 弧度。
scale(scaleX, scaleY) 縮放圖像急膀,x 方向上乘以 scaleX沮协,y 方向上乘以 scaleY。參數(shù)的默認(rèn)值都是 1.0卓嫂。
translate(x, y) 坐標(biāo)原點(diǎn)(0,0)移動(dòng)到(x,y)慷暂。
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) 將矩陣重置為默認(rèn)狀態(tài),然后再調(diào)用 transform()命黔。
transform(m1_1, m1_2, m2_1, m2_2, dx, dy) 修改變換矩陣呜呐,即乘上底下這樣的矩陣:

Markdown
Markdown

現(xiàn)在我們把原點(diǎn)變換到表盤的中心就斤,然后再繪制表針悍募,這樣在同一方向上繪制線條就變成了一個(gè)簡(jiǎn)單的數(shù)學(xué)問題咯(因?yàn)樗械牡挠?jì)算都是基于 (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);

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

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

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

        //繪制時(shí)鐘
        context.moveTo(0,0);
        context.lineTo(-65,0);

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

    }
</script>

還可以使用 rotate() 來旋轉(zhuǎn)時(shí)鐘的表針:

<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);

        //繪制內(nèi)圓
        context.moveTo(194,100);//避免出現(xiàn)從外圓移動(dòng)到內(nèi)圓洋机,造成的多余線條
        context.arc(100,100,94,0,2*Math.PI,false);

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

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

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

        //繪制時(shí)鐘
        context.moveTo(0,0);
        context.lineTo(-65,0);

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

    }
</script>
旋轉(zhuǎn)時(shí)鐘的表針
旋轉(zhuǎn)時(shí)鐘的表針

有兩種方法可以跟蹤狀態(tài)變化坠宴。一個(gè)是 save() 方法,它會(huì)把當(dāng)時(shí)的所有設(shè)置放入一個(gè)棧結(jié)構(gòu)绷旗。如果想要回到之前的設(shè)置喜鼓,可以調(diào)用另一個(gè)方法 restore() ,它會(huì)恢復(fù)之前的狀態(tài)(在棧結(jié)構(gòu)中返回一級(jí))。多次調(diào)用 save() 會(huì)把多個(gè)設(shè)置都保存到棧結(jié)構(gòu)中衔肢,如果這時(shí)再連續(xù)調(diào)用 restore() 方法庄岖,則會(huì)一級(jí)一級(jí)地返回設(shè)置:

<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);//從點(diǎn)(100,200)開始繪制藍(lán)色矩形

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

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


    }
</script>

注意:save() 只會(huì)保存繪圖上下文的設(shè)置和變換,但不會(huì)保存繪圖上下文的內(nèi)容角骤。

6 繪制圖像

使用 drawImage() 可以把圖像繪制到畫布中隅忿。可以傳入 HTML 的 <img> 元素邦尊,以及繪制該圖像的起點(diǎn)的 x 和 y 坐標(biāo)背桐;還可以再加上兩個(gè)參數(shù)(目標(biāo)寬度和目標(biāo)高度),這可以改變繪制后的圖像大胁踝帷链峭;實(shí)際上還可以把圖像的某個(gè)區(qū)域繪制到上下文中,這需要傳入 9 個(gè)參數(shù):要繪制的圖像又沾、源圖像的 x弊仪、y 坐標(biāo)、源圖像的寬度和高度杖刷、目標(biāo)圖像的 x撼短、y 坐標(biāo)、目標(biāo)圖像的寬度和高度:

<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>
![](smile.gif)
<script type="text/javascript">
    window.onload = function () {//必須在 onload 內(nèi)運(yùn)行才有效
        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>
繪制圖像
繪制圖像

還可以傳入另一個(gè) <canvas> 元素作為 drawImage() 方法的第一個(gè)參數(shù)挺勿,這樣就可以把另一個(gè)畫布內(nèi)容繪制到當(dāng)前的畫布上曲横。

drawImage() 的操作結(jié)果可以通過 toDataURL() 得到,但這個(gè)圖像不能來自其他域。還有禾嫉,這個(gè) toDataURL() 是 Canvas 對(duì)象上的方法灾杰!

7 陰影

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

方法 說明
shadowColor 陰影顏色,CSS 的顏色格式熙参,默認(rèn)為黑色艳吠。
shadowOffsetX 形狀或路徑 x 軸方向上的陰影偏移量,默認(rèn)為 0孽椰。
shadowOffsetY 形狀或路徑 y 軸方向上的陰影偏移量昭娩,默認(rèn)為 0。
shadowBlur 模糊的像素?cái)?shù)黍匾,默認(rèn)為0栏渺,即不模糊。

它們都可以通過 context 對(duì)象進(jìn)行修改锐涯,只要在繪制前為它們?cè)O(shè)置值磕诊,就能生成陰影:

<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");

       //設(shè)置陰影
       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);

       //繪制半透明的藍(lán)色矩形
       context.fillStyle = "rgba(0,0,255,0.5)";
       context.fillRect(30, 30, 50, 50);
   }
</script>
設(shè)置陰影
設(shè)置陰影

8 漸變

使用 CanvasGradient 實(shí)例可以創(chuàng)建一個(gè)新的線性漸變,然后調(diào)用 createLinearGradient() 纹腌,它接收 4 個(gè)參數(shù):起點(diǎn)的 x霎终、y 坐標(biāo)、終點(diǎn)的 x升薯、y 坐標(biāo)莱褒,它會(huì)創(chuàng)建一個(gè)指定大小的漸變,然后返回 CanvasGradient 實(shí)例涎劈。

創(chuàng)建漸變對(duì)象后广凸,可以使用 addColorStop() 來指定色標(biāo)。它接受 2 個(gè)參數(shù):色標(biāo)的位置(0 ~ 1)以及 CSS 顏色值责语。接著可以把 fillStyle 或 strokeStyle 設(shè)置為這個(gè)對(duì)象炮障,使用漸變來繪制形狀或者描邊:

<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);

        //創(chuàng)建漸變對(duì)象
        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>
繪制漸變矩形
繪制漸變矩形

如果漸變矩形沒有繪制到恰當(dāng)?shù)奈恢茫蔷椭粫?huì)顯示部分漸變效果:

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

所以要確保漸變一定要與形狀對(duì)齊坤候,因此可以可以使用函數(shù)來確定坐標(biāo)處于合適的位置:

<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);

        //創(chuàng)建漸變對(duì)象
        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() 函數(shù)是基于起點(diǎn)的 x 和 y 坐標(biāo)以及寬度和高度來創(chuàng)建漸變對(duì)象的胁赢,這樣就可以在 fillRect() 中使用相同的值。

createRadialGradient() 可以創(chuàng)建徑向漸變白筹,即放射漸變智末。它接受 6 個(gè)參數(shù):對(duì)應(yīng)兩個(gè)圓的圓心和半徑,即起點(diǎn)圓的圓心(x徒河、y)和半徑系馆,以及終點(diǎn)圓的圓心(x、y)和半徑顽照。

如果要從某個(gè)形狀的中心點(diǎn)創(chuàng)建一個(gè)向外擴(kuò)散的徑向漸變由蘑,就必須把這兩個(gè)圓定義為同心圓:

<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>
向外擴(kuò)散的徑向漸變
向外擴(kuò)散的徑向漸變

9 模式

模式就是重復(fù)的圖像闽寡,可以利用模式來填充或者描邊圖形。createPattern() 會(huì)創(chuàng)建一個(gè)模式尼酿,它接受 2 個(gè)參數(shù):一個(gè) HTML 的 <img> 元素以及如何重復(fù)圖像(與 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>
重復(fù)的圖像
重復(fù)的圖像

createPattern() 的第一個(gè)參數(shù)也可以是 <video> 元素或者是 <canvas> 元素裳擎。

10 使用圖像數(shù)據(jù)

使用 getImageData() 可以取得原始的圖像數(shù)據(jù)涎永。它接受 4 個(gè)參數(shù):圖像區(qū)域的 x、y 坐標(biāo)以及該區(qū)域的像素高度與寬度鹿响。它返回 ImageData 實(shí)例羡微。

ImageData 實(shí)例有三個(gè)屬性:width、height 和 data惶我。data 是數(shù)組妈倔,它保存著圖像中每一個(gè)像素的數(shù)據(jù)。每一個(gè)像素的數(shù)據(jù)包含 4 個(gè)元素它們是紅指孤、綠启涯、藍(lán)和透明度值贬堵。這些值都介于 0 到 255 之間恃轩。

可以修改圖像的數(shù)據(jù),創(chuàng)建一個(gè)簡(jiǎn)單的灰階過濾器:

<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);

            //取得圖像數(shù)據(jù)
            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);

                //設(shè)置顏色值黎做,透明度不變
                data[i] = average;
                data[i + 1] = average;
                data[i + 2] = average;
            }

            //回寫圖像數(shù)據(jù)并顯示結(jié)果
            imageData.data = data;
            context.putImageData(imageData, 0, 0);

        }
    };

</script>

注意上面的代碼必須運(yùn)行于 web 服務(wù)器(如果是 chrome)叉跛,而且只對(duì) gif 圖像有效!

的灰階過濾器
的灰階過濾器

** 注意:** 只有在畫布中的圖像都是來源于同一個(gè)域時(shí)蒸殿,才可以取得圖像數(shù)據(jù)筷厘!否則會(huì)報(bào) JavaScript 錯(cuò)誤。


11 合成

globalAlpha 屬性可以指定透明度宏所,它的值介于 0 到 1酥艳,默認(rèn)是 0.如果所有后續(xù)的操作都要基于同樣的透明度,那就可以先設(shè)置 globalAlpha 屬性爬骤,然后再繪制充石,最后再設(shè)置為默認(rèn)值:

<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;

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

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

</script>
指定透明度
指定透明度

globalCompositionOperation 屬性用于指定后繪制的圖形與新繪制的圖形的結(jié)合方式,值是字符串霞玄,有這些:

屬性值 說明
source-over 后繪制的圖形在先繪制的圖形的上方骤铃,默認(rèn)。
source-in 后繪制的圖形與先繪制的圖形重疊的部分可見坷剧,其他部分透明惰爬。
source-out 后繪制的圖形與先繪制的圖形不重疊的部分可見,先繪制的圖形透明惫企。
source-atop 后繪制的圖形與先繪制的圖形重疊的部分可見撕瞧,先繪制的圖形不受影響。
destination-over 后繪制的圖形在先繪制的圖形的下方,只有先繪制的圖形的透明下的部分才可見丛版。
destination-in 后繪制的圖形在先繪制的圖形的下方咨跌,不重疊的部分透明。
destination-out 后繪制的圖形擦除先繪制圖形的重疊部分硼婿。
destination-atop 后繪制的圖形在先繪制的圖形的下方锌半,不重疊的部分,先繪制的圖形透明寇漫。
lighter 后繪制的圖形與先繪制的圖形的重疊部分值相加刊殉,即變亮。
copy 后繪制的圖形完全代替先繪制的圖形的重疊部分州胳。
xor 后繪制的圖形與先繪制的圖形在重疊部分執(zhí)行“異或”操作记焊。

<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);

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

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

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

</script>
指定后繪制的圖形與新繪制的圖形的結(jié)合方式
指定后繪制的圖形與新繪制的圖形的結(jié)合方式

使用 globalCompositionOperation 屬性時(shí),請(qǐng)一定要多測(cè)試一些瀏覽器栓撞,因?yàn)椴煌臑g覽器可能在實(shí)現(xiàn)這個(gè)屬性時(shí)存在較大的差異遍膜!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瓤湘,隨后出現(xiàn)的幾起案子瓢颅,更是在濱河造成了極大的恐慌,老刑警劉巖弛说,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挽懦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡木人,警方通過查閱死者的電腦和手機(jī)信柿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來醒第,“玉大人渔嚷,你說我怎么就攤上這事〕砺” “怎么了形病?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蒲列。 經(jīng)常有香客問我窒朋,道長(zhǎng),這世上最難降的妖魔是什么蝗岖? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任侥猩,我火速辦了婚禮,結(jié)果婚禮上抵赢,老公的妹妹穿的比我還像新娘欺劳。我一直安慰自己唧取,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布划提。 她就那樣靜靜地躺著枫弟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹏往。 梳的紋絲不亂的頭發(fā)上淡诗,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音伊履,去河邊找鬼韩容。 笑死,一個(gè)胖子當(dāng)著我的面吹牛唐瀑,可吹牛的內(nèi)容都是我干的群凶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼哄辣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼请梢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起力穗,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤毅弧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后睛廊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體形真,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杉编,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年超全,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邓馒。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嘶朱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出光酣,到底是詐尸還是另有隱情疏遏,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布救军,位于F島的核電站财异,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏唱遭。R本人自食惡果不足惜戳寸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拷泽。 院中可真熱鬧疫鹊,春花似錦袖瞻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至枣耀,卻和暖如春霉晕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捞奕。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工娄昆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缝彬。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓萌焰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親谷浅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扒俯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 本章內(nèi)容 理解 元素 繪制簡(jiǎn)單的 2D 圖形 使用 WebGL 繪制 3D 圖形 這個(gè)元素負(fù)責(zé)在頁(yè)面中設(shè)定一個(gè)區(qū)域...
    悶油瓶小張閱讀 836評(píng)論 0 0
  • 熟悉html5的程序員們肯定都知道 元素,該元素是用來在頁(yè)面中規(guī)定一塊區(qū)域一疯,然后由js在該區(qū)域內(nèi)繪制圖形撼玄。canv...
    米幾V閱讀 2,139評(píng)論 1 5
  • 一:canvas簡(jiǎn)介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標(biāo)簽 ②:HTML5 ...
    GreenHand1閱讀 4,667評(píng)論 2 32
  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發(fā)出絢麗的界面效果墩邀,一方面得益于成功系統(tǒng)的設(shè)計(jì)掌猛,另一方面得益...
    韓七夏閱讀 2,710評(píng)論 2 10
  • 邊緩存邊播放的視頻器封裝 模仿原生的提供的視頻播放器VideoView,封裝一個(gè)仿微信的視頻播放器眉睹。 原生的Vid...
    maimingliang閱讀 3,895評(píng)論 2 15