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

Fabric.js 图形绘制后自由绘图异常:线条从图形中间起始

解决Fabric.js切换绘图模式后线条从正方形中心开始的问题

这个问题我之前也踩过类似的坑,本质是切换绘图模式时Fabric.js的内部状态没有被正确重置——当你画完正方形后,Canvas还保留着之前形状的相关坐标信息,切换到自由绘图模式时就会“跑偏”。下面给你具体的解决思路和修正代码:

问题根源

当你先绘制正方形(非自由绘图模式),再开启isDrawingMode = true时,Fabric.js没有自动清除之前绘制形状时的临时状态(比如形状的中心点坐标),导致自由绘图的起始点被错误绑定到了正方形的中心。

修复步骤

  • 动态控制绘图模式:不要一开始就固定isDrawingMode,而是根据当前选中的工具(正方形/铅笔)来切换。
  • 切换工具时重置状态:每次切换工具,都要清除Canvas的选中对象、重置临时绘图状态。
  • 分离不同工具的事件逻辑:把正方形绘制和自由绘图的逻辑分开,避免互相干扰。

修正后的代码示例

var functouse = "square"; // 初始设为正方形工具,可按需调整
var pensize = 5;
var pencolour = "#000000";
var fillcolour = "#ffffff";
var canvas = new fabric.Canvas('sketchpad', {
  isDrawingMode: false, // 初始关闭自由绘图模式
  transparentCorners: false
});
canvas.selection = false;

// 切换工具的函数(可绑定到按钮点击事件)
function switchTool(tool) {
  functouse = tool;
  // 清除当前选中对象,彻底重置状态
  canvas.discardActiveObject();
  // 根据工具类型切换绘图模式
  if (tool === "pencil") {
    canvas.isDrawingMode = true;
    // 配置铅笔样式
    canvas.freeDrawingBrush.width = pensize;
    canvas.freeDrawingBrush.color = pencolour;
  } else {
    canvas.isDrawingMode = false;
  }
  canvas.renderAll();
}

// 鼠标按下事件处理
canvas.on('mouse:down', function(e) {
  if (functouse === "square" && !canvas.isDrawingMode) {
    var pointer = canvas.getPointer(e.e);
    // 创建初始矩形(后续拖动调整为正方形)
    var square = new fabric.Rect({
      left: pointer.x,
      top: pointer.y,
      width: 0,
      height: 0,
      fill: fillcolour,
      stroke: pencolour,
      strokeWidth: pensize
    });
    canvas.add(square);
    canvas.setActiveObject(square);
    
    // 鼠标拖动时调整正方形大小(保持宽高一致)
    var onMouseMove = function(e) {
      var pointer = canvas.getPointer(e.e);
      var size = Math.max(Math.abs(pointer.x - square.left), Math.abs(pointer.y - square.top));
      square.set({
        width: size,
        height: size,
        left: pointer.x < square.left ? pointer.x : square.left,
        top: pointer.y < square.top ? pointer.y : square.top
      });
      canvas.renderAll();
    };
    
    // 鼠标松开时移除临时事件监听
    var onMouseUp = function() {
      canvas.off('mouse:move', onMouseMove);
      canvas.off('mouse:up', onMouseUp);
    };
    
    canvas.on('mouse:move', onMouseMove);
    canvas.on('mouse:up', onMouseUp);
  }
});

关键说明

  • 切换工具时调用canvas.discardActiveObject():彻底清除之前选中的形状对象,避免其坐标残留影响自由绘图的起始点。
  • 严格区分isDrawingMode状态:只有使用铅笔工具时才开启自由绘图模式,绘制形状时必须关闭该模式,两种模式不能同时生效。
  • 单独封装形状绘制逻辑:把正方形的绘制(按下、拖动、松开)事件单独处理,和自由绘图模式完全隔离,避免状态互相干扰。

这样修改后,你切换到铅笔模式时,线条就会从鼠标点击的位置开始,不会再从正方形中心出发啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:41:19