<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          canvas繪圖詳解筆記之線條及線條屬性

          共 8418字,需瀏覽 17分鐘

           ·

          2021-03-01 10:29

          來源 | https://www.cnblogs.com/jr1993/p/4687877.html



          創(chuàng)建 canvas

          首先創(chuàng)建一個(gè)canvas元素,我們只需要在html文件中加入這么一句代碼:

          <canvas id="canvas">當(dāng)前瀏覽器不支持canvas,請(qǐng)更換瀏覽器使用!</canvas>

          同時(shí)我們也可以通過canvas的標(biāo)簽屬性width和height設(shè)置canvas畫布的大?。?/p>

          <canvas id="canvas" width="800" height="800">當(dāng)前瀏覽器不支持canvas,請(qǐng)更換瀏覽器使用!</canvas>

          當(dāng)然,我們也可以通過js來設(shè)置canvas的寬高,下文會(huì)提到如何設(shè)置。

          接下來我們就在js中獲取到該canvas元素,然后設(shè)置它的寬高,并獲取到上下文的環(huán)境:

          var canvas = document.getElementById("canvas");//獲取到canvas元素//設(shè)置寬高canvas.width = 800;canvas.height = 800;var context = canvas.getContext("2d");//獲取上下文的環(huán)境

          接下來我們的所有操作都是基于這個(gè)context的上下文環(huán)境。

          現(xiàn)在畫一條簡(jiǎn)單的直線:

          context.moveTo(100,100);context.lineTo(500,500);

          moveTo()方法表示一次繪制的起點(diǎn)坐標(biāo),lineTo()表示基于上一個(gè)坐標(biāo)點(diǎn)到這個(gè)坐標(biāo)點(diǎn)之間的直線連接。

          注意的是,canvas是基于狀態(tài)的繪制,而不是基于對(duì)象的繪制。所以,上面代碼都是狀態(tài)的設(shè)置,我們還需要使用stroke()方法進(jìn)行繪制:

          context.stroke();//繪制

          除此之外,我們還可以設(shè)置線條的一些基本屬性:
          context.lineWidth = 8;//線條的寬度context.strokeStyle = "#333";//線條的顏色

          一個(gè)簡(jiǎn)單的繪制一條直線的完整例子:

          var canvas = document.getElementById("canvas");//獲取到canvas元素//設(shè)置寬高canvas.width = 800;canvas.height = 800;var context = canvas.getContext("2d");//獲取上下文的環(huán)境//canvas 是基于狀態(tài)的繪制,而不是對(duì)象context.moveTo(100,100);context.lineTo(500,500);context.lineWidth = 8;//線條的寬度context.strokeStyle = "#333";//線條的顏色context.stroke();//繪制

          運(yùn)行結(jié)果如下圖:

          接下來我們繪制一個(gè)連續(xù)折線:
          context.moveTo(100,100);context.lineTo(500,100);context.lineTo(500,500);context.lineTo(100,500);

          運(yùn)行結(jié)果如下:

          如果我們想要讓這個(gè)折線閉合形成一個(gè)矩形的話,可以再設(shè)置context.lineTo(100,100);然而如果線條的寬度比較大的時(shí)候,就會(huì)出現(xiàn)一些瑕疵,這個(gè)的話大家自己試試看。所以標(biāo)準(zhǔn)的話應(yīng)該使用context.closePath();這個(gè)知識(shí)點(diǎn)后面會(huì)講到,這里大家可以先試試,看看運(yùn)行結(jié)果是怎么樣的。

          上面這個(gè)簡(jiǎn)單的例子我們是連續(xù)繪制的折線,也就是說可以一筆連續(xù)畫完的折線。如果是多條間斷的折線,那么我們就需要使用context.moveTo()來重新繪制一條折線的起點(diǎn)坐標(biāo):

          context.moveTo(100,200);context.lineTo(300,400);context.lineTo(100,600);
          context.moveTo(300,200);context.lineTo(500,400);context.lineTo(300,600);
          context.moveTo(500,200);context.lineTo(700,400);context.lineTo(500,600);

          運(yùn)行結(jié)果如下:

          此時(shí),如果我們想要繪制的這三條折線是不同顏色的,那該怎么辦?一種常見的錯(cuò)誤用法就是:

          context.moveTo(100,200);context.lineTo(300,400);context.lineTo(100,600);context.lineWidth = 8;context.strokeStyle = "red";context.stroke();//繪制
          context.moveTo(300,200);context.lineTo(500,400);context.lineTo(300,600);context.lineWidth = 8;context.strokeStyle = "green";context.stroke();//繪制
          context.moveTo(500,200);context.lineTo(700,400);context.lineTo(500,600);context.lineWidth = 8;context.strokeStyle = "blue";context.stroke();//繪制

          運(yùn)行結(jié)果會(huì)是三條折線都是藍(lán)色的。因?yàn)檫@里的第二條折線的strokeStyle屬性會(huì)覆蓋第一條折線的strokeStyle屬性,而stroke()方法的執(zhí)行會(huì)繪制當(dāng)前所有的狀態(tài),所以第一條折線就變成綠色。同理,最終三條折線就都是藍(lán)色。因此呢,這里就需要使用beginPath()方法來重新進(jìn)行一次全新的繪制。

          context.lineWidth = 8;//線條的寬度context.beginPath();context.moveTo(100,200);context.lineTo(300,400);context.lineTo(100,600);context.strokeStyle = "red";context.stroke();//繪制
          context.beginPath();context.moveTo(300,200);context.lineTo(500,400);context.lineTo(300,600);context.strokeStyle = "green";context.stroke();//繪制
          context.beginPath();context.moveTo(500,200);context.lineTo(700,400);context.lineTo(500,600);context.strokeStyle = "blue";context.stroke();//繪制

          這里在每繪制一條折線的時(shí)候,都使用beginPath()方法來進(jìn)行一次全新的路徑繪制。此時(shí)再使用stroke()方法進(jìn)行繪制的時(shí)候,就只會(huì)繪制beginPath()方法下面的狀態(tài)。運(yùn)行結(jié)果如下:

          從上面的代碼我們可以看到:context.lineWidth = 8;放在了最前面,這是因?yàn)閎eginPath()方法不會(huì)將沒有修改的屬性變成默認(rèn)值。比如這里的lineWidth,三條折線都是8,那么我們放在前面的話,在進(jìn)行stroke()方法進(jìn)行繪制的時(shí)候,都是會(huì)使用lineWidth = 8;來進(jìn)行繪制。而需要修改的屬性則在具體的路徑繪制里進(jìn)行修改,比如這里的線條顏色屬性,每條折線的顏色都不一樣,所以就需要各自設(shè)置。

          還有一點(diǎn)就是:此段代碼中的moveTo()方法可以改成lineTo()方法:

          context.lineWidth = 8;//線條的寬度context.beginPath();context.lineTo(100,200);context.lineTo(300,400);context.lineTo(100,600);context.strokeStyle = "red";context.stroke();//繪制

          因?yàn)槭褂昧薭eginPath()方法,就會(huì)對(duì)之前繪制的路徑進(jìn)行清空,但不會(huì)回到(0,0)原點(diǎn)。所以這里我們直接使用lineTo()方法同樣能起到繪制起點(diǎn)的作用,但必須和beginPath()方法一起使用才能替換moveTo()方法。

          上面曾簡(jiǎn)單講過context.closePath()方法,這里將具體展開介紹:context.closePath()方法和context.beginPath()方法一起使用,以繪制閉合的路徑圖形,這是繪制封閉多邊形的標(biāo)準(zhǔn)做法。而且使用context.closePath()方法,最后一條線的繪制可以省略,它會(huì)自動(dòng)幫我們連接到繪制起點(diǎn)以形成封閉的多邊形。

          context.beginPath();context.moveTo(100,100);context.lineTo(500,100);context.lineTo(500,500);context.lineTo(100,500);context.closePath();context.lineWidth = 8;context.strokeStyle = "#333";context.stroke();

          運(yùn)行結(jié)果如下:

          接下來我們介紹一下填充屬性fillStyle和填充繪制方法fill():


          context.beginPath();context.moveTo(100,100);context.lineTo(500,100);context.lineTo(500,500);context.lineTo(100,500);context.closePath();context.lineWidth = 8;context.strokeStyle = "#333";context.stroke();context.fillStyle = "red";   //填充顏色context.fill(); //填充

          最后兩行代碼就是設(shè)置了填充的顏色(紅色)和進(jìn)行閉合圖形的顏色填充,運(yùn)行結(jié)果如下:

          可以看到圖形的邊框?qū)挾缺葲]有填充顏色的圖形的邊框?qū)挾刃。@是因?yàn)槲覀兿壤L制邊框,再填充顏色。而實(shí)際上應(yīng)該是先填充顏色,再繪制邊框。而且fill()方法和stroke()方法的原理是一樣的,都是基于當(dāng)前狀態(tài)進(jìn)行繪制。所以,為了可讀性,我們可以將屬性設(shè)置放在一起,最后在使用fill()和stroke()方法:

          context.beginPath();context.moveTo(100,100);context.lineTo(500,100);context.lineTo(500,500);context.lineTo(100,500);context.closePath();context.lineWidth = 8;context.strokeStyle = "#333";context.fillStyle = "red";
          context.fill(); //先填充context.stroke(); //再繪制邊框

          這次的運(yùn)行結(jié)果:

          可以看到,這次的結(jié)果就是正確的了。

          對(duì)于繪制矩形這個(gè)很常用,那么我們就可以封裝成函數(shù),方便以后調(diào)用:

          drawRect(context,100,100,400,400,8,"#333","blue");
          function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){ cxt.beginPath(); cxt.moveTo(x,y); cxt.lineTo(x+width,y); cxt.lineTo(x+width,y+height); cxt.lineTo(x,y+height); cxt.closePath(); cxt.lineWidth = borderWidth; cxt.strokeStyle = borderColor; cxt.fillStyle = fillColor; cxt.fill(); cxt.stroke(); }

          同樣的,運(yùn)行結(jié)果也是正常的:

          但是呢,canvas API 提供了繪制矩形更加方便的方法:rect()方法用于規(guī)劃矩形的路徑,fillRect()方法在規(guī)劃了矩形的路徑之后還填充了矩形的顏色,而strokeRect()方法則繪制了矩形的邊框。

          所以上面的函數(shù)若使用context.rect()方法可以簡(jiǎn)化為:
          function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){    cxt.beginPath();    cxt.rect(x,y,width,height);    cxt.closePath();    cxt.lineWidth = borderWidth;    cxt.strokeStyle = borderColor;    cxt.fillStyle = fillColor;    cxt.fill(); //先填充    cxt.stroke(); //再繪制邊框}
          而使用fillRect()和strokeRect()這兩個(gè)方法則可以更加簡(jiǎn)單就實(shí)現(xiàn):
          function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){    cxt.lineWidth = borderWidth;    cxt.strokeStyle = borderColor;    cxt.fillStyle = fillColor;    cxt.fillRect(x,y,width,height);    cxt.strokeRect(x,y,width,height);}

          此時(shí)如果我們繪制了兩個(gè)矩形:

          drawRect(context,100,100,400,400,8,"#333","blue");drawRect(context,300,300,400,400,8,"#333","red");

          運(yùn)行結(jié)果是這樣的:

          可以看到,后繪制的矩形會(huì)蓋在前繪制的矩形之上,當(dāng)然得顏色不同才體現(xiàn)出來。

          此時(shí)我們將第二個(gè)矩形的填充顏色改一下:

          drawRect(context,300,300,400,400,8,"#333","rgba(255,0,0,0.5)");

          結(jié)果如下:

          可以看到第二個(gè)矩形的填充顏色是半透明的紅色。那么就需要說明一下:fillStyle 和 strokeStyle 屬性的顏色值可以是CSS3支持的任何一種形式:

          #ffffff#333redrgb(0,0,0)rgba(255,0,0,0.5)hsl(20,50%,50%)hsla(20,50%,60%,0.6)

          線段還有其他一些屬性,接下來分別講解:

          lineCap屬性就是定義線段開頭和結(jié)尾處的形狀,此屬性有三個(gè)屬性值:butt(默認(rèn)值),round,square 。

          通過代碼來演示這三種效果:

          context.lineWidth = 50;context.strokeStyle = "#005588";
          context.beginPath();context.moveTo(100,200);context.lineTo(700,200);context.lineCap = "butt";context.stroke();
          context.beginPath();context.moveTo(100,400);context.lineTo(700,400);context.lineCap = "round";context.stroke();
          context.beginPath();context.moveTo(100,600);context.lineTo(700,600);context.lineCap = "square";context.stroke();

          這里畫了三條線段,分別設(shè)置了不同的lineCap屬性值,看看有什么不同:

          從結(jié)果可以看出來,使用round屬性值會(huì)比默認(rèn)值butt多出一個(gè)半圓的形狀包在線段的開始和結(jié)尾處,而是用square屬性值會(huì)在開始和結(jié)尾處多處半個(gè)方形,這就是它們的不同之處。其中,round對(duì)于我們繪制一些圓角效果的圖形比較有用,但是它只對(duì)線條的開頭和結(jié)尾處有效果,對(duì)于線段之間的連接處沒有作用,這點(diǎn)需要注意。

          接下來我們來繪制一個(gè)五角星:

          先看一下效果圖:

          我們要繪制一個(gè)這樣的五角星,其實(shí)就是要繪制出十個(gè)頂點(diǎn),而且這十個(gè)頂點(diǎn)是有規(guī)律可循的:

          從這個(gè)圖可以看到,五角星的十個(gè)頂點(diǎn)可以分成兩組,分別在外圓和內(nèi)圓上的五個(gè)頂點(diǎn),通過數(shù)學(xué)公式可以得知:a是18度,b是36度,故a+b=54度,有了一個(gè)角的度數(shù),還有大小圓的半徑,就可以根據(jù)三角函數(shù)公式求出頂點(diǎn)的坐標(biāo)了,而且大小圓上的每個(gè)頂點(diǎn)之間的度數(shù)都是相差72度,那么我們就可以使用函數(shù)來繪制這個(gè)五角星:

          context.lineWidth = 10;context.strokeStyle = "#005588";drawStar(context,150,300,400,400,0);context.stroke();
          function drawStar(cxt,r,R,x,y,rotate){ cxt.beginPath(); for(var i = 0; i < 5; i++){ cxt.lineTo(Math.cos((18 + i*72 - rotate)/180*Math.PI)*R + x, -Math.sin((18 + i*72 - rotate)/180 * Math.PI)*R + y); cxt.lineTo(Math.cos((54 + i*72 - rotate)/180*Math.PI)*r + x, -Math.sin((54 + i*72 - rotate)/180 * Math.PI)*r + y); } cxt.closePath();}

          至于這里面的公式,大家就自己想一下吧,其實(shí)就是正弦和余弦函數(shù)。drawStar()方法的參數(shù)分別是上下文環(huán)境,小圓半徑,大圓半徑,偏移量x,偏移量y,旋轉(zhuǎn)角度。

          最后還有兩個(gè)線條的屬性:lineJoin 和 miterLimit

          lineJoin顧名思義就是線條與線條之間的連接方式,該屬性有三個(gè)屬性值:miter(默認(rèn)值,尖角),bevel(銜接),round(圓角)。

          我們基于上面的五角星的例子,分別設(shè)置不同的lineJoin屬性值,看看有什么不同:

          context.lineJoin = "bevel";

          context.lineJoin = "round";

          這些細(xì)微的差別還是大家自己試一下才有比較直觀的感受,更能理解其中的用法。

          還有一個(gè)miterLimit屬性,這個(gè)屬性只有當(dāng)lineJoin屬性值是miter時(shí)才有用,默認(rèn)值是10 。那么它到底是什么呢?

          我們通過代碼來演示:

          context.lineWidth = 10;context.strokeStyle = "#005588";context.lineJoin = "miter";drawStar(context,30,300,400,400,0);context.stroke();

          我們將小圓的半徑設(shè)置得比較小,此時(shí)我們的lineJoin是miter,即尖角。那么結(jié)果會(huì)是怎么樣的呢?

          可以看到它畢竟變成bevel連接方法了,這就是miterLimit屬性的影響,那么它究竟怎么計(jì)算的呢?看下圖:

          可以看到,它的計(jì)算還是比較復(fù)雜的,所以canvas給我們一個(gè)經(jīng)驗(yàn)值,也就是10,當(dāng)然自己也可以修改miterLimit的值,得到自己想要的結(jié)果。


          本文完?

          瀏覽 14
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜免费无码 | 国产无码精彩视频 | 乱伦免费小说黄色电影 | 探花 的搜索结果 - 91n | 国产精品久久久久久最猛 |