主頁(yè) > 知識(shí)庫(kù) > html5 Canvas畫(huà)圖教程(11)—使用lineTo/arc/bezierCurveTo畫(huà)橢圓形

html5 Canvas畫(huà)圖教程(11)—使用lineTo/arc/bezierCurveTo畫(huà)橢圓形

熱門(mén)標(biāo)簽:高德地圖標(biāo)注錯(cuò)誤怎么修改 江蘇高頻外呼系統(tǒng)線路 洛陽(yáng)市伊川縣地圖標(biāo)注中心官網(wǎng) 平頂山電子地圖標(biāo)注怎么修改 電銷機(jī)器人視頻 地圖標(biāo)注自己去過(guò)的地方 標(biāo)準(zhǔn)智能外呼系統(tǒng) 搜狗星級(jí)酒店地圖標(biāo)注 會(huì)聲會(huì)影怎樣做地圖標(biāo)注效果
在canvas中可以很方便的用arc方法畫(huà)出圓形,本來(lái)圓形也可以看作是一個(gè)寬高相等的橢圓,但canvas中根本沒(méi)有畫(huà)橢圓的方法,我們要用其他方法來(lái)模擬。
我們首先要明確畫(huà)一個(gè)橢圓需要那些參數(shù),基本的幾何知識(shí)告訴我們,橢圓需要圓心坐標(biāo),寬度,高度——或者還有旋轉(zhuǎn)角度,不過(guò)這個(gè)可以暫時(shí)不要,旋轉(zhuǎn)是比較容易的。
1,使用lineTo畫(huà)橢圓
你沒(méi)有看錯(cuò),lineTo這樣一個(gè)純粹用來(lái)畫(huà)直線的方法居然可以用來(lái)畫(huà)橢圓???但他確實(shí)存在,不過(guò)寫(xiě)法實(shí)在是有些不可思議:

復(fù)制代碼
代碼如下:

function DrawEllipse(Canvas,O,OA,OB){
//畫(huà)橢圓,例子:var B=new Array(150,150); DrawEllipse(hb,B,50,30);
with (Canvas){
var x=O[0]+OA;
var y=O[1];
moveTo(x,y);
for (var i=0;i<=360;i++){
var ii=i*Math.PI/180;
var x=O[0]+OA*Math.cos(ii);
var y=O[1]-OB*Math.sin(ii);
lineTo(x,y);
}
}
}

這個(gè)方法的原理是,一個(gè)圓有360度,那么就用lineTo循環(huán)360次,畫(huà)出每一度的線段,最終連成一個(gè)橢圓。其中需要用到三角函數(shù)正弦余弦進(jìn)行計(jì)算。
注意,這個(gè)方法的第2個(gè)參數(shù)是個(gè)數(shù)組,即橢圓的圓心坐標(biāo).

思路很奇葩,而且畫(huà)出的橢圓也比較平滑。但不值得大家使用——此方法每畫(huà)一個(gè)橢圓,就要循環(huán)360次,只有畫(huà)的橢圓稍微一多,對(duì)瀏覽器的性能就是個(gè)考驗(yàn)。
我們只用了解一下他的思路即可
2,使用arc畫(huà)圓,然后把他縮放成一個(gè)橢圓
這個(gè)方法的原文在此,核心函數(shù)如下:

復(fù)制代碼
代碼如下:

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = 0;
var centerY = 0;
var radius = 50;
// save state
context.save();
// translate context
context.translate(canvas.width / 2, canvas.height / 2);
// scale context horizontally
context.scale(2, 1);
// draw circle which will be stretched into an oval
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
context.restore()

此方法用了一個(gè)我前面還沒(méi)講過(guò)的canvas函數(shù),即scale,他能實(shí)現(xiàn)canvas的縮放??s放有水平和垂直兩個(gè)方向,代碼中把canvas水平方向放大了,而垂直方向不變,so,原來(lái)arc畫(huà)出的圓形就變成了一個(gè)橢圓。
這個(gè)方法初看甚妙,代碼少,而且原理淺顯易懂。但分析一下就能發(fā)現(xiàn)他的明顯缺點(diǎn)了,就是——不精確!比如我需要寬171高56的橢圓,此時(shí)我們?nèi)绻補(bǔ)rc的半徑定為28的話,那么后面就要為171/28/2這個(gè)蛋疼的不知所云的數(shù)字郁悶了。

