likes
comments
collection
share

canvas 实现超椭圆

作者站长头像
站长
· 阅读数 51

工作中要实现一个超椭圆头像,超椭圆,不是圆角矩形么,和椭圆有什么区别?第一次看到这个需求不禁有些疑问 🤔,专门查了下,解释如下:

定义: 椭圆:椭圆是由两个焦点定义的,并且它的形状主要取决于这两个焦点之间的距离。 超椭圆:超椭圆是由两个指数定义的,通常表示为 nX 和 nY。当 nX 和 nY 都等于 2 时,超椭圆就变成了普通的椭圆。

形状: 椭圆:椭圆的形状主要取决于两个焦点之间的距离。当两个焦点靠得很近时,椭圆会变得更扁;当两个焦点离得很远时,椭圆会变得更圆。 超椭圆:超椭圆的形状主要取决于 nX 和 nY 的值。当 nX 和 nY 的值增加时,超椭圆会变得更扁;当 nX 和 nY 的值减小时,超椭圆会变得更圆。

好像还是没有明白 😂 简单来说就是椭圆的形状由两个焦点决定,而超椭圆的形状由两个指数决定。

看一下这个是不是就一目了然了 👀

canvas 实现超椭圆

除了小米 logo,很多手机的 App 图标都是超椭圆形状。

canvas 实现超椭圆

我们检查下元素,发现它是用 svg 实现的,换一种方式,用更灵活的 canvas 实现。

实现原理

下面这篇文章用图形的方式,讲的很详细:

canvas 实现超椭圆

上面是把数学公式转换成代码画出来的,那么有没有更好理解的方式呢?答案是有的 💡

通常在canvas里面画一个圆,用的arc()方法,如果不用这个方法,也可以用画线的方式,循环遍历Math.PI * 2(360 度),每次移动 1 度,这样画出来的就是圆了。

超椭圆也可以用同样的方式实现,只是在画线过程中使用Math.cos(angle)Math.sin(angle)计算角度的余弦和正弦值,然后使用偏导数(nXnY)调整坐标点,以绘制超椭圆。

以下是完整实现:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>绘制超椭圆</title>
  </head>
  <body>
    <!-- 创建一个300x300的canvas元素,用于绘制超椭圆 -->
    <canvas id="myCanvas" width="300" height="300"></canvas>
    <script>
      /**
       * 绘制超椭圆
       * @param canvas - 画布元素
       * @returns {Path2D} - 返回绘制的超椭圆路径
       */
      function drawSuperEllipse(canvas) {
        const ellipse = new Path2D(); // 创建一个新的Path2D对象,用于绘制超椭圆路径
        const nX = 3.06; // x方向的超椭圆参数
        const nY = 3.45; // y方向的超椭圆参数
        const r = canvas.width / 2; // 计算椭圆的半径
        const x = canvas.width / 2; // 椭圆中心的x坐标
        const y = canvas.height / 2; // 椭圆中心的y坐标

        for (let angle = 0; angle < Math.PI * 2; angle += 0.01) {
          // 计算超椭圆上的每一个点的坐标
          const px =
            Math.abs(Math.cos(angle)) ** (2 / nX) *
              r *
              Math.sign(Math.cos(angle)) +
            x;
          const py =
            Math.abs(Math.sin(angle)) ** (2 / nY) *
              r *
              Math.sign(Math.sin(angle)) +
            y;
          if (angle === 0) {
            ellipse.moveTo(px, py); // 在第一个点处移动到坐标 (px, py)
          } else {
            ellipse.lineTo(px, py); // 绘制从上一个点到当前点的线段
          }
        }
        ellipse.closePath(); // 关闭路径
        return ellipse; // 返回绘制的超椭圆路径
      }

      const canvas = document.getElementById("myCanvas"); // 获取画布元素
      const ctx = canvas.getContext("2d"); // 获取2D绘图上下文

      // 添加点击事件监听
      canvas.addEventListener("click", () => {
        // 清除画布
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 要绘制的图形
        const superEllipse = drawSuperEllipse(canvas);
        ctx.stroke(superEllipse);
      });
    </script>
  </body>
</html>

最后画出的图形是超椭圆:

canvas 实现超椭圆

当然我们也可以用其他方法实现,比如贝塞尔曲线,有兴趣的可以自行尝试。

转载自:https://juejin.cn/post/7356404267504730163
评论
请登录