mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
fix(line): hover detection of the fold line (#167)
This commit is contained in:
parent
1887d53ce9
commit
cb942616ab
@ -1,26 +1,46 @@
|
|||||||
import { type IPoint, Point, Rectangle } from '@flowgram.ai/utils';
|
import { type IPoint, Point, Rectangle } from '@flowgram.ai/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算点和直线的距离
|
* 计算点到线段的距离
|
||||||
* @param p1
|
* @param point 待测试点
|
||||||
* @param p2
|
* @param segStart 线段起点
|
||||||
* @param p3
|
* @param segEnd 线段终点
|
||||||
*/
|
*/
|
||||||
function pointLineDistance(p1: IPoint, p2: IPoint, p3: IPoint): number {
|
const getPointToSegmentDistance = (point: IPoint, segStart: IPoint, segEnd: IPoint): number => {
|
||||||
let len;
|
const { x: px, y: py } = point;
|
||||||
|
const { x: x1, y: y1 } = segStart;
|
||||||
|
const { x: x2, y: y2 } = segEnd;
|
||||||
|
|
||||||
// 竖着的线
|
const A = px - x1;
|
||||||
if (p1.x - p2.x === 0) {
|
const B = py - y1;
|
||||||
len = Math.abs(p3.x - p1.x);
|
const C = x2 - x1;
|
||||||
|
const D = y2 - y1;
|
||||||
|
|
||||||
|
const dot = A * C + B * D;
|
||||||
|
const lenSq = C * C + D * D;
|
||||||
|
|
||||||
|
// 参数方程中的t参数
|
||||||
|
const param = lenSq === 0 ? -1 : dot / lenSq;
|
||||||
|
|
||||||
|
let xx: number;
|
||||||
|
let yy: number;
|
||||||
|
|
||||||
|
if (param < 0) {
|
||||||
|
xx = x1;
|
||||||
|
yy = y1;
|
||||||
|
} else if (param > 1) {
|
||||||
|
xx = x2;
|
||||||
|
yy = y2;
|
||||||
} else {
|
} else {
|
||||||
const A = (p1.y - p2.y) / (p1.x - p2.x);
|
xx = x1 + param * C;
|
||||||
const B = p1.y - A * p1.x;
|
yy = y1 + param * D;
|
||||||
|
|
||||||
len = Math.abs((A * p3.x + B - p3.y) / Math.sqrt(A * A + 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
const dx = px - xx;
|
||||||
}
|
const dy = py - yy;
|
||||||
|
|
||||||
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
|
};
|
||||||
|
|
||||||
export namespace FoldLine {
|
export namespace FoldLine {
|
||||||
const EDGE_RADIUS = 5;
|
const EDGE_RADIUS = 5;
|
||||||
@ -218,22 +238,33 @@ export namespace FoldLine {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 折叠线和点的距离
|
* 计算点到折线的最短距离
|
||||||
* @param linePosition
|
* @param points 折线的所有端点
|
||||||
* @param pos
|
* @param pos 待测试点
|
||||||
|
* @returns 最短距离
|
||||||
*/
|
*/
|
||||||
export function getFoldLineToPointDistance(points: IPoint[], pos: IPoint): number {
|
export const getFoldLineToPointDistance = (points: IPoint[], pos: IPoint): number => {
|
||||||
const bounds = getBounds(points);
|
// 特殊情况处理
|
||||||
if (bounds.contains(pos.x, pos.y)) {
|
if (points.length === 0) {
|
||||||
const lines = points.reduce((res, point, index) => {
|
return Infinity;
|
||||||
if (index === 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
res.push([points[index - 1]!, point]);
|
|
||||||
return res;
|
|
||||||
}, [] as [IPoint, IPoint][]);
|
|
||||||
return Math.min(...lines.map((l) => pointLineDistance(...l, pos)));
|
|
||||||
}
|
}
|
||||||
return Math.min(...points.map((p) => Point.getDistance(p, pos)));
|
|
||||||
}
|
if (points.length === 1) {
|
||||||
|
return Point.getDistance(points[0]!, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建线段数组
|
||||||
|
const lines: [IPoint, IPoint][] = [];
|
||||||
|
for (let i = 0; i < points.length - 1; i++) {
|
||||||
|
lines.push([points[i]!, points[i + 1]!]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算点到每个线段的最短距离
|
||||||
|
const distances = lines.map((line) => {
|
||||||
|
const [p1, p2] = line;
|
||||||
|
return getPointToSegmentDistance(pos, p1, p2);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Math.min(...distances);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user