UNPKG

@logicflow/extension

Version:
668 lines (667 loc) 32.8 kB
"use strict"; 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); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DynamicGroup = exports.dynamicGroup = void 0; var core_1 = require("@logicflow/core"); var lodash_es_1 = require("lodash-es"); var node_1 = require("./node"); var model_1 = require("./model"); var utils_1 = require("./utils"); __exportStar(require("./node"), exports); __exportStar(require("./model"), exports); exports.dynamicGroup = { type: 'dynamic-group', view: node_1.DynamicGroupNode, model: model_1.DynamicGroupNodeModel, }; var DEFAULT_TOP_Z_INDEX = -1000; var DEFAULT_BOTTOM_Z_INDEX = -10000; var DynamicGroup = /** @class */ (function () { function DynamicGroup(_a) { var lf = _a.lf, options = _a.options; var _this = this; this.topGroupZIndex = DEFAULT_BOTTOM_Z_INDEX; // 存储节点与 group 的映射关系 this.nodeGroupMap = new Map(); this.onSelectionDrop = function () { var selectedNodes = _this.lf.graphModel.getSelectElements().nodes; selectedNodes.forEach(function (node) { _this.addNodeToGroup(node); }); }; this.onNodeAddOrDrop = function (_a) { var node = _a.data; _this.addNodeToGroup(node); }; this.addNodeToGroup = function (node) { // 1. 如果该节点之前已经在 group 中了,则将其从之前的 group 移除 var preGroupId = _this.nodeGroupMap.get(node.id); if (preGroupId) { var group = _this.lf.getNodeModelById(preGroupId); group.removeChild(node.id); _this.nodeGroupMap.delete(node.id); group.setAllowAppendChild(false); } // 2. 然后再判断这个节点是否在某个 group 范围内,如果是,则将其添加到对应的 group 中 var nodeModel = _this.lf.getNodeModelById(node.id); var bounds = nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.getBounds(); if (nodeModel && bounds) { // TODO: 确认下面的注释内容 // https://github.com/didi/LogicFlow/issues/1261 // 当使用 SelectionSelect 框选后触发 lf.addNode(Group) // 会触发 appendNodeToGroup() 的执行 // 由于 this.getGroup() 会判断 node.id !== nodeData.id // 因此当 addNode 是 Group 类型时,this.getGroup() 会一直返回空 // 导致了下面这段代码无法执行,也就是无法将当前添加的 Group 添加到 this.nodeGroupMap 中 // 这导致了折叠分组时触发的 foldEdge() 无法正确通过 getNodeGroup() 拿到正确的 groupId // 从而导致折叠分组时一直都会创建一个虚拟边 // 而初始化分组时由于正确设置了nodeGroupMap的数据,因此不会产生虚拟边的错误情况 if (nodeModel.isGroup) { var group_1 = nodeModel; (0, lodash_es_1.forEach)(Array.from(group_1.children), function (childId) { _this.nodeGroupMap.set(childId, node.id); }); // 新增 node 时进行 this.topGroupZIndex 的校准更新 _this.calibrateTopGroupZIndex([node]); _this.onNodeSelect({ data: node, isSelected: false, isMultiple: false, }); } // TODO: 找到这个范围内的 groupModel, 并加 node 添加到该 group var group = _this.getGroupByBounds(bounds, node); if (group) { var isAllowAppendIn = group.isAllowAppendIn(node); if (isAllowAppendIn) { group.addChild(node.id); // 建立节点与 group 的映射关系放在了 group.addChild 触发的事件中,与直接调用 addChild 的行为保持一致 group.setAllowAppendChild(false); } else { // 抛出不允许插入的事件 _this.lf.emit('group:not-allowed', { group: group.getData(), node: node, }); } } } }; this.onGroupAddNode = function (_a) { var groupData = _a.data, childId = _a.childId; _this.nodeGroupMap.set(childId, groupData.id); }; this.removeNodeFromGroup = function (_a) { var node = _a.data, model = _a.model; if (model.isGroup && node.children) { (0, lodash_es_1.forEach)(Array.from(node.children), function (childId) { _this.nodeGroupMap.delete(childId); _this.lf.deleteNode(childId); }); } var groupId = _this.nodeGroupMap.get(node.id); if (groupId) { var group = _this.lf.getNodeModelById(groupId); group && group.removeChild(node.id); _this.nodeGroupMap.delete(node.id); } }; this.onSelectionDrag = function () { var selectedNodes = _this.lf.graphModel.getSelectElements().nodes; selectedNodes.forEach(function (node) { _this.setActiveGroup(node); }); }; this.onNodeDrag = function (_a) { var node = _a.data; _this.setActiveGroup(node); }; this.setActiveGroup = function (node) { var nodeModel = _this.lf.getNodeModelById(node.id); var bounds = nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.getBounds(); if (nodeModel && bounds) { var targetGroup = _this.getGroupByBounds(bounds, node); if (_this.activeGroup) { _this.activeGroup.setAllowAppendChild(false); } if (!targetGroup || (nodeModel.isGroup && targetGroup.id === node.id)) { return; } var isAllowAppendIn = targetGroup.isAllowAppendIn(node); if (!isAllowAppendIn) return; _this.activeGroup = targetGroup; _this.activeGroup.setAllowAppendChild(true); } }; /** * 1. 分组节点默认在普通节点下面 * 2. 分组节点被选中后,会将分组节点以及其内部的其它分组节点放到其余分组节点的上面 * 3. 分组节点取消选中后,不会将分组节点重置为原来的高度 * 4. 由于 LogicFlow 核心目标是支持用户手动绘制流程图,所以暂时不支持一张流程图超过 1000 个分组节点的情况 * @param node * @param isMultiple * @param isSelected */ this.onNodeSelect = function (_a) { var node = _a.data, isMultiple = _a.isMultiple, isSelected = _a.isSelected; var nodeModel = _this.lf.getNodeModelById(node.id); _this.sendNodeToFront(nodeModel); // 重置所有 group 的 zIndex,防止 group 节点 zIndex 增长为正数(目的是保持 group 节点在最底层) if (_this.topGroupZIndex > DEFAULT_TOP_Z_INDEX) { var nodes = _this.lf.graphModel.nodes; _this.topGroupZIndex = DEFAULT_BOTTOM_Z_INDEX; var groups = (0, lodash_es_1.sortBy)((0, lodash_es_1.filter)(nodes, function (node) { return !!node.isGroup; }), 'zIndex'); var preZIndex_1 = 0; (0, lodash_es_1.forEach)(groups, function (group) { if (group.zIndex !== preZIndex_1) { _this.topGroupZIndex++; preZIndex_1 = group.zIndex; } group.setZIndex(_this.topGroupZIndex); }); } // FIX #1004 // 如果节点被多选, // 这个节点是分组,则将分组的所有子节点取消选中 // 这个节点是分组的子节点,且其所属分组节点已选,则取消选中 if (isMultiple && isSelected) { if (nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.isGroup) { var children = nodeModel.children; (0, lodash_es_1.forEach)(Array.from(children), function (childId) { var childModel = _this.lf.getNodeModelById(childId); childModel === null || childModel === void 0 ? void 0 : childModel.setSelected(false); }); } else { var groupId = _this.nodeGroupMap.get(node.id); if (groupId) { var graphModel = _this.lf.getNodeModelById(groupId); (graphModel === null || graphModel === void 0 ? void 0 : graphModel.isSelected) && (nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.setSelected(false)); } } } }; this.onNodeMove = function (_a) { var deltaX = _a.deltaX, deltaY = _a.deltaY, data = _a.data; var id = data.id, x = data.x, y = data.y, properties = data.properties; if (!properties) { return; } var width = properties.width, height = properties.height; var groupId = _this.nodeGroupMap.get(id); if (!groupId) { return; } var groupModel = _this.lf.getNodeModelById(groupId); if (!groupModel || !groupModel.isRestrict || !groupModel.autoResize) { return; } // 当父节点isRestrict=true & autoResize=true // 子节点在父节点中移动时,父节点会自动调整大小 // step1: 计算出当前child的bounds var newX = x + deltaX / 2; var newY = y + deltaY / 2; var minX = newX - width / 2; var minY = newY - height / 2; var maxX = newX + width / 2; var maxY = newY + height / 2; // step2:比较当前child.bounds与parent.bounds的差异,比如child.minX<parent.minX,那么parent.minX=child.minX var hasChange = false; var groupBounds = groupModel.getBounds(); var newGroupBounds = Object.assign({}, groupBounds); if (minX < newGroupBounds.minX) { newGroupBounds.minX = minX; hasChange = true; } if (minY < newGroupBounds.minY) { newGroupBounds.minY = minY; hasChange = true; } if (maxX > newGroupBounds.maxX) { newGroupBounds.maxX = maxX; hasChange = true; } if (maxY > newGroupBounds.maxY) { newGroupBounds.maxY = maxY; hasChange = true; } if (!hasChange) { return; } // step3: 根据当前parent.bounds去计算出最新的x、y、width、height var newGroupX = newGroupBounds.minX + (newGroupBounds.maxX - newGroupBounds.minX) / 2; var newGroupY = newGroupBounds.minY + (newGroupBounds.maxY - newGroupBounds.minY) / 2; var newGroupWidth = newGroupBounds.maxX - newGroupBounds.minX; var newGroupHeight = newGroupBounds.maxY - newGroupBounds.minY; groupModel.moveTo(newGroupX, newGroupY); groupModel.width = newGroupWidth; groupModel.height = newGroupHeight; }; this.onGraphRendered = function (_a) { var data = _a.data; (0, lodash_es_1.forEach)(data.nodes, function (node) { if (node.children) { (0, lodash_es_1.forEach)(node.children, function (childId) { _this.nodeGroupMap.set(childId, node.id); }); } }); // TODO: 确认一下下面方法的必要性及合理性 // 初始化 nodes 时进行 this.topGroupZIndex 的校准更新 _this.calibrateTopGroupZIndex(data.nodes); }; lf.register(exports.dynamicGroup); this.lf = lf; (0, lodash_es_1.assign)(this, options); // 初始化插件,从监听事件开始及设置规则开始 this.init(); } /** * 获取节点所属的分组 * @param nodeId */ DynamicGroup.prototype.getGroupByNodeId = function (nodeId) { var groupId = this.nodeGroupMap.get(nodeId); if (groupId) { return this.lf.getNodeModelById(groupId); } }; /** * 获取自定位置及其所属分组 * 当分组重合时,优先返回最上层的分组 * @param bounds * @param nodeData */ DynamicGroup.prototype.getGroupByBounds = function (bounds, nodeData) { var nodes = this.lf.graphModel.nodes; var groups = (0, lodash_es_1.filter)(nodes, function (node) { return (!!node.isGroup && (0, utils_1.isBoundsInGroup)(bounds, node) && node.id !== nodeData.id); }); var count = groups.length; if (count <= 1) { return groups[0]; } else { var topZIndexGroup = groups[count - 1]; for (var i = count - 2; i >= 0; i--) { if (groups[i].zIndex > topZIndexGroup.zIndex) { topZIndexGroup = groups[i]; } } return topZIndexGroup; } }; /** * 提高元素的层级,如果是 group,同时提高其子元素的层级 * @param model */ DynamicGroup.prototype.sendNodeToFront = function (model) { var _this = this; if (!model || !model.isGroup) return; this.topGroupZIndex++; model.setZIndex(this.topGroupZIndex); if (model.children) { var children = model.children; (0, lodash_es_1.forEach)(Array.from(children), function (nodeId) { var node = _this.lf.getNodeModelById(nodeId); _this.sendNodeToFront(node); }); } }; /** * 递归计算某个分组内最高的 zIndex 值 * TODO: 这块儿有点疑问❓如果 node 不是 group,这块儿返回的 maxZIndex 是最小值,但 node 的 zIndex 不一定是这个值 * @param node */ DynamicGroup.prototype.getMaxZIndex = function (node) { var _this = this; var maxZIndex = DEFAULT_BOTTOM_Z_INDEX; if (node.isGroup) { maxZIndex = Math.max(maxZIndex, node.zIndex); } if (node.children) { var children = node.children; (0, lodash_es_1.forEach)(Array.from(children), function (childId) { var child = _this.lf.getNodeModelById(childId); if (child === null || child === void 0 ? void 0 : child.isGroup) { var childMaxZIndex = _this.getMaxZIndex(child); maxZIndex = Math.max(maxZIndex, childMaxZIndex); } }); } return maxZIndex; }; /** * 校准当前 topGroupZIndex 的值 * @param nodes */ DynamicGroup.prototype.calibrateTopGroupZIndex = function (nodes) { var _this = this; // 初始化时 or 增加新节点时,找出所有 nodes 的最大 zIndex var maxZIndex = DEFAULT_BOTTOM_Z_INDEX; (0, lodash_es_1.forEach)(nodes, function (node) { var nodeModel = _this.lf.getNodeModelById(node.id); if (nodeModel) { var currNodeMaxZIndex = _this.getMaxZIndex(nodeModel); if (currNodeMaxZIndex > maxZIndex) { maxZIndex = currNodeMaxZIndex; } } }); // TODO: 不是很理解这块儿的代码逻辑,需要整理一下 if (this.topGroupZIndex >= maxZIndex) { // 一般是初始化时/增加新节点时发生,因为外部强行设置了一个很大的 zIndex // 删除节点不会影响目前最高 zIndex 的赋值 return; } // 新增 nodes 中如果存在 zIndex 比 this.topGroupZIndex 大 // 说明 this.topGroupZIndex 已经失去意义,代表不了目前最高 zIndex 的 group,需要重新校准 // https://github.com/didi/LogicFlow/issues/1535 // 当外部直接设置多个 BaseNode.zIndex = 1 时 // 当点击某一个 node 时,由于这个 this.topGroupZIndex 是从 -10000 开始计算的, // this.topGroupZIndex + 1 也就是-9999,这就造成当前点击的 node 的 zIndex 远远 // 比其它 node 的 zIndex 小,因此造成 zIndex 错乱的问题 // TODO: 这儿的 nodes 能否直接用传参进来的 nodes 呢??? var allNodes = this.lf.graphModel.nodes; var allGroups = (0, lodash_es_1.filter)(allNodes, function (node) { return !!node.isGroup; }); var max = this.topGroupZIndex; (0, lodash_es_1.forEach)(allGroups, function (group) { if (group.zIndex > max) max = group.zIndex; }); this.topGroupZIndex = max; }; DynamicGroup.prototype.removeChildrenInGroupNodeData = function (nodeData) { var _a; var newNodeData = (0, lodash_es_1.cloneDeep)(nodeData); delete newNodeData.children; if ((_a = newNodeData.properties) === null || _a === void 0 ? void 0 : _a.children) { delete newNodeData.properties.children; } return newNodeData; }; /** * 创建一个 Group 类型节点内部所有子节点的副本 * 并且在遍历所有 nodes 的过程中,顺便拿到所有 edges (只在 Group 范围的 edges) */ DynamicGroup.prototype.initGroupChildNodes = function (nodeIdMap, children, curGroup, distance) { var _this = this; // Group 中所有子节点 var allChildNodes = []; // 属于 Group 内部边的 EdgeData var edgesDataArr = []; // 所有有关联的连线 var allRelatedEdges = []; (0, lodash_es_1.forEach)(Array.from(children), function (childId) { var childNode = _this.lf.getNodeModelById(childId); if (childNode) { var childNodeChildren = childNode.children; var childNodeData = childNode.getData(); var eventType = core_1.EventType.NODE_GROUP_COPY || 'node:group-copy-add'; var newNodeConfig = (0, core_1.transformNodeData)(_this.removeChildrenInGroupNodeData(childNodeData), distance); var tempChildNode = _this.lf.addNode(newNodeConfig, eventType); curGroup.addChild(tempChildNode.id); nodeIdMap[childId] = tempChildNode.id; // id 同 childId,做映射存储 allChildNodes.push(tempChildNode); // 1. 存储 children 内部节点相关的输入边(incoming) allRelatedEdges.push.apply(allRelatedEdges, __spreadArray([], __read(__spreadArray(__spreadArray([], __read(tempChildNode.incoming.edges), false), __read(tempChildNode.outgoing.edges), false)), false)); if (childNodeChildren instanceof Set) { var _a = _this.initGroupChildNodes(nodeIdMap, childNodeChildren, tempChildNode, distance), childNodes = _a.childNodes, edgesData = _a.edgesData; allChildNodes.push.apply(allChildNodes, __spreadArray([], __read(childNodes), false)); edgesDataArr.push.apply(edgesDataArr, __spreadArray([], __read(edgesData), false)); } } }); // 1. 判断每一条边的开始节点、目标节点是否在 Group 中 var edgesInnerGroup = (0, lodash_es_1.filter)(allRelatedEdges, function (edge) { return ((0, lodash_es_1.has)(nodeIdMap, edge.sourceNodeId) && (0, lodash_es_1.has)(nodeIdMap, edge.targetNodeId)); }); // 2. 为「每一条 Group 的内部边」构建出 EdgeData 数据,得到 EdgeConfig,生成新的线 var edgesDataInnerGroup = (0, lodash_es_1.map)(edgesInnerGroup, function (edge) { return edge.getData(); }); return { childNodes: allChildNodes, edgesData: edgesDataArr.concat(edgesDataInnerGroup), }; }; /** * 根据参数 edge 选择是新建边还是基于已有边,复制一条边出来 * @param edge * @param nodeIdMap * @param distance */ DynamicGroup.prototype.createEdge = function (edge, nodeIdMap, distance) { var _a, _b; var sourceNodeId = edge.sourceNodeId, targetNodeId = edge.targetNodeId; var sourceId = (_a = nodeIdMap[sourceNodeId]) !== null && _a !== void 0 ? _a : sourceNodeId; var targetId = (_b = nodeIdMap[targetNodeId]) !== null && _b !== void 0 ? _b : targetNodeId; // 如果是有 id 且 text 是对象的边,需要重新计算位置,否则直接用 edgeConfig 生成边 var newEdgeConfig = (0, lodash_es_1.cloneDeep)(edge); if (edge.id && typeof edge.text === 'object' && edge.text !== null) { newEdgeConfig = (0, core_1.transformEdgeData)(edge, distance); } return this.lf.graphModel.addEdge(__assign(__assign({}, newEdgeConfig), { sourceNodeId: sourceId, targetNodeId: targetId })); }; /** * 检测group:resize后的bounds是否会小于children的bounds * 限制group进行resize时不能小于内部的占地面积 * @param groupModel * @param deltaX * @param deltaY * @param newWidth * @param newHeight */ DynamicGroup.prototype.checkGroupBoundsWithChildren = function (groupModel, deltaX, deltaY, newWidth, newHeight) { if (groupModel.children) { var children = groupModel.children, x = groupModel.x, y = groupModel.y; // 根据deltaX和deltaY计算出当前model的bounds var newX = x + deltaX / 2; var newY = y + deltaY / 2; var groupMinX = newX - newWidth / 2; var groupMinY = newY - newHeight / 2; var groupMaxX = newX + newWidth / 2; var groupMaxY = newY + newHeight / 2; var childrenArray = Array.from(children); for (var i = 0; i < childrenArray.length; i++) { var childId = childrenArray[i]; var child = this.lf.getNodeModelById(childId); if (!child) { continue; } var childBounds = child.getBounds(); var minX = childBounds.minX, minY = childBounds.minY, maxX = childBounds.maxX, maxY = childBounds.maxY; // parent:resize后的bounds不能小于child:bounds,否则阻止其resize var canResize = groupMinX <= minX && groupMinY <= minY && groupMaxX >= maxX && groupMaxY >= maxY; if (!canResize) { return false; } } } return true; }; /** * Group 插件的初始化方法 * TODO:1. 待讨论,可能之前插件分类是有意义的 components, material, tools * 区别是:1. 有些插件就是自定义节点,可能会有初始化方法 init,但不必要有 render (比如 Group) * 2. 有些插件是渲染一些部件(比如 MiniMap、Control、Menu 等)必须要有 render * 3. 工具类的,init 、 render * 该如何分类呢?并如何完善插件的类型 * * TODO: 2. 插件的 destroy 方法该做些什么,是否应该加 destroy 方法 * TODO: 3. 是否应该定义一个 Extension 的基类,所有插件基于这个基类来开发,这样在初始化的时候就可以确认执行什么方法 */ DynamicGroup.prototype.init = function () { var _this = this; var lf = this.lf; var graphModel = lf.graphModel; // 添加分组节点移动规则 // 1. 移动分组节点时,同时移动分组内所有节点 // 2. 移动子节点时,判断是否有限制规则(isRestrict) graphModel.addNodeMoveRules(function (model, deltaX, deltaY) { // 判断如果是 group,移动时需要同时移动组内的所有节点 if (model.isGroup) { // https://github.com/didi/LogicFlow/issues/1826 // 这里不应该触发移动子节点的逻辑,这里是判断是否可以移动,而不是触发移动逻辑 // 而且这里触发移动,会导致resize操作的this.x变动也会触发子item的this.x变动 // resize时的deltaX跟正常移动的deltaX是不同的 // const nodeIds = this.getNodesInGroup(model as DynamicGroupNodeModel) // graphModel.moveNodes(nodeIds, deltaX, deltaY, true) return true; } var groupId = _this.nodeGroupMap.get(model.id); var groupModel = _this.lf.getNodeModelById(groupId); if (groupModel && groupModel.isRestrict) { if (groupModel.autoResize) { // 子节点在父节点中移动时,父节点会自动调整大小 // 在node:mousemove中进行父节点的调整 return true; } else { // 如果移动的节点存在于某个分组中,且这个分组禁止子节点移出去 var groupBounds = groupModel.getBounds(); return (0, utils_1.isAllowMoveTo)(groupBounds, model, deltaX, deltaY); } } return true; }); // https://github.com/didi/LogicFlow/issues/1442 // https://github.com/didi/LogicFlow/issues/937 // 添加分组节点resize规则 // isRestrict限制模式下,当前model resize时不能小于children的占地面积 // 并且在isRestrict限制模式下,transformWidthContainer即使设置为true,也无效 graphModel.addNodeResizeRules(function (model, deltaX, deltaY, width, height) { if (model.isGroup && model.isRestrict) { return _this.checkGroupBoundsWithChildren(model, deltaX, deltaY, width, height); } return true; }); graphModel.dynamicGroup = this; lf.on('node:add,node:drop,node:dnd-add', this.onNodeAddOrDrop); lf.on('selection:drop', this.onSelectionDrop); lf.on('node:delete', this.removeNodeFromGroup); lf.on('node:drag,node:dnd-drag', this.onNodeDrag); lf.on('selection:drag', this.onSelectionDrag); lf.on('node:click', this.onNodeSelect); lf.on('node:mousemove', this.onNodeMove); lf.on('graph:rendered', this.onGraphRendered); lf.on('group:add-node', this.onGroupAddNode); // https://github.com/didi/LogicFlow/issues/1346 // 重写 addElements() 方法,在 addElements() 原有基础上增加对 group 内部所有 nodes 和 edges 的复制功能 // 使用场景:addElements api 项目内部目前只在快捷键粘贴时使用(此处解决的也应该是粘贴场景的问题) lf.addElements = function (_a, distance) { var selectedNodes = _a.nodes, selectedEdges = _a.edges; if (distance === void 0) { distance = 40; } // oldNodeId -> newNodeId 映射 Map var nodeIdMap = {}; // 本次添加的所有节点和边 var elements = { nodes: [], edges: [], }; // 所有属于分组内的边 -> sourceNodeId 和 targetNodeId 都在 Group 内 var edgesInnerGroup = []; (0, lodash_es_1.forEach)(selectedNodes, function (node) { var _a, _b; var originId = node.id; var children = (_b = (_a = node.properties) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : node.children; var model = lf.addNode(_this.removeChildrenInGroupNodeData(node)); if (originId) nodeIdMap[originId] = model.id; elements.nodes.push(model); // 此时为 group 的 nodeModel // TODO: 递归创建 group 的 nodeModel 的 children if (model.isGroup) { var edgesData = _this.initGroupChildNodes(nodeIdMap, children, model, distance).edgesData; edgesInnerGroup.push.apply(edgesInnerGroup, __spreadArray([], __read(edgesData), false)); } }); (0, lodash_es_1.forEach)(edgesInnerGroup, function (edge) { _this.createEdge(edge, nodeIdMap, distance); }); (0, lodash_es_1.forEach)(selectedEdges, function (edge) { elements.edges.push(_this.createEdge(edge, nodeIdMap, distance)); }); // 返回 elements 进行选中效果,即触发 element.selectElementById() // shortcut.ts 也会对最外层的 nodes 和 edges 进行偏移,即 translationNodeData() return elements; }; this.render(); }; DynamicGroup.prototype.render = function () { }; DynamicGroup.prototype.destroy = function () { // 销毁监听的事件,并移除渲染的 dom 内容 this.lf.off('node:add,node:drop,node:dnd-add', this.onNodeAddOrDrop); this.lf.off('selection:drop', this.onSelectionDrop); this.lf.off('node:delete', this.removeNodeFromGroup); this.lf.off('node:drag,node:dnd-drag', this.onNodeDrag); this.lf.off('selection:drag', this.onSelectionDrag); this.lf.off('node:click', this.onNodeSelect); this.lf.off('node:mousemove', this.onNodeMove); this.lf.off('graph:rendered', this.onGraphRendered); this.lf.off('group:add-node', this.onGroupAddNode); // 还原 lf.addElements 方法? // 移除 graphModel 上重写的 addNodeMoveRules 方法? // TODO: 讨论一下插件该具体做些什么 }; DynamicGroup.pluginName = 'dynamicGroup'; return DynamicGroup; }()); exports.DynamicGroup = DynamicGroup; exports.default = DynamicGroup;