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

Fabric.js:带路径的IText转换为SVG时的路径处理及兼容问题

Fabric.js 曲线路径文本SVG导出问题修复

我在Fabric.js的Kitchensink演示环境中实现了沿圆形路径排列的IText效果,核心代码如下:

let drawCirclePath = (cx, cy, r) => {
  return "M" + cx + "," + cy + "m" + -r + ",0a" + r + "," + r + " 0 1,0 " + r * 2 + ",0a" + r + "," + r + " 0 1,0 " + -r * 2 + ",0";
};
fabric.IText.prototype.setCurvedTextPath = function () {
  if (this.curved) {
    let path = new fabric.Path(drawCirclePath(0, 0, this.curveRadius), {
      fill: 'red',
      strokeWidth: 1,
      stroke: 'rgba(0,0,0, 0.1)',
      visible: true
    });

    this.set('path', path);
    this.setCurvedTextPosition();
  }
};
fabric.IText.prototype.setCurvedTextPosition = function () {
  if (this.curved && this.path) {
    this.pathSide = this.curveReverse ? 'left' : 'right';
    const offset = this.curveReverse ? Math.PI * this.curveRadius * 2 * 0.25 : Math.PI * this.curveRadius / 2;
    this.pathStartOffset = offset - this.calcTextWidth() / 2;
    this.pathAlign = 'center';
  }
};
var textPath = new fabric.IText('Text on a path', {
    top: 150,
    left: 150,
    curved: true,
    curveRadius: 170,
    curveReverse: false
});
canvas.add(textPath)
textPath.setCurvedTextPath()

完整可运行代码

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<canvas id="canvasFabric" width="500" height="500"></canvas>

CSS

canvas,
svg{
  border: 1px solid #ccc;
  overflow:visible;
}

JavaScript

var canvas = new fabric.Canvas("canvasFabric");
let drawCirclePath = (cx, cy, r) => {
  return "M" + cx + "," + cy + "m" + -r + ",0a" + r + "," + r + " 0 1,0 " + r * 2 + ",0a" + r + "," + r + " 0 1,0 " + -r * 2 + ",0";
};
fabric.IText.prototype.setCurvedTextPath = function () {
  if (this.curved) {
    let path = new fabric.Path(drawCirclePath(0, 0, this.curveRadius), {
      fill: 'red',
      strokeWidth: 1,
      stroke: 'rgba(0,0,0, 0.1)',
      visible: true
    });

    this.set('path', path);
    this.setCurvedTextPosition();
  }
};
fabric.IText.prototype.setCurvedTextPosition = function () {
  if (this.curved && this.path) {
    this.pathSide = this.curveReverse ? 'left' : 'right';
    const offset = this.curveReverse ? Math.PI * this.curveRadius * 2 * 0.25 : Math.PI * this.curveRadius / 2;
    this.pathStartOffset = offset - this.calcTextWidth() / 2;
    this.pathAlign = 'center';
  }
};
var textPath = new fabric.IText('Text on a path', {
    top: 150,
    left: 150,
    curved: true,
    curveRadius: 170,
    curveReverse: true
});
canvas.add(textPath)
textPath.setCurvedTextPath()

效果预览

曲线路径文本效果


SVG导出问题

使用canvas.toSVG()导出画布内容时,路径文本出现两个异常:

  1. startOffset未正确处理,导出的SVG中始终为0;
  2. 文本路径侧设置在Chrome浏览器中无效。

当前导出的SVG内容示例:

<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="
    background: #000000a8;
">

<g transform="matrix(1 0 0 1 156.5 213.5)" style="">

  <path id="curvedPath" 
  style="stroke: rgb(0,0,0); stroke-opacity: 0.1; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;"  transform=" translate(0, 0)" 
  d="M 0 0 M -170 0 C -170 93.88840747123488 -93.88840747123488 170 0 170 C 93.88840747123487 170 170 93.88840747123488 170 0 C 170 -93.88840747123488 93.88840747123488 -170 0 -170 C -93.88840747123487 -170 -170 -93.8884074712349 -170 -2.0818995585505004e-14"
  stroke-linecap="round"
 />

  <text xml:space="preserve" font-family="Times New Roman" font-size="40" font-style="normal" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1; white-space: pre;">
    <textPath xlink:href="#curvedPath" startOffset="0" alignment-baseline="middle" dominant-baseline="middle">
      Text on a path
    </textPath>
  </text>
</g>
</svg>

尝试过社区相关解决方案,但未解决问题。


修复方案

1. 修复startOffset导出异常

Fabric.js默认导出SVG时未读取pathStartOffset属性,需要重写IText的toSVG方法,手动替换正确的偏移值:

fabric.IText.prototype.toSVG = function(reviver) {
  var markup = this._toSVG('text');
  if (this.path && this.pathStartOffset !== undefined) {
    // 将默认的startOffset="0"替换为计算好的pathStartOffset
    markup = markup.replace(/startOffset="0"/, `startOffset="${this.pathStartOffset}"`);
  }
  return reviver ? reviver(markup) : markup;
};

2. 修复Chrome中文本路径侧无效问题

Chrome支持SVG textPath的side属性,但Fabric.js默认未导出该属性,扩展上述toSVG方法添加side属性:

fabric.IText.prototype.toSVG = function(reviver) {
  var markup = this._toSVG('text');
  if (this.path) {
    // 替换startOffset
    if (this.pathStartOffset !== undefined) {
      markup = markup.replace(/startOffset="0"/, `startOffset="${this.pathStartOffset}"`);
    }
    // 添加pathSide对应的side属性
    if (this.pathSide) {
      markup = markup.replace(/<textPath/, `<textPath side="${this.pathSide}"`);
    }
  }
  return reviver ? reviver(markup) : markup;
};

3. 完整修复代码

将上述重写的toSVG方法添加到你的代码中,重新调用canvas.toSVG()即可导出正确的SVG。修复后的SVG会包含正确的startOffset和side属性,Chrome中也能正常渲染文本路径侧。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:47:32