You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Fabric.JS实现Canvas文本沿圆弧/圆形弯曲并通过滑块调节弧度

Fabric JS 弧形/圆形弯曲文本实现方案

Fabric JS 未内置弧形文本组件,可通过自定义扩展类实现字符沿圆弧排布的效果,具体实现如下:

1. 自定义弧形文本扩展类

// 自定义弧形文本类
fabric.CurvedText = fabric.util.createClass(fabric.Object, {
  type: 'curved-text',
  initialize: function(text, options) {
    options || (options = {});
    this.text = text;
    this.fontSize = options.fontSize || 50;
    this.fill = options.fill || '#000';
    this.fontFamily = options.fontFamily || 'Arial';
    this.radius = options.radius || 200; // 圆弧半径,越小弧度越大
    this.spacing = options.spacing || 2; // 字符间距
    this.callSuper('initialize', options);
    this._calcDimensions();
  },
  _calcDimensions: function() {
    const tempCanvas = document.createElement('canvas');
    const tempCtx = tempCanvas.getContext('2d');
    tempCtx.font = `${this.fontSize}px ${this.fontFamily}`;
    this.charWidths = this.text.split('').map(c => tempCtx.measureText(c).width + this.spacing);
    this.totalWidth = this.charWidths.reduce((a, b) => a + b, 0);
    this.angleRange = (this.totalWidth / (Math.PI * this.radius)) * 180; // 总占角度
    this.set('width', this.radius * 2);
    this.set('height', this.radius * 2);
  },
  _render: function(ctx) {
    ctx.save();
    ctx.font = `${this.fontSize}px ${this.fontFamily}`;
    ctx.fillStyle = this.fill;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    
    let currentAngle = -this.angleRange / 2; // 从中间向左开始排布
    for (let i = 0; i < this.text.length; i++) {
      const char = this.text[i];
      const charWidth = this.charWidths[i];
      const angleRad = currentAngle * Math.PI / 180;
      
      ctx.save();
      ctx.translate(this.radius * Math.cos(angleRad), this.radius * Math.sin(angleRad));
      ctx.rotate(angleRad + Math.PI / 2); // 字符沿圆弧切线方向旋转
      ctx.fillText(char, 0, 0);
      ctx.restore();
      
      // 计算下一个字符的角度
      currentAngle += (charWidth / (Math.PI * this.radius)) * 180;
    }
    ctx.restore();
  },
  // 更新弧度(调整半径)
  setRadius: function(newRadius) {
    this.radius = Math.max(50, newRadius); // 最小半径限制,避免字符重叠
    this._calcDimensions();
    this.dirty = true;
  }
});

// 支持从JSON反序列化(可选)
fabric.CurvedText.fromObject = function(object, callback) {
  return callback(new fabric.CurvedText(object.text, object));
};

2. 替换原有文本实例

将你原有的IText替换为CurvedText实例即可生成弧形文本:

// 替换原来的IText实例
const curvedText = new fabric.CurvedText('Lorem Ipsum', {
  fill: 'black',
  fontSize: 50,
  radius: 250, // 初始半径,值越小弧度越大
  id: 'text'
});

canvas.add(curvedText);
canvas.centerObject(curvedText);
canvas.requestRenderAll();

3. 滑块调整弧度实现

HTML部分 新增范围输入控件

<!-- 范围输入滑块,min越小弧度越大,max越大弧度越平 -->
<input type="range" id="radiusSlider" min="50" max="500" value="250">

JS部分 监听滑块变化

const slider = document.getElementById('radiusSlider');
slider.addEventListener('input', function(e) {
  const newRadius = parseInt(e.target.value);
  curvedText.setRadius(newRadius);
  canvas.centerObject(curvedText); // 调整后保持居中
  canvas.requestRenderAll();
});

效果调整说明

  • 滑块的min值越小,对应圆弧半径越小,文本弧度越大
  • 滑块的max值越大,对应圆弧半径越大,文本越接近平直
  • 若要实现文本向下弯曲的效果,修改_render方法中字符的旋转角度偏移量即可,将ctx.rotate(angleRad + Math.PI / 2)调整为ctx.rotate(angleRad - Math.PI / 2)即可反转弯曲方向
  • 如果需要可编辑的弧形文本,可以监听画布双击事件,临时将弧形文本替换为IText供用户编辑,编辑完成后再重新生成CurvedText实例即可

内容的提问来源于stack exchange,提问作者Faizan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 14:54:11