canvas學習筆記(中篇) -- canvas入門教程-- 顏色/透明度/漸變色/線寬/線條樣式/虛線/文本/陰影/圖片/像素處理


【中篇】 -- 建議學習時間4小時  課程共(上中下)三篇

此筆記是我初次接觸canvas的時候的學習筆記,這次特意整理為博客供大家入門學習,幾乎涵蓋了canvas所有的基礎知識,並且有眾多練習案例,建議大家學習10~15個小時,里面的案例請挨個敲一遍,這樣才能轉化為自己的知識。

技術要求:有html/css/js基礎。

 

顏色


為canvas添加顏色我們使用 fillStyle 和 strokeStyle,在上一篇中我們已經簡單的使用過

fillStyle = color
設置圖形的填充顏色。
strokeStyle = color
設置圖形輪廓的顏色。

其中的 color可以是   顏色名/顏色值/rgba等等

 

例子:繪制多彩方塊

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        for(var i=0; i<6; i++){
            for(var j=0; j<6; j++){
                ctx.fillStyle = 'rgb('+Math.floor(255-42.5*i)+','+Math.floor(255-42.5*j)+',0)';
                ctx.fillRect(150+j*25,50+i*25,25,25);
            }
        }

 

例子:繪制多彩圓圈

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        for(var i=0; i<6; i++){
            for(var j=0; j<6; j++){
                ctx.strokeStyle = 'rgb(0,'+Math.floor(255-42.5*i)+','+Math.floor(255-42.5*j)+')';
                ctx.beginPath();
                ctx.arc(150+j*25,50+i*25,10,0,Math.PI*2,true);
                ctx.stroke();
            }
        }

 

透明度


 

 全局透明度:

ctx.globalAlpha = transparencyValue
這個屬性影響到 canvas 里所有圖形的透明度,有效的值范圍是 0.0 (完全透明)到 1.0(完全不透明),默認是 1.0。

下面代碼設置全局透明度為 0.3,后續繪制的所有圖像,都會是0.3的透明度。

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");
        
        ctx.globalAlpha = 0.3;//設置全局透明度
        ctx.fillStyle = "red"; //設置顏色
        ctx.fillRect(50,50, 100, 100); //繪制方塊

例子:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        ctx.fillStyle = "#fd0";
        ctx.fillRect(0,0,75,75);
        ctx.fillStyle = "#6c0";
        ctx.fillRect(75,0,75,75);
        ctx.fillStyle = "#09f";
        ctx.fillRect(0,75,75,75);
        ctx.fillStyle = "#f30";
        ctx.fillRect(75,75,75,75);
        ctx.fillStyle = "#fff";

        //設置透明值
        ctx.globalAlpha = 0.2;
        for(var i=0; i<7; i++){
            ctx.beginPath();
            ctx.arc(75, 75, 10+10*i, 0, Math.PI*2, true);
            ctx.fill();
        }

這種設置全局透明度的方式不好控制,我們通常通過設置 rgba 顏色值的透明度來設置透明

例子:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        ctx.fillStyle = "#fd0";
        ctx.fillRect(0,0,150,37.5);
        ctx.fillStyle = "#6c0";
        ctx.fillRect(0,37,150,37.5);
        ctx.fillStyle = "#09f";
        ctx.fillRect(0,75,150,37.5);
        ctx.fillStyle = "#f30";
        ctx.fillRect(0,112,150,37.5);
        ctx.fillStyle = "#fff";
        for(var i=0; i<10; i++){
            ctx.fillStyle = "rgba(255, 255, 255,"+ (i+1)/10 +")";
            for(var j=0; j<4; j++){
                ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5);
            }
        }

 

漸變色


 

線性漸變  createLinearGradient(x1, y1, x2, y2)
createLinearGradient 方法接受 4 個參數,表示漸變的起點 (x1,y1) 與終點 (x2,y2)。


徑向漸變  createRadialGradient(x1, y1, r1, x2, y2, r2)
createRadialGradient 方法接受 6 個參數,前三個定義一個以 (x1,y1) 為原點,半徑為 r1 的圓,后三個參數則定義另一個以 (x2,y2) 為原點,半徑為 r2 的圓。

創建出 canvasGradient 對象后,我們就可以用 addColorStop 方法給它上色了。

