头闻号

广州市曼博瑞材料科技有限公司

防伪技术产品|其他未分类|防伪包装

首页 > 新闻中心 > 科技常识:html5 Canvas画图教程(11)―使用lineTo/arc/bezierCurveTo画椭圆形
科技常识:html5 Canvas画图教程(11)―使用lineTo/arc/bezierCurveTo画椭圆形
发布时间:2024-11-18 22:25:09        浏览次数:3        返回列表

今天小编跟大家讲解下有关html5 Canvas画图教程(11)―使用lineTo/arc/bezierCurveTo画椭圆形 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关html5 Canvas画图教程(11)―使用lineTo/arc/bezierCurveTo画椭圆形 的相关资料,希望小伙伴们看了有所帮助。

在canvas中可以很方便的用arc方法画出圆形 本来圆形也可以看作是一个宽高相等的椭圆 但canvas中根本没有画椭圆的方法 我们要用其他方法来模拟。 我们首先要明确画一个椭圆需要那些参数 基本的几何知识告诉我们 椭圆需要圆心坐标 宽度 高度——或者还有旋转角度 不过这个可以暂时不要 旋转是比较容易的。 1,使用lineTo画椭圆 你没有看错 lineTo这样一个纯粹用来画直线的方法居然可以用来画椭圆! 但他确实存在 不过写法实在是有些不可思议: 复制代码代码如下: 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); } } } 这个方法的原理是 一个圆有360度 那么就用lineTo循环360次 画出每一度的线段 最终连成一个椭圆。其中需要用到三角函数正弦余弦进行计算。 注意 这个方法的第2个参数是个数组 即椭圆的圆心坐标. 思路很奇葩 而且画出的椭圆也比较平滑。但不值得大家使用——此方法每画一个椭圆 就要循环360次 只有画的椭圆稍微一多 对浏览器的性能就是个考验。 我们只用了解一下他的思路即可 2,使用arc画圆 然后把他缩放成一个椭圆 这个方法的原文在此 核心函数如下: 复制代码代码如下: 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() 此方法用了一个我前面还没讲过的canvas函数 即scale 他能实现canvas的缩放。缩放有水平和垂直两个方向 代码中把canvas水平方向放大了 而垂直方向不变 so,原来arc画出的圆形就变成了一个椭圆。 这个方法初看甚妙 代码少 而且原理浅显易懂。但分析一下就能发现他的明显缺点了 就是——不精确!比如我需要宽171高56的椭圆 此时我们如果把arc的半径定为28的话 那么后面就要为171/28/2这个蛋疼的不知所云的数字郁闷了。 不过有个折中的办法是始终把arc的半径设成100 然后 不够就放大 超过了就缩小。但是 还是不精确。 3 使用贝赛尔曲线bezierCurveTo 自从觉得上面的缩放法不精确后 我就很想找到一个精确的画椭圆的方法 最后在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(); } 这个方法可以算是比较完美的了。他把一个椭圆分成了4条贝塞尔曲线 用他们连成了一个椭圆。最后宽度高度也比较精确 开销也较少。 但此方法依然有缺点。大家看那个kappa参数 有个很奇特的值 相信很多人在几何专家告诉你为什么他要取这个值之前 都不明白为什么非要取这个值——我到现在还是不知道。并且我有很强烈的想把他改一下看看有什么后果的冲动。 当然我这种类似强迫症患者的冲动并不能说成是此方法的缺点 他真正的缺点是——为什么要用4条贝塞尔曲线 我个人觉得 一个椭圆明显是由两条贝塞尔曲线组成的而不是4条。这个想法最终让我找到了最完美的画椭圆的方法。4 使用两条贝赛尔曲线画出椭圆 为了了解上一个方法能否精简 我专门注册了一个stackoverflow的帐号去提问 由于问题里有图片 积分不够不能传 我还迫不得已用勉勉强强的英语水平去回答老外的问题挣积分。但最终好运到了 回答一个问题就解决了我的积分问题。 我提的贝赛尔曲线和椭圆的关系的问题在此. 说实话 下面老外的回答我大部分没看懂 但幸亏他提供了一个代码示例页 让我明白了原理 在此对他表示再次的感谢。而根据他的解答 我找到的画椭圆的方法如下: 复制代码代码如下: //椭圆 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; } 此方法既精确 又代码少 而且也没有奇怪的难懂的地方。只需要记住这一点 椭圆的宽度与画出椭圆的贝赛尔曲线的控制点的坐标比例如下: 贝塞尔控制点x=(椭圆宽度/0.75)/2这一点已经在代码中体现了。 大家可自行试验上面的4个方法画出椭圆。 如果你发现了更简单的方法 也请分享出来大家探讨吧。

来源:爱蒂网