UNPKG

@logicflow/extension

Version:
359 lines (358 loc) 16.6 kB
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 };