canvas如何画一个椭圆

3,713 阅读1分钟

最近被问的一个问题,canvas中如何画一个椭圆。作为一名前端工程师,平时接触图形学和webgl很少,对canvas了解仅限于看过canvas画图相应的api,遇到这个问题一脸蒙蔽,依稀记得canvas原生有个画圆的api,想当然的认为应该也有个对应的画椭圆的api,传入坐标点/长轴/短轴参数就可以。后面专门去尝试并研究了下,分享一下。

canvas如何画圆

原生api:arc接收:x坐标/y坐标/开始角度/结束角度/绘制方向false为顺时针(默认)几个参数

 const ctx = canvas.getContext('2d');
 ctx.arc(x,y,radius,startAngle,endAngle,anticlockwise)

了解了一下,实际上计算机内部调用的是光栅学,圆的参数方程x=rcosθ y=rsinθ,由此可以自己写一个画圆的方法

function circle(context, x, y, r) {
    const step = 1/r; 
    context.beginPath();
    context.moveTo(x + r, y);
    for(let i = 0; i < 2 * Math.PI; i += step) {
        context.lineTo(x + r * Math.cos(i), y + r * Math.sin(i));
    }
    context.closePath();
    context.fill();
}
x、y是坐标,r是半径,1/r是1px的线段对应的角度值,也就是精细程度,当r较大时,可以写个固定的,比如1/10,不然会影响性能

开始画椭圆

其实最新版的chrome中已经有了原生画椭圆的api,只是兼容性不太好,参数x坐标/y坐标/横轴长度/竖轴长度/旋转角度/其实角度/结束角度/方向

  ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);

和圆类似,利用椭圆的参数方程:x=acosθ | y=bsinθ,也可以自己实现一个绘制椭圆的方法

 function ellipse(context, x, y, a, b) {
        const step = (a > b) ? 1 / a : 1 / b;
        context.beginPath();
        context.moveTo(x + a, y);
        for (let i = 0; i < 2 * Math.PI; i += step) {
            context.lineTo(x + a * Math.cos(i), y + b * Math.sin(i));
        }
        context.closePath();
        ctx.fillStyle = "rgba(0,0,0,.2)";
        context.fill();
    }
参数与原生和画圆的类似,step可以依据实际情况调整

还有一种比较简单的方法,性能也更高,一看代码就明白了,将标准圆压缩成一个椭圆,不过用这种方法当边框宽度较大的时候会把宽度也一起压缩了

function ellipse(context, x, y, a, b) {
            context.save();
            const r = (a > b) ? a : b;
            const ratioX = a / r;
            const ratioY = b / r;
            context.scale(ratioX, ratioY);
            context.beginPath();
            context.arc(x / ratioX, y / ratioY, r, 0, 2 * Math.PI, false);
            context.closePath();
            context.restore();
            ctx.fillStyle = "rgba(255,0,0,.2)";
            context.fill();
        }
与君共勉,需要学习的还有很多。

最后推荐个学习canvas相关的地址:地址