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

Fabric.js设置originX/originY为center时多边形绘制出现位移问题

解决Fabric.js中设置originX/Y为"center"时多边形绘制位移的问题

这个问题的核心是原点基准改变后,多边形的坐标计算逻辑没有同步调整。当originX/Y从"left"/"top"改为"center"时,Fabric.js会以多边形的中心作为位置计算的基准点,而你在绘制过程中还是直接使用鼠标的原始坐标来更新点,导致最终生成的多边形位置偏移。

下面是修复后的实现思路和代码:

关键修复点

  • 在绘制过程中,动态更新多边形点的时候,需要基于当前多边形的中心原点来计算坐标偏移;
  • 最终创建正式多边形对象时,确保位置和点坐标的基准统一为"center";
  • 移除绘制过程中临时对象的坐标偏移(比如辅助圆点的top/left计算)。

修改后的完整代码

var canvas = window._canvas = new fabric.Canvas('c');
draw_polygon(1);

function draw_polygon(id){
  editandoPoligono = true;
  canvas.selection=false;
  var mode = "add", currentShape;
  var puntos;
  newColor = "red";

  canvas.observe("mouse:move", function (event) {
    var pos = canvas.getPointer(event.e);
    if (mode === "edit" && currentShape) {
      // 启用center原点
      currentShape.originX = "center";
      currentShape.originY = "center";
      var points = currentShape.get("points");
      // 基于中心原点计算当前鼠标位置对应的点坐标
      const centerX = currentShape.left;
      const centerY = currentShape.top;
      points[points.length - 1].x = pos.x - centerX;
      points[points.length - 1].y = pos.y - centerY;
      currentShape.set({ points: points });
      canvas.renderAll();
    }
  });

  canvas.observe("mouse:down", function (event) {
    var pos = canvas.getPointer(event.e);
    if (mode === "add") {
      // 初始多边形的点基于中心原点计算(第一个点为(0,0),第二个点偏移1px)
      var obj = new fabric.Polygon([{ x: 0, y: 0 }, { x: 1, y: 1 }], {
        fill: newColor,
        objectCaching: false,
        selectable: false,
        id: id,
        olvidar: "olvidar",
        strokeWidth: 0,
        originX: "center",
        originY: "center",
        left: pos.x,
        top: pos.y
      });
      var circ = new fabric.Circle({
        id: "guiaPol",
        evented: false,
        selectable: false,
        top: pos.y,
        left: pos.x,
        radius: 5,
        fill:"black",
        perPixelTargetFind: true,
        originX: "center",
        originY: "center"
      });
      currentShape = obj;
      canvas.add(currentShape);
      canvas.add(circ);
      newColor= currentShape.get('fill');
      mode = "edit";
    } else if (mode === "edit" && currentShape && currentShape.type === "polygon") {
      currentShape.originX="center";
      currentShape.originY="center";
      var points = currentShape.get("points");
      const centerX = currentShape.left;
      const centerY = currentShape.top;
      // 基于中心原点添加新的点坐标
      points.push({ x: pos.x - centerX , y: pos.y - centerY });
      puntos = points;
      currentShape.set({ points: points });
      var circ = new fabric.Circle({
        id: "guiaPol",
        evented: false,
        selectable: false,
        top: pos.y,
        left: pos.x,
        radius: 5,
        fill: "black",
        perPixelTargetFind: true,
        originX: "center",
        originY: "center"
      });
      canvas.add(circ);
      canvas.renderAll();
    }
  });

  function pararCreacion(){
    if (mode === 'edit' || mode === 'add') {
      mode = 'normal';
      // 基于中心原点创建最终的多边形
      currentShape = new fabric.Polygon(puntos,{
        id:id,
        originY: "center",
        originX: "center",
        fill: newColor,
        type: 'polygon',
        nombre: 'Objeto_' + id,
        perPixelTargetFind: true,
        strokeWidth: 0,
        left: currentShape.left,
        top: currentShape.top
      });
      var circleObjects = [];
      canvas.forEachObject(function (o) {
        if (o.id == "guiaPol") {
          circleObjects.push(o);
        }
      });
      canvas.remove(...circleObjects);
      canvas._objects.pop();
      currentShape.nombre = 'Objeto_'+id;
      if(currentShape.get('points').length>4){
        canvas.add(currentShape);
        // 全局设置为center原点(根据你的需求)
        fabric.Object.prototype.originX ="center";
        fabric.Object.prototype.originY ="center";
        currentShape.set({ selectable: true });
      }else{
        alert("Error");
      }
      canvas.selection=true;
      editandoPoligono = false;
      canvas.renderAll();
    }
    currentShape = null;
  }
  canvas.on("mouse:dblclick", pararCreacion);
};

修复逻辑解释

  1. 初始多边形创建:把初始点设为[{x:0,y:0}, {x:1,y:1}],同时将多边形的left和top直接设为鼠标点击的位置(因为origin是center,所以这个位置就是多边形的中心)。
  2. 鼠标移动更新点:计算鼠标位置相对于多边形中心的偏移量,作为点的坐标值,而不是直接用鼠标的原始坐标。
  3. 添加新点:同样基于多边形中心计算偏移量来添加新点,保证所有点的坐标都是相对于中心原点的。
  4. 最终多边形创建:保持origin为center,继承临时多边形的left和top位置,确保视觉上和绘制过程一致。

这样修改后,即使originX/Y设为"center",多边形的绘制位置也会和鼠标操作完全匹配,不会出现位移问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:56:42