DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> HTML基礎知識 >> HTML5教程 >> canvas API ,通俗的canvas基礎知識(三)
canvas API ,通俗的canvas基礎知識(三)
編輯:HTML5教程     

全文說到了三角形,圓形等相關圖形的畫法,不熟悉的同學可以出門右轉,先看看前文,接下來繼續我們的圖形——曲線。

學過數學,或者是比較了解js 的同學都知道貝塞爾曲線,當然,在數學裡面,這是一門高深的學問,js裡面的貝塞爾曲線一般是用來做動畫的,其實別的地方也有體現,比如說Photoshop裡面的鋼筆工具,CorelDraw裡面的貝塞爾工具等等,canvas中,也是有體現的

當然,如果是單純的畫一條曲線,也可以用前面的方法:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
    
ctx.arc(100,100,100,0,90*Math.PI/180,false);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(103,103);
ctx.arcTo(183,83,162,182,40);
ctx.stroke();

如果要畫一個彎彎曲曲的線條就費勁了,這才有下面的主角登場:

quadraticCurveTo(cpx,cpy,x,y)  二次貝塞爾曲線

參數:cpx,cpy 表示第一個控制點,x,y 表示結束點

加上起點,就是3個點控制一條曲線,其實這個跟arcTo的用法差不多,不同的地方就是arcTo是需要指定圓弧的半徑的,因為它是2條線中畫一個圓與直線的切點形成的曲線,那這個二次貝塞爾曲線的畫圖原理是什麼呢?咱們一起來畫一畫:

二次貝塞爾曲線的大致規律:從起始點出發,曲線越靠近控制點,曲線越陡,然後慢慢遠離控制點,曲線隨即越來越平緩,直到結束點,並且此曲線會與起始點和結束點相切

這個控制點是不是有點像一個磁鐵一樣,吸引著這條曲線的運動,俗話說耳聞不如一見,咱們試一下:

ctx.moveTo(50,50);
ctx.lineTo(70,120);
ctx.lineTo(200,80);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(50,50);
ctx.quadraticCurveTo(70,120,200,80);
ctx.stroke();

 

    

看看,是不是這樣的,當然,曲線彎曲的程度是多少是有公式的,但是我們不需要關心,只需要記住一點就夠了:曲線靠近控制點,曲線越陡,遠離控制點,曲線越平,哦了!

再次提示一下,arcTo與quadraticCurveTo的區別,現在是否明白?

現在我們來介紹一下三次貝塞爾曲線:

bezierCurveTo(cpx1,cpy1,cpx2,cpy2,x,y)  三次貝塞爾曲線

參數:cpx1,cpy1表示第一個控制點,cpx2,cpy2表示第二個控制點  x,y表示結束點

包括起始點一起4個點來決定一條曲線,這個跟二次貝塞爾曲線的原理是一樣一樣的,只是多一個控制點,其精髓還是那句話:曲線靠近控制點,曲線越陡,遠離控制點,曲線越平

先來一個簡單的例子吧(來個U形):

ctx.moveTo(20,20);
ctx.bezierCurveTo(20,100,200,100,200,20);
ctx.stroke();

   

如上圖,第一張是效果圖,第二張是原理圖,曲線從起始點開始,下方有一個控制點,則曲線越陡,到第二個控制點與曲線的切線的點的位置,因為受2個控制點的影響,曲線開始慢慢變平緩,因為2控制點剛好對稱,所以到中間點,曲線出於水平,然後繼續受2個控制點的作用,其中第二個控制點的作用越來越大,知道第一個控制點與曲線的切線點位置,曲線繼續受到第二個控制點的作用,反向受力,到結束點,額,聽不懂,好吧,不懂就不懂吧,記住那句總結性的話就行了!

其經典例子莫過於正弦圖(用2個貝塞爾曲線,一個正U一個反U):

ctx.beginPath();
ctx.moveTo(20,150);
ctx.bezierCurveTo(20,50,150,50,150,150);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(150,150);
ctx.bezierCurveTo(150,250,280,250,280,150);
ctx.stroke();

   

當然,三次貝塞爾曲線不知道能畫U形圖,而是任意曲線都能畫,只有你想不到,沒有畫不了的,哈哈,腦洞打大一下吧!

 

都說作畫作畫的,不能老是做水墨畫啊,我喜歡顏色,五彩缤紛的顏色,恩,canvas也是可以的,canvas和css3一樣都可以設置漸變,這樣一來,看到彩虹是不是就不遠了,嘻嘻

我們先看看css3的漸變是怎麼設置的,然後對比一下canvas的漸變,我們都知道漸變分為線性漸變和徑向漸變,我們一一來比較:

線性漸變:

.box1{
    width:500px;
    height:50px;
    background: -webkit-linear-gradient(left, red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%);
}

