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

Fabric.js中如何获取图形实际坐标而非bounding rectangle?

解决Fabric.js 5获取图形顶点坐标并添加中点标签的问题

核心思路

Fabric.js中不同类型图形的顶点获取方式不同,需区分内置基础形状(如Triangle)和自定义Path形状(如平行四边形):

  • 内置形状:利用其固定的局部顶点位置,结合getAbsoluteTransformMatrix()获取包含父级Group变换的矩阵,将局部坐标转换为画布全局坐标。
  • 自定义Path:从path属性提取原始路径点,同样应用绝对变换矩阵得到实际坐标。

获取顶点后,计算相邻顶点的中点,再在中点位置创建带文本的矩形标签。

完整实现代码

HTML部分

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
<canvas id="c" width="400" height="300"></canvas>

JavaScript部分

const fc = new fabric.Canvas("c");

// 获取图形的实际顶点(画布全局坐标)
function getShapeVertices(shape) {
  const matrix = shape.getAbsoluteTransformMatrix();
  let vertices = [];

  if (shape.type === 'triangle') {
    // Triangle的局部顶点(相对于自身origin)
    const localPoints = [
      { x: shape.width / 2, y: 0 },
      { x: shape.width, y: shape.height },
      { x: 0, y: shape.height }
    ];
    vertices = localPoints.map(point => fabric.util.transformPoint(point, matrix));
  } else if (shape.type === 'path') {
    // 提取Path中的直线坐标点
    shape.path.forEach(segment => {
      if (segment[0] === 'M' || segment[0] === 'L') {
        const localPoint = { x: segment[1], y: segment[2] };
        vertices.push(fabric.util.transformPoint(localPoint, matrix));
      }
    });
    // 移除闭合路径的重复终点
    if (vertices.length > 0 && shape.path.at(-1)[0] === 'z') {
      vertices.pop();
    }
  }
  return vertices;
}

// 在顶点中点创建带文本的矩形标签
function addMidpointLabels(vertices, canvas) {
  vertices.forEach((point, index) => {
    const nextIndex = (index + 1) % vertices.length;
    const nextPoint = vertices[nextIndex];
    // 计算中点坐标
    const midX = (point.x + nextPoint.x) / 2;
    const midY = (point.y + nextPoint.y) / 2;

    // 创建标签矩形
    const label = new fabric.Textbox(`${index+1}-${nextIndex+1}`, {
      left: midX - 20,
      top: midY - 15,
      width: 40,
      height: 30,
      fill: 'white',
      stroke: 'black',
      strokeWidth: 1,
      textAlign: 'center',
      fontSize: 12,
      backgroundColor: '#333',
      selectable: false
    });
    canvas.add(label);
  });
}

// 选中图形时获取顶点并添加中点标签
fc.on('selection:created', event => {
  const selectedGroup = event.target;
  const shape = selectedGroup.item(0);
  const vertices = getShapeVertices(shape);
  console.log("实际顶点坐标: ", vertices);
  addMidpointLabels(vertices, fc);
});

// 创建三角形
const triangle1Options = {
  stroke: 'black',
  strokeWidth: 2,
  fill: 'red',
  left: 10,
  top: 10,
  width: 100,
  height: 100,
}
let triangle1 = new fabric.Triangle(triangle1Options);
const group1 = new fabric.Group([triangle1], {
  selectable: true,
  lockScalingFlip: true,
  lockUniScaling: true,
  subTargetCheck: true,
  lockScalingX: false,
  lockScalingY: false,
  objectCaching: false,
  noScaleCache: true
});
fc.add(group1);

// 创建平行四边形
var parallelogram1 = new fabric.Path('M 0 0 L 100 0 L 150 50 L 50 50 z', {
  left: 150,
  top: 50,
  stroke: 'black',
  strokeWidth: 2,
  fill: 'red',
});
const group2 = new fabric.Group([parallelogram1], {
  selectable: true,
  lockScalingFlip: true,
  lockUniScaling: true,
  subTargetCheck: true,
  lockScalingX: false,
  lockScalingY: false,
  objectCaching: false,
  noScaleCache: true
});
fc.add(group2);

关键说明

  1. 绝对变换矩阵:getAbsoluteTransformMatrix()会自动包含父级Group的缩放、旋转、平移变换,确保转换后的坐标是画布全局坐标。
  2. 形状适配:代码中针对Triangle和Path做了适配,如需支持其他内置形状(如Rect、Polygon),可扩展getShapeVertices函数,添加对应形状的局部顶点逻辑。
  3. 中点计算:通过取相邻顶点坐标的平均值得到中点,再将标签矩形定位到中点位置(做了偏移确保文本居中)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:42:32