写在开头
Hello everyone! 🤠
在LogicFlow 交互新体验:让锚点"活"起来,鼠标跟随动效实战!🧲中,咱们解决了锚点的吸附交互问题。今天小编要分享的是另一项细节优化------连线轨迹(Trajectory)。
大家在使用 LogicFlow 时,默认的拖拽连线,无论你最终生成的边是折线还是曲线,在鼠标拖拽的过程中,跟随鼠标的那条线始终是一条笔直的虚线。
效果如下:

对于一个追求极致体验的项目来说,这多少有点 "出戏"。🤔
在小编的项目中,我们最终生成的边 是贝塞尔曲线,根据设计人员的要求,连线过程中也期望是以曲线的形式,以此匹配项目的整体设计规范。
于是,小编在翻阅 LogicFlow 文档时,找了一个 customTrajectory 属性,它能让咱们进行自定义连线轨迹。✨
非常灵活方便,在小编早期技术选型时,也是看中了 LogicFlow 库超强的自定义能力。
优化后的最终效果如下,请诸君按需食用哈。

需求背景
在小编项目中,节点之间的边采用的是三次贝塞尔曲线 (bezierCurveEdge),并且我们对边进行自定义开发。
但是,目前的痛点是:
- 视觉割裂:拖拽时是直线,松手后变曲线,视觉体验不连续。
- 风格不符:生硬的直线无法体现项目整体"圆润、流畅"的设计语言。
设计人员想要的效果是:
- 用户拖拽连线时,跟随鼠标的引导线直接展示为曲线。
- 引导线的曲率动态计算,与最终生成的边保持一致。
具体实现
LogicFlow 提供了一个非常强大的配置项 customTrajectory,允许我们自定义连线过程中引导线的渲染逻辑。
第1️⃣步:理解customTrajectory属性
从文档上看 customTrajectory 属性接收的是一个函数,扒其相关的源码。⏰
源码位置在: packages/core/src/view/Anchor.tsx
核心逻辑如下:

从源码中可以清晰地看到,customTrajectory 是一个优先级更高的渲染函数。它接收起点 (sourcePoint)、终点 (targetPoint) 以及样式配置 (edgeStyle),要求返回一个 VDOM 节点(它在 render 函数中,通常是 SVG 元素)。
LogicFlow 内部使用 Preact/React 的 VDOM 机制,所以我们需要引入其的 h 函数来创建元素。
第2️⃣步:编写贝塞尔轨迹算法
核心难点在于计算贝塞尔曲线的控制点。为了让曲线看起来自然,通常控制点会根据起点和终点的相对位置进行偏移。
咱们新建文件 customTrajectory.js:
javascript
import { h } from "@logicflow/core";
// 定义一些常量,保持与最终边的样式一致
const STROKE_COLOR = "#2961F7"; // 引导线颜色
const STROKE_WIDTH = 1;
/**
* @name 自定义连线轨迹
* @param {object} params 轨迹参数对象
* @param {{x:number,y:number}} params.sourcePoint 起点坐标
* @param {{x:number,y:number}} params.targetPoint 终点坐标(即鼠标当前位置)
* @returns {*} Preact 虚拟节点
*/
export default function customTrajectory({ sourcePoint, targetPoint, ...edgeStyle }) {
const { x: startX, y: startY } = sourcePoint;
const { x: endX, y: endY } = targetPoint;
// 1. 计算水平和垂直方向的距离
const dx = Math.abs(endX - startX);
const dy = Math.abs(endY - startY);
// 2. 计算控制点偏移量
// 这里采用"以水平方向为主"的策略,系数 0.6 是经验值,可以让曲线弯得更好看
const controlOffset = Math.max(dx, dy) * 0.6;
// 3. 生成三次贝塞尔曲线的路径(C 指令:C 控制点1.x,控制点1.y 控制点2.x,控制点2.y 终点.x,终点.y)
let d = "";
if (endX > startX && endY > startY) {
// 右下方向:控制点1 右上,控制点2 左下
d = `M ${startX},${startY} C ${startX + controlOffset},${startY} ${endX - controlOffset},${endY} ${endX},${endY}`;
} else if (endX > startX && endY < startY) {
// 右上方向:控制点1 右下,控制点2 左上
d = `M ${startX},${startY} C ${startX + controlOffset},${startY} ${endX - controlOffset},${endY} ${endX},${endY}`;
} else if (endX < startX && endY > startY) {
// 左下方向:控制点1 左上,控制点2 右下
d = `M ${startX},${startY} C ${startX - controlOffset},${startY} ${endX + controlOffset},${endY} ${endX},${endY}`;
} else {
// 左上方向:控制点1 左下,控制点2 右上
d = `M ${startX},${startY} C ${startX - controlOffset},${startY} ${endX + controlOffset},${endY} ${endX},${endY}`;
}
// 4. 返回 SVG Path 元素
return h(
"path",
{
d,
fill: "none",
pointerEvents: "none", // 极其重要!防止引导线阻挡鼠标事件
...edgeStyle,
strokeDasharray: undefined, // 小编的项目设计不需要虚线,所以清除掉,你可以根据自己需要
stroke: STROKE_COLOR,
strokeWidth: STROKE_WIDTH,
},
);
}
注意 🔉:这里的控制点计算逻辑(controlOffset)最好与你的边里的逻辑保持一致,这样松手的一瞬间,线条才不会有奇怪的 "跳动"。
这里如此复杂的计算是小编自己写的?那么牛?🐮
当然不是,这里小编也是借助了AI的协助。这要是放在几年前,这种交互效果直接就砍掉,实在太费劲了,现在不一样了,你让AI帮助你写,只要你提示词写得足够清楚,AI分分钟帮你解决,你只要调调参数,验收结果就行了。
第3️⃣步:注册配置
最后,在初始化 LogicFlow 时,将这个函数传给 customTrajectory 选项。
javascript
import LogicFlow from "@logicflow/core";
import customTrajectory from "./customTrajectory";
const lf = new LogicFlow({
container: document.querySelector("#container"),
// ... 其他配置
// 注册自定义轨迹
customTrajectory: customTrajectory,
// 确保最终生成的边也是贝塞尔曲线
edgeGenerator: () => "bezierCurveEdge",
});
总结
通过简单的数学计算和 VDOM 渲染,咱们成功将 LogicFlow 的连线轨迹从 "工业风" 的直线升级成了 "艺术风" 的曲线。😋
希望这个小技巧能让你的流程图编辑体验更加出色!🌟
至此,本篇文章就写完啦,撒花撒花。

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。