不過(guò)有個(gè)折中的辦法是始終把a(bǔ)rc的半徑設(shè)成100,然后,不夠就放大,超過(guò)了就縮小。但是,還是不精確。
3,使用貝賽爾曲線bezierCurveTo
自從覺(jué)得上面的縮放法不精確后,我就很想找到一個(gè)精確的畫(huà)橢圓的方法,最后在stackoverflow上找到了:

復(fù)制代碼
代碼如下:

function drawEllipse(ctx, x, y, w, h) {
var kappa = 0.5522848;
ox = (w / 2) * kappa, // control point offset horizontal
oy = (h / 2) * kappa, // control point offset vertical
xe = x + w, // x-end
ye = y + h, // y-end
xm = x + w / 2, // x-middle
ym = y + h / 2; // y-middle
ctx.beginPath();
ctx.moveTo(x, ym);
ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
ctx.closePath();
ctx.stroke();
}

這個(gè)方法可以算是比較完美的了。他把一個(gè)橢圓分成了4條貝塞爾曲線,用他們連成了一個(gè)橢圓。最后寬度高度也比較精確,開(kāi)銷也較少。
但此方法依然有缺點(diǎn)。大家看那個(gè)kappa參數(shù),有個(gè)很奇特的值,相信很多人在幾何專家告訴你為什么他要取這個(gè)值之前,都不明白為什么非要取這個(gè)值——我到現(xiàn)在還是不知道。并且我有很強(qiáng)烈的想把他改一下看看有什么后果的沖動(dòng)。

當(dāng)然我這種類似強(qiáng)迫癥患者的沖動(dòng)并不能說(shuō)成是此方法的缺點(diǎn),他真正的缺點(diǎn)是——為什么要用4條貝塞爾曲線?我個(gè)人覺(jué)得,一個(gè)橢圓明顯是由兩條貝塞爾曲線組成的而不是4條。這個(gè)想法最終讓我找到了最完美的畫(huà)橢圓的方法。
 4,使用兩條貝賽爾曲線畫(huà)出橢圓
為了了解上一個(gè)方法能否精簡(jiǎn),我專門(mén)注冊(cè)了一個(gè)stackoverflow的帳號(hào)去提問(wèn),由于問(wèn)題里有圖片,積分不夠不能傳,我還迫不得已用勉勉強(qiáng)強(qiáng)的英語(yǔ)水平去回答老外的問(wèn)題掙積分。但最終好運(yùn)到了,回答一個(gè)問(wèn)題就解決了我的積分問(wèn)題。
我提的貝賽爾曲線和橢圓的關(guān)系的問(wèn)題在此.
說(shuō)實(shí)話,下面老外的回答我大部分沒(méi)看懂,但幸虧他提供了一個(gè)代碼示例頁(yè),讓我明白了原理,在此對(duì)他表示再次的感謝。而根據(jù)他的解答,我找到的畫(huà)橢圓的方法如下:

復(fù)制代碼
代碼如下:

//橢圓
CanvasRenderingContext2D.prototype.oval = function (x, y, width, height) {
var k = (width/0.75)/2,
w = width/2,
h = height/2;
this.beginPath();
this.moveTo(x, y-h);
this.bezierCurveTo(x+k, y-h, x+k, y+h, x, y+h);
this.bezierCurveTo(x-k, y+h, x-k, y-h, x, y-h);
this.closePath();
return this;
}

此方法既精確,又代碼少,而且也沒(méi)有奇怪的難懂的地方。只需要記住這一點(diǎn),橢圓的寬度與畫(huà)出橢圓的貝賽爾曲線的控制點(diǎn)的坐標(biāo)比例如下:
貝塞爾控制點(diǎn)x=(橢圓寬度/0.75)/2這一點(diǎn)已經(jīng)在代碼中體現(xiàn)了。

大家可自行試驗(yàn)上面的4個(gè)方法畫(huà)出橢圓。
如果你發(fā)現(xiàn)了更簡(jiǎn)單的方法,也請(qǐng)分享出來(lái)大家探討吧。

標(biāo)簽:蚌埠 松原 廣東 果洛 鄂爾多斯 常德 阿克蘇 廣西

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《html5 Canvas畫(huà)圖教程(11)—使用lineTo/arc/bezierCurveTo畫(huà)橢圓形》,本文關(guān)鍵詞  html5,Canvas,畫(huà)圖,教程,使用,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《html5 Canvas畫(huà)圖教程(11)—使用lineTo/arc/bezierCurveTo畫(huà)橢圓形》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于html5 Canvas畫(huà)圖教程(11)—使用lineTo/arc/bezierCurveTo畫(huà)橢圓形的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章