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

PaperJS拖拽线段端点快速移动丢焦点 如何保持30px拖拽容差

Paper.js 线段拖拽丢焦点修复

问题原因

快速拖拽时丢失目标的问题出在两个地方:

  1. 拖拽过程中每帧都重新计算离鼠标最近的端点,没有锁定一开始选中的拖拽目标。鼠标快速移动时两帧之间的位移超过30px,就会直接不满足容差判断条件,拖拽逻辑中断。
  2. 原closestPointData方法里API用错了:line.getPointAt()接收的参数是路径长度偏移值,传segment对象根本拿不到正确的端点坐标,距离计算本身就不准。

修复方法

  • 加一个拖拽状态变量,鼠标按下时如果在30px容差范围内,就锁定当前选中的端点索引
  • 拖拽过程中直接操作锁定的端点,不重复做最近点计算,不受鼠标移动距离限制
  • 鼠标抬起时清空拖拽锁定状态
  • 修正端点坐标获取逻辑,直接读取segment的point属性

修正后的完整代码:

const line = new Path.Line([90, 90], [250, 250]);
line.strokeColor = 'black';
line.strokeWidth = 3;

const redDot = new Path.Circle({
  radius: 3,
  fillColor: 'transparent',
  position: [90, 90]
});

// 记录当前正在拖拽的端点索引,值为null时表示没有正在进行的拖拽
let draggingSegmentIndex = null;

function onMouseDown(e) {
  const nearestPoint = closestPointData(e);
  if (nearestPoint.closestDistance < 30) {
    draggingSegmentIndex = nearestPoint.closestPointIndex;
    redDot.fillColor = 'red';
  }
}

function onMouseDrag(e) {
  if (draggingSegmentIndex !== null) {
    line.segments[draggingSegmentIndex].point = e.point;
    redDot.position = e.point;
  }
}

function onMouseUp(e) {
  draggingSegmentIndex = null;
  const nearestPoint = closestPointData(e);
  if (nearestPoint.closestDistance < 30) {
    redDot.position = nearestPoint.usePoint;
    redDot.fillColor = 'red';
  } else {
    redDot.fillColor = 'transparent';
  }
}

function onMouseMove(e) {
  if (draggingSegmentIndex !== null) return;
  const nearestPoint = closestPointData(e);
  if (nearestPoint.closestDistance < 30) {
    redDot.position = nearestPoint.usePoint;
    redDot.fillColor = 'red';
  } else {
    redDot.fillColor = 'transparent';
  }
}

// 计算线段上距离鼠标最近的端点信息
function closestPointData(e) {
  let closestPointIndex = null;
  let closestDistance = Infinity;
  let usePoint;
  
  for (let i = 0; i < line.segments.length; i++) {
    const segmentPoint = line.segments[i].point;
    const distance = e.point.getDistance(segmentPoint);
    if (distance < closestDistance) {
      closestDistance = distance;
      closestPointIndex = i;
      usePoint = segmentPoint;
    }
  }
  return { closestPointIndex, closestDistance, usePoint };
}

修复后只要鼠标按下时在30px容差范围内选中了端点,不管拖拽时鼠标移动多快,只要不松开就不会丢失拖拽目标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:36:32