gradient.addColorStop(position, color)
addColorStop 方法接受 2 個參數,position 參數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置。例如,0.5 表示顏色會出現在正中間。color 參數必須是一個有效的 CSS 顏色值(如 #FFF, rgba(0,0,0,1),等等)。

 

線性漸變 示例:

代碼如下:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        //線性漸變
        var lineargradient = ctx.createLinearGradient(0,0,0,140);
        lineargradient.addColorStop(0,'#00ABEB');
        lineargradient.addColorStop(0.5, "#fff");
        lineargradient.addColorStop(0.5, "green");
        lineargradient.addColorStop(1,'#fff');

        var lineargradient2 = ctx.createLinearGradient(0,50,0,95);
        lineargradient2.addColorStop(0,'#000');
        lineargradient2.addColorStop(1,'rgba(0,0,0,0)');

        ctx.fillStyle = lineargradient;
        ctx.strokeStyle = lineargradient2;

        ctx.fillRect(10,10,130,130);
        ctx.strokeRect(50,50,50,50);

 

徑向漸變 示例:

 

代碼如下:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        /*徑向漸變*/
        var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
        radgrad.addColorStop(0, "#fff");
        radgrad.addColorStop(0.9, "green");
        radgrad.addColorStop(1, "rgba(255,255,255,0)"); //最后一個顏色最好寫成透明的,這樣圓圈以外部分會以這個顏色填充

        var radgrad2 = ctx.createRadialGradient(112,120,0,112,120,50);
        radgrad2.addColorStop(0, "#fff");
        radgrad2.addColorStop(0.9, "#FF0188");
        radgrad2.addColorStop(1, "rgba(255,1,136,0)");

        var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);
        radgrad3.addColorStop(0, '#00C9FF');
        radgrad3.addColorStop(0.8, '#00B5E2');
        radgrad3.addColorStop(1, 'rgba(0,201,255,0)');

        ctx.fillStyle = radgrad;
        ctx.fillRect(0,0,150,150);

        ctx.fillStyle = radgrad2;
        ctx.fillRect(0,0,200,200);

        ctx.fillStyle = radgrad3;
        ctx.fillRect(0,0,200,200);

 

 

線寬


 

 lineWidth = value

設置線條寬度。 直接給數值,不需要單位,默認單位為像素

 例子:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        //線寬
        for(var i=0; i<10; i++){
            ctx.lineWidth = i+1;
            ctx.beginPath();
            var a = 5;
            ctx.moveTo(a+i*14, 5);
            ctx.lineTo(a+i*14, 140);
            ctx.stroke();
        }

大家會發現,我們繪制出的線條中,基數線條居然是模糊的

那這是什么原因呢!見下圖,用網格來代表 canvas 的坐標格,每一格對應屏幕上一個像素點。在第一個圖中,填充了 (2,1) 至 (5,5) 的矩形,整個區域的邊界剛好落在像素邊緣上,這樣就可以得到的矩形有着清晰的邊緣。

如果你想要繪制一條從 (3,1) 到 (3,5),寬度是 1.0 的線條,你會得到像第二幅圖一樣的結果。實際填充區域(深藍色部分)僅僅延伸至路徑兩旁各一半像素。而這半個像素又會以近似的方式進行渲染,這意味着那些像素只是部分着色,結果就是以實際筆觸顏色一半色調的顏色來填充整個區域(淺藍和深藍的部分)。這就是上例中為何寬度為 1.0 的線並不准確的原因。

要解決這個問題,你必須對路徑施以更加精確的控制。已知粗 1.0 的線條會在路徑兩邊各延伸半像素,那么像第三幅圖那樣繪制從 (3.5,1) 到 (3.5,5) 的線條,其邊緣正好落在像素邊界,填充出來就是准確的寬為 1.0 的線條。

以此原理,我們只要將原來繪制過程中的基數線條 +0.5 像素即可

代碼修改如下(修改地方在9/10行):

 1         var c = document.getElementById("myCanvas");
 2         var ctx = c.getContext("2d");
 3 
 4         //線寬
 5         for(var i=0; i<10; i++){
 6             ctx.lineWidth = i+1;
 7             ctx.beginPath();
 8             var a = 5;
 9             if(i%2 == 0){
10                 a = 5.5;  //基數像素避免模糊
11             }
12             ctx.moveTo(a+i*14, 5);
13             ctx.lineTo(a+i*14, 140);
14             ctx.stroke();
15         }

這樣呈現的效果就不模糊了

 

線條樣式


lineCap = type 設置線條末端樣式。它可以為下面的三種的其中之一:butt,round 和 square。默認是 butt。

示例:

