html5 Canvas画图实例教程(11)—应用lineTo/arc/bezierC

日期:2020-12-11 类型:科技新闻 

关键词:如何制作微信小程序,微信小程序源码,小程序码生成,凡科网微信小程序,微信公众号小程序

在canvas中能够很便捷的用arc方式画出圆形,原本圆形还可以看做是1个宽高相同的椭圆,但canvas中压根沒有画椭圆的方式,大家要用别的方式来仿真模拟。
大家最先要确立画1个椭圆必须那些主要参数,基础的几何图形专业知识告知大家,椭圆必须圆心座标,宽度,高宽比——或也有转动角度,但是这个能够临时不必,转动是较为非常容易的。
1,应用lineTo画椭圆
你沒有看错,lineTo这样1个纯碎用来画平行线的方式竟然能够用来画椭圆!?但他的确存在,但是写法确实是一些不能思议:

拷贝编码
编码以下:

function DrawEllipse(Canvas,O,OA,OB){
//画椭圆,事例: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);
}
}
}

这个方式的基本原理是,1个圆有360度,那末就用lineTo循环系统360次,画出每度的直线,最后连成1个椭圆。在其中必须用到3角涵数正弦余弦开展测算。
留意,这个方式的第2个主要参数是个数字能量数组,即椭圆的圆心座标.

思路很奇葩,并且画出的椭圆也较为光滑。但不值得得大伙儿应用——此方式每画1个椭圆,就要循环系统360次,仅有画的椭圆略微1多,对访问器的特性便是个考验。
大家只用掌握1下他的思路便可
2,应用arc画圆,随后把他放缩成1个椭圆
这个方式的原文在此,关键涵数以下:

拷贝编码
编码以下:

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

此方式用了1个我前面还没讲过的canvas涵数,即scale,他能完成canvas的放缩。放缩有水平静竖直两个方位,编码中把canvas水平方位变大了,而竖直方位不会改变,so,原先arc画出的圆形就变为了1个椭圆。
这个方式初看甚妙,编码少,并且基本原理粗浅易懂。但剖析1下就可以发现他的显著缺陷了,便是——不精准!例如我必须宽171高56的椭圆,此时大家假如把arc的半径定为28的话,那末后边就要为171/28/2这个蛋疼的不知道所云的数据烦闷了。

但是有个折衷的方法是自始至终把arc的半径设成100,随后,不足就变大,超出了就变小。可是,還是不精准。
3,应用贝赛尔曲线图bezierCurveTo
自从感觉上面的放缩法不精准后,我就很想寻找1个精准的画椭圆的方式,最终在stackoverflow上寻找了:

拷贝编码
编码以下:

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

这个方式能够算是较为完善的了。他把1个椭圆分为了4条贝塞尔曲线图,用她们连变成1个椭圆。最终宽度高宽比也较为精准,花销也较少。
但此方式仍然有缺陷。大伙儿看那个kappa主要参数,有个很独特的值,坚信许多人在几何图形权威专家告知你为何他要取这个值以前,都不搞清楚为何非要取这个值——我到如今還是不知道道。而且我有很明显的想把他改1下看看有甚么不良影响的欲望。

自然我这类相近逼迫症病人的欲望其实不能说成是此方式的缺陷,他真实的缺陷是——为何要用4条贝塞尔曲线图?我本人感觉,1个椭圆显著是由两条贝塞尔曲线图构成的而并不是4条。这个念头最后让我寻找了最完善的画椭圆的方式。
 4,应用两条贝赛尔曲线图画出椭圆
以便掌握上1个方式能否精简,我专业申请注册了1个stackoverflow的帐号去发问,因为难题里有照片,積分不足不可以传,我还不得已用勉凑合强的英语水平去回应老外的难题挣積分。但最后好运气到了,回应1个难题就处理了我的積分难题。
我提的贝赛尔曲线图和椭圆的关联的难题在此.
说真话,下面老外的回应我绝大多数没看懂,但多亏他出示了1个编码示例页,让我搞清楚了基本原理,在此对他表明再度的谢谢。而依据他的解答,我寻找的画椭圆的方式以下:

拷贝编码
编码以下:

//椭圆
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;
}

此方式既精准,又编码少,并且也沒有怪异的晦涩难懂的地区。只必须记牢这1点,椭圆的宽度与画出椭圆的贝赛尔曲线图的操纵点的座标占比以下:
贝塞尔操纵点x=(椭圆宽度/0.75)/2这1点早已在编码中反映了。

大伙儿可自主实验上面的4个方式画出椭圆。
假如你发现了更简易的方式,也请共享出来大伙儿讨论吧。