@logicflow/extension
Version:
LogicFlow Extensions
359 lines (358 loc) • 16.6 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import { twoPointDistance, isInNode, } from '@logicflow/core';
import { assign, isEmpty, isEqual, isNil, isFinite, reduce } from 'lodash-es';
var ProximityConnect = /** @class */ (function () {
function ProximityConnect(_a) {
var lf = _a.lf, options = _a.options;
this.enable = true;
this.currentDistance = Infinity; // 当前间距
this.thresholdDistance = 100; // 节点-节点连接距离阈值
this.reverseDirection = false; // 节点-节点连线方向,默认是拖拽节点连向最近节点
this.virtualEdgeStyle = {
strokeDasharray: '10,10',
stroke: '#acacac',
}; // 虚拟边样式
this.lf = lf;
assign(this, options);
}
ProximityConnect.prototype.render = function () {
this.addEventListeners();
};
// 增加节点拖拽和锚点拖拽的事件监听
ProximityConnect.prototype.addEventListeners = function () {
var _this = this;
// 节点开始拖拽事件
this.lf.graphModel.eventCenter.on('node:dragstart', function (_a) {
var data = _a.data;
if (!_this.enable)
return;
var graphModel = _this.lf.graphModel;
var id = data.id;
_this.currentNode = graphModel.getNodeModelById(id);
});
// 节点拖拽事件
this.lf.graphModel.eventCenter.on('node:drag', function () {
_this.handleNodeDrag();
});
// 锚点开始拖拽事件
this.lf.graphModel.eventCenter.on('anchor:dragstart', function (_a) {
var data = _a.data, nodeModel = _a.nodeModel;
if (!_this.enable)
return;
_this.currentNode = nodeModel;
_this.currentAnchor = data;
});
// 锚点拖拽事件
this.lf.graphModel.eventCenter.on('anchor:drag', function (_a) {
var _b = _a.e, clientX = _b.clientX, clientY = _b.clientY;
if (!_this.enable)
return;
_this.handleAnchorDrag(clientX, clientY);
});
// 节点、锚点拖拽结束事件
this.lf.graphModel.eventCenter.on('node:drop', function () {
if (!_this.enable)
return;
_this.handleDrop();
});
// 锚点拖拽需要单独判断一下当前拖拽终点是否在某个锚点上,如果是,就不触发插件的连线,以免出现创建了两条连线的问题,表现见 issue 2140
this.lf.graphModel.eventCenter.on('anchor:dragend', function (_a) {
var e = _a.e, edgeModel = _a.edgeModel;
if (!_this.enable)
return;
var _b = _this.lf.graphModel.getPointByClient({
x: e.clientX,
y: e.clientY,
}).canvasOverlayPosition, eventX = _b.x, eventY = _b.y;
if (edgeModel && _this.virtualEdge) {
var virtualEdgeId = _this.virtualEdge.id;
var targetNodeId = edgeModel.targetNodeId;
var targetNodeModel = _this.lf.graphModel.getNodeModelById(targetNodeId);
if (targetNodeModel &&
isInNode({ x: eventX, y: eventY }, targetNodeModel, 10)) {
// 如果当前拖拽点在锚点上,就不触发插件的连线
_this.lf.deleteEdge(virtualEdgeId);
return;
}
}
_this.handleDrop();
});
};
// 节点拖拽动作
ProximityConnect.prototype.handleNodeDrag = function () {
/**
* 主要做几件事情
* 判断当前是否有虚拟连线,有的话判断两点距离是否超过阈值,超过的话删除连线
* 遍历画布上的所有节点,找到距离最近的节点,获取其所有锚点数据
* 判断每个锚点与当前选中节点的所有锚点之间的距离,找到路路径最短的两个点时,把当前节点、当前锚点当前最短记录记录下来,作为当前最近数据
* 判断当前最短距离是否小于阈值
* 如果是 就创建虚拟边
*/
var nodes = this.lf.graphModel.nodes;
if (!isNil(this.virtualEdge)) {
var _a = this.virtualEdge, startPoint = _a.startPoint, endPoint = _a.endPoint, id = _a.id;
var curDistance = twoPointDistance(startPoint, endPoint);
if (curDistance > this.thresholdDistance) {
this.lf.deleteEdge(id);
this.virtualEdge = undefined;
}
}
if (this.currentNode) {
this.findClosestAnchorOfNode(this.currentNode, nodes);
}
if (this.currentDistance < this.thresholdDistance) {
this.addVirtualEdge();
}
};
// 节点放下
ProximityConnect.prototype.handleDrop = function () {
this.addActualEdge();
this.resetData();
};
// 锚点拖拽动作
ProximityConnect.prototype.handleAnchorDrag = function (clientX, clientY) {
// 获取当前点在画布上的位置
var graphModel = this.lf.graphModel;
var _a = graphModel.getPointByClient({
x: clientX,
y: clientY,
}).canvasOverlayPosition, x = _a.x, y = _a.y;
if (isNil(x) || isNil(y))
return;
var currentPoint = { x: x, y: y };
var nodes = graphModel.nodes;
// 判断当前是否有虚拟连线,有的话判断两点距离是否超过阈值,超过的话删除连线
if (!isNil(this.virtualEdge)) {
var _b = this.virtualEdge, endPoint = _b.endPoint, id = _b.id;
var curDistance = twoPointDistance(currentPoint, endPoint);
if (curDistance > this.thresholdDistance) {
this.lf.deleteEdge(id);
this.virtualEdge = undefined;
}
}
// 记录最近点的信息
this.findClosestAnchorOfAnchor(currentPoint, nodes);
if (this.currentDistance < this.thresholdDistance) {
this.addVirtualEdge();
}
};
// 节点→节点 找最近的节点和锚点
ProximityConnect.prototype.findClosestAnchorOfNode = function (draggingNode, allNodes) {
var _this = this;
if (isNil(draggingNode) || isEmpty(draggingNode))
return;
var _a = draggingNode.anchors, draggingAnchors = _a === void 0 ? [] : _a, id = draggingNode.id;
var distance;
var preConnectAnchor;
var closestAnchor;
var closestNode;
allNodes.forEach(function (node) {
if (isEqual(node.id, id))
return;
var _a = node.anchors, anchors = _a === void 0 ? [] : _a;
// 遍历所有节点,找离当前拖拽节点最近的可连接节点和锚点
anchors.forEach(function (anchor) {
// 找距离最近的两个锚点
draggingAnchors.forEach(function (draggingAnchor) {
// 判断拖拽点锚点和当前锚点是否可连线
var anchorAllowConnect = _this.anchorAllowConnect(node, anchor, draggingAnchor);
if (!anchorAllowConnect)
return;
// 获取两个锚点之间的距离
var curDistance = twoPointDistance(draggingAnchor, anchor);
if (!distance || curDistance < distance) {
// 如果是第一条数据,或者当前这对锚点距离更短,就替换数据
distance = curDistance;
preConnectAnchor = draggingAnchor;
closestAnchor = anchor;
closestNode = node;
}
});
});
});
this.currentDistance = distance;
this.currentAnchor = preConnectAnchor;
this.closestAnchor = closestAnchor;
this.closestNode = closestNode;
};
// 锚点→节点 找最近的锚点
ProximityConnect.prototype.findClosestAnchorOfAnchor = function (draggingPoint, allNodes) {
var _this = this;
if (isNil(draggingPoint))
return;
var distance;
var closestAnchor;
var closestNode;
var _a = this, currentNode = _a.currentNode, currentAnchor = _a.currentAnchor;
allNodes.forEach(function (node) {
if (!currentNode)
return;
var _a = node.anchors, anchors = _a === void 0 ? [] : _a;
// 遍历所有节点,找离当前拖拽节点最近的可连接节点和锚点
anchors.forEach(function (anchor) {
var _a;
if (isEqual((_a = _this.currentAnchor) === null || _a === void 0 ? void 0 : _a.id, anchor.id))
return;
// 判断拖拽点锚点和当前锚点是否可连线
var anchorAllowConnect = _this.anchorAllowConnect(node, anchor, currentAnchor);
if (!anchorAllowConnect)
return;
// 获取两个锚点之间的距离
var curDistance = twoPointDistance(draggingPoint, anchor);
if (!distance || curDistance < distance) {
// 如果是第一条数据,或者当前这对锚点距离更短,就替换数据
distance = curDistance;
closestAnchor = anchor;
closestNode = node;
}
});
});
this.currentDistance = distance;
this.closestAnchor = closestAnchor;
this.closestNode = closestNode;
};
// 判断锚点是否允许连线
ProximityConnect.prototype.anchorAllowConnect = function (node, anchor, draggingAnchor) {
var currentNode = this.currentNode;
if (!currentNode)
return;
// 判断起点是否可连接
var sourceValidResult = (this.reverseDirection
? node.isAllowConnectedAsSource(currentNode, anchor, draggingAnchor)
: currentNode.isAllowConnectedAsSource(node, draggingAnchor, anchor)).isAllPass;
// 判断终点是否可连接
var targetValidResult = (this.reverseDirection
? currentNode.isAllowConnectedAsTarget(node, anchor, draggingAnchor)
: node.isAllowConnectedAsTarget(currentNode, draggingAnchor, anchor)).isAllPass;
return sourceValidResult && targetValidResult;
};
// 判断是否应该删除虚拟边
ProximityConnect.prototype.sameEdgeIsExist = function (edge) {
if (isNil(this.closestNode) ||
isNil(this.currentNode) ||
isNil(this.closestAnchor) ||
isNil(this.currentAnchor))
return false;
if (isNil(edge))
return false;
var _a = this, closestNodeId = _a.closestNode.id, currentNodeId = _a.currentNode.id, closestAnchorId = _a.closestAnchor.id, currentAnchorId = _a.currentAnchor.id, reverseDirection = _a.reverseDirection;
var sourceNodeId = edge.sourceNodeId, targetNodeId = edge.targetNodeId, sourceAnchorId = edge.sourceAnchorId, targetAnchorId = edge.targetAnchorId;
var isExist = reverseDirection
? isEqual(closestNodeId, sourceNodeId) &&
isEqual(currentNodeId, targetNodeId) &&
isEqual(closestAnchorId, sourceAnchorId) &&
isEqual(currentAnchorId, targetAnchorId)
: isEqual(currentNodeId, sourceNodeId) &&
isEqual(closestNodeId, targetNodeId) &&
isEqual(currentAnchorId, sourceAnchorId) &&
isEqual(closestAnchorId, targetAnchorId);
return isExist;
};
// 增加虚拟边
ProximityConnect.prototype.addVirtualEdge = function () {
var _this = this;
var edges = this.lf.graphModel.edges;
// 判断当前是否已存在一条同样配置的真实边
var actualEdgeIsExist = reduce(edges, function (result, edge) {
if (edge.virtual)
return result;
return result || _this.sameEdgeIsExist(edge);
}, false);
// 如果有真实边就不重复创建边了
if (actualEdgeIsExist)
return;
// 判断当前是否有虚拟边
// 如果当前已有虚拟边,判断当前的节点和锚点信息与虚拟边的信息是否一致
if (!isNil(this.virtualEdge)) {
var edgeId = this.virtualEdge.id;
// 信息一致不做处理
if (this.sameEdgeIsExist(this.virtualEdge))
return;
// 不一致就删除老边
this.lf.deleteEdge(edgeId);
}
// 开始创建虚拟边
var _a = this, reverseDirection = _a.reverseDirection, currentNode = _a.currentNode, closestNode = _a.closestNode, currentAnchor = _a.currentAnchor, closestAnchor = _a.closestAnchor;
if (isEmpty(currentNode) || isEmpty(closestNode))
return;
var properties = {
style: this.virtualEdgeStyle,
};
this.virtualEdge = this.lf.addEdge(reverseDirection
? {
sourceNodeId: closestNode === null || closestNode === void 0 ? void 0 : closestNode.id,
targetNodeId: currentNode === null || currentNode === void 0 ? void 0 : currentNode.id,
sourceAnchorId: closestAnchor === null || closestAnchor === void 0 ? void 0 : closestAnchor.id,
targetAnchorId: currentAnchor === null || currentAnchor === void 0 ? void 0 : currentAnchor.id,
properties: properties,
}
: {
sourceNodeId: currentNode === null || currentNode === void 0 ? void 0 : currentNode.id,
targetNodeId: closestNode === null || closestNode === void 0 ? void 0 : closestNode.id,
sourceAnchorId: currentAnchor === null || currentAnchor === void 0 ? void 0 : currentAnchor.id,
targetAnchorId: closestAnchor === null || closestAnchor === void 0 ? void 0 : closestAnchor.id,
properties: properties,
});
this.virtualEdge.virtual = true;
};
// 增加实体边
ProximityConnect.prototype.addActualEdge = function () {
if (isNil(this.virtualEdge))
return;
var _a = this.virtualEdge, type = _a.type, sourceNodeId = _a.sourceNodeId, targetNodeId = _a.targetNodeId, sourceAnchorId = _a.sourceAnchorId, targetAnchorId = _a.targetAnchorId, startPoint = _a.startPoint, endPoint = _a.endPoint, pointsList = _a.pointsList;
this.lf.deleteEdge(this.virtualEdge.id);
this.lf.addEdge({
type: type,
sourceNodeId: sourceNodeId,
targetNodeId: targetNodeId,
sourceAnchorId: sourceAnchorId,
targetAnchorId: targetAnchorId,
startPoint: startPoint,
endPoint: endPoint,
pointsList: pointsList,
});
};
// 设置虚拟边样式
ProximityConnect.prototype.setVirtualEdgeStyle = function (value) {
this.virtualEdgeStyle = __assign(__assign({}, this.virtualEdgeStyle), value);
};
// 设置连线阈值
ProximityConnect.prototype.setThresholdDistance = function (distance) {
if (!isFinite(distance))
return;
this.thresholdDistance = distance;
};
// 设置连线方向
ProximityConnect.prototype.setReverseDirection = function (value) {
this.reverseDirection = value;
};
// 设置插件开关状态
ProximityConnect.prototype.setEnable = function (enable) {
this.enable = enable;
if (!enable) {
this.resetData();
}
};
// 重置数据
ProximityConnect.prototype.resetData = function () {
this.closestNode = undefined;
this.currentDistance = Infinity;
this.currentNode = undefined;
this.currentAnchor = undefined;
this.closestAnchor = undefined;
this.virtualEdge = undefined;
};
ProximityConnect.pluginName = 'proximityConnect';
return ProximityConnect;
}());
export { ProximityConnect };