canvas 实现超椭圆

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

定义:

椭圆:椭圆是由两个焦点定义的,并且它的形状主要取决于这两个焦点之间的距离。

超椭圆:超椭圆是由两个指数定义的,通常表示为 nX 和 nY。当 nX 和 nY 都等于 2 时,超椭圆就变成了普通的椭圆。
形状:

椭圆:椭圆的形状主要取决于两个焦点之间的距离。当两个焦点靠得很近时,椭圆会变得更扁;当两个焦点离得很远时,椭圆会变得更圆。

超椭圆:超椭圆的形状主要取决于 nX 和 nY 的值。当 nX 和 nY 的值增加时,超椭圆会变得更扁;当 nX 和 nY 的值减小时,超椭圆会变得更圆。

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

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

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

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

实现原理

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

canvas 实现超椭圆

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

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

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

以下是完整实现:

js 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>绘制超椭圆</title>
  </head>
  <body>
    <!-- 创建一个600x600的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>

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

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

相关推荐
柒和远方10 分钟前
从审计日志到可下载证据包:事务型 Outbox、租约 fencing 与保留水位
前端·后端·架构
minglie137 分钟前
npm ali-oss库依赖冲突
前端·npm
CryptoPP1 小时前
BSE股票K线数据接入实战:从接口调用到前端图表展示
大数据·前端·网络·人工智能·websocket·网络协议
没落英雄3 小时前
5. 从零开始搭建一个 AI Agent —— 人机协作与中断恢复
前端·人工智能·架构
品尚公益团队3 小时前
C#在asp.net网页开发中的带cookie登录实现
前端·c#·asp.net
多加点辣也没关系4 小时前
JavaScript|第9章:对象 — 基础
开发语言·javascript·ecmascript
没有了遇见4 小时前
AI Agent 是什么?—— 一文理解 LLM、Memory、Skills、Tools、MCP、Workflow,Context
android·前端·程序员
后台开发者Ethan5 小时前
setState组件更新
前端·javascript·react
谙忆10245 小时前
大文件上传实战:前端分片、断点续传、秒传与并发控制怎么落地
前端
轻动琴弦5 小时前
VoltTool —— 一站式在线开发者工具平台,69+实用工具免费使用
前端·chrome