Fabric.js中自动生成SVG对象出现边缘模糊、运行卡顿问题求解
问题根源分析
你的实现方案存在核心逻辑错误:你将菜单项对象的创建、添加到画布的逻辑写在了mouse:move事件回调中,该事件每移动1像素就会触发一次,每触发一次就会往画布新增2个路径对象,运行时间稍长画布上会堆叠成千上万的重复对象,这是两个问题的共同诱因。
- 边缘模糊失真:大量相同路径对象在同一位置堆叠,每个对象的描边自带抗锯齿效果,多层半透明抗锯齿边缘叠加后就会出现模糊、发虚的失真问题,和边框粗细、透明度参数无关。
- 运行卡顿:画布对象数量随鼠标移动指数级增长,fabric.js每次渲染都要遍历所有对象计算绘制参数,渲染压力随对象数量暴涨急剧升高,自然会出现卡顿,哪怕仅接入少量菜单项,只要在
mouse:move中反复新增对象,很快就会达到卡顿阈值。
解决方案
- 首先将菜单项的创建逻辑从
mouse:move事件中移出,仅在初始化时创建一次菜单项,放置到画布固定的菜单区域,设置为可拖拽即可,不需要每次鼠标移动都重新创建。 - 如果你的需求是「拖动菜单项时复制出一个新对象放置到画布任意位置」,可以监听
mouse:down事件判断点击的是否为菜单项,只有拖拽菜单项时才创建一个副本跟随鼠标,拖拽结束后将副本固定到目标位置,原有菜单项保留在菜单区域不动。 - 额外性能优化建议:
- 静态对象可以设置
selectable: false,完全不需要交互的对象还可以设置evented: false,减少fabric.js的事件计算开销 - 不需要修改的多个静态对象可以合并为
fabric.Group,减少渲染遍历的开销 - 你当前使用的fabric.js 1.5.0版本非常老旧,建议升级到最新稳定版,新版本对渲染性能、路径绘制效果都有大量优化
- 静态对象可以设置
以下是修正后的代码示例:
var canvas = this.__canvas = new fabric.Canvas('c'); // 初始化时仅创建一次菜单项 function createMenuItems() { var prthss = new fabric.Path('m 37.066323,664.72823 c -0.526572,-7.80009 -0.530124,-15.64425 -0.0136,-23.48118 5.487368,-4.37172 13.310902,-4.34082 18.754907,0.0798 -0.533656,7.62909 -0.579648,15.59958 0.03127,23.20784 -5.375259,4.48954 -13.24684,4.55212 -18.772561,0.19357 z'); prthss.set({ fill: '#fff', stroke: '#1a1a1a', strokeWidth: 2, opacity: 1, left:130, top:110, lockScalingX: true, lockScalingY: true, originX: 'center', originY: 'center', isMenuItem: true // 自定义标记区分菜单项和普通对象 }); prthss.setControlsVisibility({ mt: false, mb: false, ml: false, mr: false, bl: false, br: false, tl: false, tr: false, mtr: true }); canvas.add(prthss); var tpr = new fabric.Path('m 313.13828,618.74455 c 2.11345,1.08854 2.18323,3.22159 2.1986,5.06456 m -23.10338,-9.61297 7.80969,0 -4.00165,0 0.0394,9.61297 m 5.78092,0 0.0394,-9.61297 2.83155,0 c 3.28759,0 3.40318,4.60019 0,4.60019 l -2.91027,0 m 8.34298,5.01278 0.0394,-9.61297 2.83154,0 c 3.2876,0 3.40319,4.60019 0,4.60019 l -2.91026,0 m 9.56121,-0.23614 c 0,8.35908 -6.77638,15.13546 -15.13545,15.13546 -8.35909,0 -15.13547,-6.77637 -15.13547,-15.13546 0,-8.35908 6.77638,-15.13544 15.13547,-15.13544 8.35907,0 15.13545,6.77638 15.13545,15.13544 z'); tpr.set({ fill: '#fff', stroke: '#1a1a1a', strokeWidth: 2, opacity: 1, left:100, top:110, lockRotation: true, originX: 'center', originY: 'center', isMenuItem: true }); canvas.add(tpr); } // 初始化执行一次 createMenuItems(); // 拖拽复制菜单项逻辑 let cloneObj = null; canvas.on('mouse:down', function(e) { if (e.target && e.target.isMenuItem) { // 点击菜单项时创建副本 e.target.clone(function(cloned) { cloneObj = cloned; cloneObj.set({ left: e.pointer.x, top: e.pointer.y, isMenuItem: false }); canvas.add(cloneObj); }); } }); canvas.on('mouse:move', function(e) { if (cloneObj) { // 仅存在拖拽副本时更新位置,不新增对象 cloneObj.set({ left: e.pointer.x, top: e.pointer.y }); canvas.renderAll(); } }); canvas.on('mouse:up', function() { cloneObj = null; // 拖拽结束清空标记 });
.controls { display: inline-block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js" type="text/javascript"></script> <h3>Menu with autogenerative items </h3> <canvas id="c" width="400" height="300" style="border:1px solid #ccc"></canvas>
内容的提问来源于stack exchange,提问作者SIMBIOSIS surl
相关产品推荐
相关产品推荐