css3可以指定顏色,支持各種顏色格式,且可以指定顏色所在位置,不僅如此,css3還可以指定漸變的方向:

.box1{
    width:500px;
    height:50px;
    background: -webkit-linear-gradient(45deg , red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%);
}

方向可以用角度來定義,45度角是從左下到右上進行漸變

徑向漸變:

.box2{
    width:300px;
    height:200px;
    background:-webkit-radial-gradient(red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%);
}

   漸變原點為中心,漸變顏色為百分百之間的顏色漸變

可以看出,徑向漸變是以中心為原點,一圈一圈向外擴散,同樣支持自定義顏色,支持各種顏色格式,支持指定位置,也是可以設置原點和漸變方式(圓形,橢圓):

.box2{
    width:300px;
    height:200px;
    background:-webkit-radial-gradient(bottom left, ellipse,red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%);
}

  原點左下,漸變形狀為橢圓

.box2{
    width:300px;
    height:200px;
    background:-webkit-radial-gradient(bottom left, circle,red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%);
}

    原點左下,漸變形狀為圓形

 

以上只是簡單列舉一下css3的漸變樣式,當然css3的漸變肯定不止這些,這裡主要是想對比一下canvas的漸變樣式,順便科普一下!

canvas的漸變相對要簡單一些,沒有那麼多的花花腸子:

createLinearGradient(x1,y1,x2,y2)   創建線性漸變

參數:x1,y1 表示漸變起始點   x2,y2 表示漸變結束點

createRadialGradient(x1,y1,r1,x2,y2,r2)  創建徑向漸變

參數:x1,y1 表示漸變開始圓心坐標,r1表示漸變開始圓的半徑  x2,y2 表示漸變結束圓心坐標,r2表示漸變結束圓的半徑 

gradient.addColorStop(stop,color)  規定gradient 對象中的顏色和位置

參數: stop 取值0-1之間,表示漸變中開始與結束之間的位置   color表示漸變顏色

注意,這裡添加漸變顏色的對象並不是context,而是gradient

怎麼用呢?看線性漸變一個小例子:

這個科普一個誤區:

ctx.fillRect(50,50,200,50);
var line = ctx.createLinearGradient(50,50,200,50);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');

 

這樣是錯誤的,什麼都出不來!

照理說,應該是先創建一個圖像,然後給這個圖形加漸變色,一般的規律都如此,比如畫畫,比如css,但是canvas不一樣,重點來了:canvas凡是設置樣式的,必須放在繪圖前面 ,怎麼理解這句話?

繪圖的方法: fill() , fillRect() , stroke() , strokeRect() , rect() 

那設置:比如文字類字體,字體大小,字體顏色,字體陰影,漸變色  路徑類如線條,矩形,圓形,背景,漸變等等

所以正確的格式是:

var line = ctx.createLinearGradient(50,50,200,50);
        line.addColorStop(0,'red');
        line.addColorStop(0.2 ,'#0F0');
        line.addColorStop(0.5 ,'rgb(51,102,255)');
        line.addColorStop(1 ,'rgba(204,255,0,0.8)');
        
        ctx.fillStyle = line;
        ctx.fillRect(50,50,200,50);

可以看到canvas一樣可以自定義顏色,支持各種顏色格式,支持指定位置(用0-1的數,跟百分比類似),相比css3之下,我覺得canvas的漸變顏色區域更加准確!

好了,既然canvas能像css3一樣設置漸變樣式,那可不可以設置方向呢?怎麼設?以上面的代碼為例,我們畫一張圖:

圖可能畫的有點蒙啊,解釋一下,第一張圖表示我們上面的代碼顯示的效果,漸變方向是(50,50)——> (200,50),是一條水平線,表示方向是從左到右漸變,要是我將坐標方向設為(50,50)——> (200,100),如第二張圖,那麼漸變是否是從左上角到右下角呢?我們試一下:

var line = ctx.createLinearGradient(50,50,200,100);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
        
ctx.fillStyle = line;
ctx.fillRect(50,50,200,50);

        

可以看出角度是正確的,createLinearGradient的2個坐標就是為了指明漸變方向的,那麼canvas的徑向漸變會不會跟css3相同呢?我們寫一個小例子:

var line = ctx.createRadialGradient(150,150,0,150,150,200);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
        
ctx.fillStyle = line;
ctx.fillRect(50,50,200,150);

可以看到,如果圖形即使不是一個正方形,徑向漸變的圓依然是正圓,與css3的漸變機制有點不一樣(css3是橢圓,看上面的css3圖),並且漸變區域是根據兩個圓來決定的,我們改一下這2個圓的區域看看:

var line = ctx.createRadialGradient(150,150,50,150,150,100);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
        
ctx.fillStyle = line;
ctx.fillRect(50,50,200,150);

比對上面的圖可以看出,下圖在50-100的區間裡是有漸變的,其他地方則是首尾的顏色填充,那麼圓心在邊角上呢?

