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()导出画布内容时,路径文本出现两个异常:
startOffset未正确处理,导出的SVG中始终为0;- 文本路径侧设置在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
相关产品推荐
相关产品推荐