代碼如下:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        //線條末尾樣式
        var lineCap = ['butt','round','aquare'];
        ctx.strokeStyle = "#09f";
        ctx.beginPath();
        ctx.moveTo(10,10);
        ctx.lineTo(140,10);
        ctx.moveTo(10,140);
        ctx.lineTo(140,140);
        ctx.stroke();

        ctx.strokeStyle = "black";
        for(var i=0; i<lineCap.length; i++){
            ctx.lineWidth = 15;
            ctx.lineCap = lineCap[i];
            ctx.beginPath();
            ctx.moveTo(25+i*50,10);
            ctx.lineTo(25+i*50,140);
            ctx.stroke();
        }

 

 lineJoin = type  設定線條與線條間接合處的樣式。lineJoin 的屬性值決定了圖形中兩線段連接處所顯示的樣子。它可以是這三種之一:round, bevel 和 miter。默認是 miter。

示例:

代碼如下:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        //線條鏈接處樣式
        var lineJoin = ['round','bevel','miter'];
        ctx.strokeStyle = "#09f";
        ctx.lineWidth = 10;

        for(var i=0; i<lineJoin.length; i++){
            ctx.lineJoin = lineJoin[i];
            ctx.beginPath();
            ctx.moveTo(-5,5+i*40);
            ctx.lineTo(35,45+i*40);
            ctx.lineTo(75,5+i*40);
            ctx.lineTo(115,45+i*40);
            ctx.lineTo(155,5+i*40);
            ctx.stroke();
        }

 

虛線


 

ctx.setLineDash([x1, x2]); //設置設置虛線的間隔 x1表示虛線自身長度 x2表示間隔長度  默認單位:px
ctx.lineDashOffset = offset; //設置偏移量
ctx.strokeRect(x,y, width, height); //繪制虛線邊框

 

例子:跑馬燈效果

代碼如下:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        //虛線
        ctx.strokeStyle = "#09f";
        ctx.lineWidth = 4;
        var offset = 0;

        function draw(){
            ctx.clearRect(0, 0, c.width, c.height);
            ctx.setLineDash([4,2]);
            ctx.lineDashOffset = - offset;
            ctx.strokeRect(100,100,100,100);
        }

        function march(){
            offset++;
            if(offset > 16){
                offset = 0;
            }
            draw();
            setTimeout(march, 20)
        }
        march();

 

 

描繪文字


 canvas 提供了兩種方法來渲染文本:

fillText(text, x, y [, maxWidth])
在指定的(x,y)位置填充指定的文本,繪制的最大寬度是可選的.


strokeText(text, x, y [, maxWidth])
在指定的(x,y)位置繪制文本邊框,繪制的最大寬度是可選的.

 

文本設置(可不掌握):

font = value
當前我們用來繪制文本的樣式. 這個字符串使用和 CSS font 屬性相同的語法. 默認的字體是 10px sans-serif。
textAlign = value
文本對齊選項. 可選的值包括:start, end, left, right or center. 默認值是 start。
textBaseline = value
基線對齊選項. 可選的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默認值是 alphabetic。
direction = value
文本方向。可能的值包括:ltr, rtl, inherit。默認值是 inherit。

 

另外可以使用 measureText 來測量文本長度 (單位px)

 

示例:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        //線條鏈接處樣式
        ctx.strokeStyle = "#09f";
        ctx.lineWidth = 1;

        ctx.font = "48px Arial";
        ctx.fillText("Hellow World ! " , 50, 100);

        ctx.strokeText("Hellow World ! ", 50, 200);
        /* 測量文本長度 */
        var text = ctx.measureText("Hellow World ! ");
        ctx.fillText(text.width , 50, 300);

 

繪制陰影


 

 通過 ctx.shadow來設置

例子:

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        /* 陰影 */ 
        ctx.shadowOffsetX = 2;  //陰影x方向偏移量
        ctx.shadowOffsetY = 2;  //陰影y方向偏移量
        ctx.shadowBlur = 5;  //陰影模糊度
        ctx.shadowColor = "rgba(0,0,0,0.5)";  //陰影顏色

        ctx.font = "20px Times New Roman";
        ctx.fillStyle = "black";
        ctx.fillText("Sample String", 5, 30);

效果:

 

 

 繪制圖片


 

 使用 drawImage(image, x, y)

其中 image 是 Image對象 或者 canvas 對象,x 和 y 是其在目標 canvas 里的起始坐標。

示例(圖片使用了網絡圖片,所以地址比較長):

        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");
        
        var img = new Image(); //創建了一個Image對象
        img.src = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507713846845&di=51e9f2958ed57789a0fa8e656a8c57c8&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimage%2Fc0%253Dshijue1%252C0%252C0%252C294%252C40%2Fsign%3D952c2aeb14178a82da3177e39e6a19f8%2Fb8014a90f603738dbe7ddc05b91bb051f819ece6.jpg";
        img.onload = function(){
            ctx.drawImage(img,50,50,300,190);  //將圖片繪制到canvas中
        }

