@logicflow/extension
Version:
LogicFlow Extensions
668 lines (667 loc) • 32.8 kB
JavaScript
"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;