✏️Canvas实现环形文字

什么是环形文字?

搜索相关的图片可以看到

从上面可以得知, 环形文字其实就是文字围绕一个中心点或一个圆形区域(如圆形徽章、硬币、印章、表盘、圆形按钮、图标等)进行布局.

在前端中,如果想要实现这种环形文字,我们可以借助canvas来实现,也可以用传统的css来实现。

这边采用的是cavans来实现

最终效果

完整代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>文字环绕</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      canvas {
        background: #1a1a1a;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" height="800px" width="800px"></canvas>
    <script>
      const canvas = document.getElementById('canvas')
      const ctx = canvas.getContext('2d')
      const num = 360
      if (!ctx) console.log('上下文对象不存在')
      ctx.font = '24px 微软雅黑'
      ctx.fillStyle = '#fff'
      /**
       * @function 环形文本
       * @param text 文本
       * @params spacing 间距
       */
      const circularText = (
        text,
        spacing,
        options = {
          x: 400,
          y: 400,
          radius: 250
        }
      ) => {
        const num = 360
        for (let index = 0; index < num; index += spacing) {
          const startAngle = (Math.PI * index) / 180
          const angle = parseFloat(startAngle)
          ctx.save()
          ctx.beginPath()
          ctx.translate(
            options.x + Math.cos(angle) * options.radius,
            options.y + Math.sin(angle) * options.radius
          )
          ctx.rotate(Math.PI / 2 + angle)
          ctx.font = '24px 微软雅黑'
          ctx.fillStyle = '#fff'
          ctx.fillText(text, 0, 0)
          ctx.restore()
        }
      }
      circularText('/', 3.6)
      circularText('+', 10, {
        x: 400,
        y: 400,
        radius: 200
      })
      circularText('{', 20, {
        x: 400,
        y: 400,
        radius: 150
      })
      circularText('</>', 30, {
        x: 400,
        y: 400,
        radius: 100
      })
      const poetry = '桃之夭夭,灼灼其华。之子于归,宜其室家。'
      const total = num / 20
      // 汉字环绕
      for (let index = 0; index < total; index++) {
        const text = poetry.charAt(index % total)
        const startAngle = (Math.PI * index * 20) / 180
        const angle = parseFloat(startAngle)
        ctx.save()
        ctx.beginPath()
        ctx.translate(400 + Math.cos(angle) * 300, 400 + Math.sin(angle) * 300)
        ctx.rotate(Math.PI / 2 + angle)
        ctx.fillText(text, 0, 0)
        ctx.restore()
      }
      ;(function () {})()
    </script>
  </body>
</html>

实现思路

  1. 根据间距计算在环上面的位置,以及起始弧度
  2. 文字按照环形排列
  3. 对每一个字符,进行旋转
js 复制代码
const total = num / 20
for (let index = 0; index < total; index++) {
    // 计算当前文字所在位置的角度(弧度制)。因为每个文字间隔20度,所以当前角度为`index * 20`度,然后转换为弧度(乘以π除以180)
    const startAngle = (Math.PI * index * 20) / 180
    // 确保是浮点数,可以省略
    const angle = parseFloat(startAngle)
   // 在通过sin和cos函数计算 对应的文字点在圆周上面的坐标
    ctx.fillText(
      'A',
      400 + Math.cos(angle) * 300,
      400 + Math.sin(angle) * 300
    )
  }

x=400 + Math.cos(angle) * 300

y=400 + Math.sin(angle) * 300

这个x,y就是文字坐标

公式如下:

js 复制代码
x = 圆心的x坐标+Math.cos(弧度)*半径
y = 圆心的y坐标+Math.cos(弧度)*半径

最终画出来的效果是这样的

这时候文字字符以及围成一个圆形了

但是文字本身还没有旋转到对应的角度,看起来就很奇怪。

这时候需要用到下面几个方法

  • save():用于存储当前绘制状态

  • translate():修改当前画布原点,这里要注意 这个方法修改的是整个画布的原点

  • rotate():根据画布原点旋转画布

  • restore():恢复最近的保存状态

旋转字符的步骤如下: 保存状态->将 字符坐标设置画布原点->旋转画布->恢复到上一次的画布绘制状态

js 复制代码
ctx.save()
ctx.beginPath()
ctx.translate(400 + Math.cos(angle) * 300, 400 + Math.sin(angle) * 300)
ctx.rotate(Math.PI / 2 + angle)
ctx.fillText(text, 0, 0)
ctx.restore()

之前我们将文本按圆心环绕绘制了,那么这里就按前面获取到的字符坐标设置原点

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>文字环绕</title>
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      canvas {
        background: #1a1a1a;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" height="800px" width="800px"></canvas>
    <script>
      const canvas = document.getElementById('canvas')
      const ctx = canvas.getContext('2d')
      const num = 360
      if (!ctx) console.log('上下文对象不存在')
      ctx.font = '24px 微软雅黑'
      ctx.fillStyle = '#fff'
      const total = num / 20
      // 汉字环绕
      for (let index = 0; index < total; index++) {
        const startAngle = (Math.PI * index * 20) / 180
        const angle = parseFloat(startAngle)
        ctx.save()
        ctx.beginPath()
        ctx.translate(400 + Math.cos(angle) * 300, 400 + Math.sin(angle) * 300)
        ctx.rotate(Math.PI / 2 + angle)
        ctx.fillText('A', 0, 0)
        ctx.restore()
      }
      ;(function () {})()
    </script>
  </body>
</html>

画出来的效果就是这样的

结尾

到这里环形文本的实现方式已经结束了,下一篇文章我打算用这些知识实现mdn文档官网首页的这个效果

相关推荐
前端小巷子10 分钟前
Webpack 5模块联邦
前端·javascript·面试
玲小珑13 分钟前
Next.js 教程系列(十九)图像优化:next/image 与高级技巧
前端·next.js
晓得迷路了13 分钟前
栗子前端技术周刊第 91 期 - 新版 React Compiler 文档、2025 HTML 状态调查、Bun v1.2.19...
前端·javascript·react.js
江城开朗的豌豆20 分钟前
Vue和React中的key:为什么列表渲染必须加这玩意儿?
前端·vue.js·面试
江城开朗的豌豆25 分钟前
前端路由傻傻分不清?route和router的区别,看完这篇别再搞混了!
前端·javascript·vue.js
pengzhuofan28 分钟前
Web开发系列-第0章 Web介绍
前端
小鱼人爱编程37 分钟前
Java基石--反射让你直捣黄龙
前端·spring boot·后端
JosieBook2 小时前
【web应用】如何进行前后端调试Debug? + 前端JavaScript调试Debug?
前端·chrome·debug
LBJ辉2 小时前
2. Webpack 高级配置
前端·javascript·webpack
灵感__idea9 小时前
JavaScript高级程序设计(第5版):好的编程就是掌控感
前端·javascript·程序员