這里繪制圖片也可以使用 從頁面獲取的 Img dom對象,如:  ctx.drawImage(document.getElementsByTagName("img")[0],100,100,300,190);

 

圖片導出/下載圖片


 使用c.toDataURL()對canvas圖片數據進行輸出

示例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        *{margin: 0;padding: 0}
        body{
            margin: 30px;
        }
        canvas{
            border: 1px solid #a4e2f9;
            float: left;
        }
        img{
            float:left;
            margin: 0 10px;
        }

    </style>
</head>
<body>
    <canvas height="300" width="300" id="myCanvas"></canvas>
    <img id="showImg" src="" alt=""/>
    <a id="downloadBtn" href="" download="testImg">下載</a>
    <!-- a標簽設置 download="圖片名稱" 來設置點擊下載 -->
    

    <script>
        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        ctx.fillStyle = "#fd0";
        ctx.fillRect(0,0,150,37.5);
        ctx.fillStyle = "#6c0";
        ctx.fillRect(0,37,150,37.5);
        ctx.fillStyle = "#09f";
        ctx.fillRect(0,75,150,37.5);
        ctx.fillStyle = "#f30";
        ctx.fillRect(0,112,150,37.5);
        ctx.fillStyle = "#fff";
        for(var i=0; i<10; i++){
            ctx.fillStyle = "rgba(255, 255, 255,"+ (i+1)/10 +")";
            for(var j=0; j<4; j++){
                ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5);
            }
        }
        
        //將canvas生成的圖像 鏈接到 img標簽  和 a標簽下載鏈接中
        document.getElementById("showImg").setAttribute("src",c.toDataURL('png')); //輸出為png格式
        document.getElementById("downloadBtn").setAttribute("href",c.toDataURL('png'));

    </script>
</body>
</html>

 

 

獲取和操作canvas像素信息


 

可以用getImageData()方法,獲得一個包含畫布場景像素數據的ImageData對像
var myImageData = ctx.getImageData(left, top, width, height);


你可以用putImageData()方法去對場景進行像素數據的寫入。
ctx.putImageData(myImageData, dx, dy);
dx和dy參數表示你希望在場景內左上角繪制的像素數據所得到的設備坐標。

 

下面示例中,我們獲取canvas已經繪制的圖形信息,然后經過去色處理,然后再在旁邊重新繪制去色的圖形,具體解釋在代碼注釋中

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        *{margin: 0;padding: 0}
        body{
            margin: 30px;
        }
        canvas{
            border: 1px solid #a4e2f9;
        }
    </style>
</head>
<body>
    <canvas height="300" width="600" id="myCanvas"></canvas>
    
    <script>
        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        ctx.fillStyle = "#fd0";
        ctx.fillRect(0,0,150,37.5);
        ctx.fillStyle = "#6c0";
        ctx.fillRect(0,37,150,37.5);
        ctx.fillStyle = "#09f";
        ctx.fillRect(0,75,150,37.5);
        ctx.fillStyle = "#f30";
        ctx.fillRect(0,112,150,37.5);
        ctx.fillStyle = "#fff";
        for(var i=0; i<10; i++){
            ctx.fillStyle = "rgba(255, 255, 255,"+ (i+1)/10 +")";
            for(var j=0; j<4; j++){
                ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5);
            }
        }
        
        //獲取canvas的圖片數據
        var imageData = ctx.getImageData(0, 0, 150, 150); //獲取canvas的繪制區域的像素信息
        var idata = imageData.data;  //真實的像素rgba信息在 data中 
        console.log(idata)
        /*
         idata中的數據是一個數組,每四個分別代表一個像素點的 r g b a 值 ,如下:
         [159,159,159,255,159,159,159,255......]
         R - 紅色 (0-255)
         G - 綠色 (0-255)
         B - 藍色 (0-255)
         A - alpha 通道 (0-255; 0 是透明的,255 是完全可見的)
          */
        
        for(var i=0; i<idata.length; i+=4){
            var avg = (idata[i]+idata[i+1]+idata[i+2])/3;
            idata[i]     = avg; // red
            idata[i + 1] = avg; // green
            idata[i + 2] = avg; // blue
        }
        ctx.putImageData(imageData, 200, 0);

    </script>
</body>
</html>

 

 

 

 

 

今天就講到這里,下節課我們講解:canvas變換 / 路徑保存 / 綜合案例

 

 

關注公眾號,博客更新即可收到推送

 


免責聲明!

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



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