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

如何求取线段中点沿法线偏移指定距离的点坐标

Canvas线段法线偏移标签点最简实现

不需要解复杂的距离方程,用向量运算3步就能算出结果,代码实现没有复杂推导,鲁棒性也更高。

计算步骤

  • 第一步:算线段中点和方向向量
    设线段两端点为(x1,y1)、(x2,y2),中点坐标直接套中点公式:
    mx = (x1 + x2) / 2,my = (y1 + y2) / 2
    沿线段方向的向量为:dx = x2 - x1,dy = y2 - y1
  • 第二步:求单位法线向量
    垂直于线段的法线方向不需要推导直线方程,直接把方向向量旋转90度即可,两个旋转方向分别对应线段两侧:
    • 顺时针旋转90度法线:(dy, -dx)
    • 逆时针旋转90度法线:(-dy, dx)
      先算线段总长度做归一化:len = Math.hypot(dx, dy),如果len为0说明两端点重合,直接返回中点即可,避免除零错误。
      把选好的法线向量除以线段长度,就得到长度为1的单位法线向量。
  • 第三步:按偏移距离算最终坐标
    设定你需要的偏移距离offset(单位为像素,正数沿法线方向偏移,负数则反向偏移),最终标签锚点坐标为:
    xn = mx + 单位法线x分量 * offset
    yn = my + 单位法线y分量 * offset

可直接复用的Canvas代码

/**
 * 计算线段中点法线偏移位置,用于放置标签
 * @param {number} x1 线段起点x
 * @param {number} y1 线段起点y
 * @param {number} x2 线段终点x
 * @param {number} y2 线段终点y
 * @param {number} offset 偏移像素距离,默认10px
 * @param {boolean} flipSide 是否翻转到线段另一侧,默认false
 * @returns {{x: number, y: number}} 标签锚点坐标
 */
function getLineLabelAnchor(x1, y1, x2, y2, offset = 10, flipSide = false) {
  const mx = (x1 + x2) / 2;
  const my = (y1 + y2) / 2;
  const dx = x2 - x1;
  const dy = y2 - y1;
  const lineLen = Math.hypot(dx, dy);
  // 两端点重合时直接返回中点
  if (lineLen === 0) return {x: mx, y: my};
  // 计算单位法线
  let nx = -dy / lineLen;
  let ny = dx / lineLen;
  // 翻转到另一侧
  if (flipSide) {
    nx = -nx;
    ny = -ny;
  }
  return {
    x: mx + nx * offset,
    y: my + ny * offset
  };
}

实用优化提示

实际绘制标签时可以参考这几个小技巧,显示效果更好:

  • 偏移量可以多留2-3px冗余,不要刚好卡着文字不压线的距离,视觉上会更宽松
  • 如果需要标签始终显示在线段上方(水平线段时标签在更靠上的一侧),可以判断法线向量的y分量正负,自动选择y值更小的一侧,不需要手动传翻转参数
  • 绘制文字前先在同样位置画一个和文字轮廓匹配的半透明白色底,或者给文字加1-2px的白色描边,就算偶尔和其他图形重叠也能看清文字

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.15 16:16:02