var line = ctx.createRadialGradient(50,50,0,50,50,200);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
        
ctx.fillStyle = line;
ctx.fillRect(50,50,200,150);

效果跟css3的樣式一樣,顏色更加准確,如果2圓的圓心不一樣,會有什麼反應?

var line = ctx.createRadialGradient(50,50,0,150,150,200);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
        
ctx.fillStyle = line;
ctx.fillRect(50,50,200,150);

 

一個圓心在左上角,一個圓心在中間

咦,什麼鬼,算了,如果想要正常的徑向漸變,還是同圓心吧,不同圓心太詭異,hold 不住啊!

那徑向漸變能像css3一樣可以設置橢圓嗎?咳咳,我只能借用一句台詞:臣妾做不到啊!

我們來一個炫酷的漸變應用:

ctx.font = "40px 微軟雅黑";
var line = ctx.createLinearGradient(10,100,200,100);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
ctx.fillStyle = line;
ctx.fillText("狂拽炫酷吊炸天",10,100);

下面我們介紹另外一個與顏色有關的屬性——透明!

globalAlpha = num    參數:num取值0-1之間   設置或返回繪圖的當前透明值

有同學會問,按這個詞的意思是全局透明,那麼它是全局的嗎?我也想問,那我們試一下:

ctx.fillStyle = "red";
ctx.fillRect(50,50,100,100);
ctx.globalAlpha = 0.5;
ctx.fillStyle = "green";
ctx.fillRect(100,100,100,100);
ctx.fillStyle = "blue";
ctx.fillRect(150,150,100,100);

可以看到,第一個沒有變透明,後面2個變透明了,那麼如果我將路徑閉合,是否還會出現這樣的效果:

ctx.beginPath();
ctx.fillStyle = "red";
ctx.fillRect(50,50,100,100);
ctx.closePath();
        
ctx.globalAlpha = 0.5;
        
ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(100,100,100,100);
ctx.closePath();
        
ctx.beginPath();
ctx.fillStyle = "blue";
ctx.fillRect(150,150,100,100);
ctx.closePath();

 

結果是一樣的,說明它是”人“如其名啊,果然是全局的,那麼將它放入閉合路徑中,會污染其他的路徑嗎?

ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.fillStyle = "red";
ctx.fillRect(50,50,100,100);
ctx.closePath();

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(100,100,100,100);
ctx.closePath();
        
ctx.beginPath();
ctx.fillStyle = "blue";
ctx.fillRect(150,150,100,100);
ctx.closePath();

馬蛋,簡直是嚴重的核污染啊,穿透力如此之強?如果我只想讓第一個透明,後面的不透明?我要怎麼弄呢?

為了解決這個問題,我們需要引入2個方法,同樣是一對活寶啊:

context.save()   保存當前環境的狀態

context.restore() 返回之前保存過的路徑狀態和屬性

怎麼理解這對活寶呢?

可以這麼理解:當設置了save()方法,就相當於將後面的繪圖放在一個堆棧中,與世隔絕,知道看到restore(),就返回到原來的位置,舉個例子哈,就像是一堆糖果,save()就是將一部分糖果裝進盒子,restore()就是封閉盒子,繼續撿糖果,但是盒子裡的糖果就不會與其他糖果混合了,恩,可以這麼理解,特別注意的是,restore()方法必須要有save()才起作用,你想啊,都沒有盒子裝糖果,怎麼能封閉盒子呢

那咱們來看看他們的神奇技能:

ctx.save();
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.fillStyle = "red";
ctx.fillRect(50,50,100,100);
ctx.closePath();
ctx.restore();

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(100,100,100,100);
ctx.closePath();
        
ctx.beginPath();
ctx.fillStyle = "blue";
ctx.fillRect(150,150,100,100);
ctx.closePath();

哎呀,瞬間覺得整個世界都完美了!在面對凶悍的全局變量,屬性或方法時,我們可以用上面的這對活寶來避免它們對我們需要的部分的侵害(這裡為什麼要說侵害,會讓人想污的),確實是好技能!

回到globalAlpha,它的用處還是有很多的,路徑,圖形,文字都可以設置透明,那我們來一個文字透明看看:

ctx.font = "40px 微軟雅黑";
var line = ctx.createLinearGradient(10,100,200,100);
line.addColorStop(0,'red');
line.addColorStop(0.2 ,'#0F0');
line.addColorStop(0.5 ,'rgb(51,102,255)');
line.addColorStop(1 ,'rgba(204,255,0,0.8)');
ctx.fillStyle = line;
ctx.globalAlpha = 0.3;
ctx.fillText("狂拽炫酷吊炸天",10,100);

恩,今天就介紹到這裡吧,後面的內容比較復雜,需要認真的准備,就這樣吧!

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved