@logicflow/extension
Version:
LogicFlow Extensions
534 lines (533 loc) • 25.4 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);
};
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 __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
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));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Group = void 0;
/**
* @deprecated
* 待废弃,2.0 版本将 提供 dynamic-group 支持分组功能,当前 Group 插件设计和实现有比较多的问题,后续不再维护,请及时切换
*/
var lodash_es_1 = require("lodash-es");
var core_1 = require("@logicflow/core");
var GroupNode_1 = __importDefault(require("./GroupNode"));
var DEFAULT_TOP_Z_INDEX = -1000;
var DEFAULT_BOTTOM_Z_INDEX = -10000;
var Group = /** @class */ (function () {
function Group(_a) {
var lf = _a.lf;
var _this = this;
this.topGroupZIndex = DEFAULT_BOTTOM_Z_INDEX;
this.nodeGroupMap = new Map();
this.graphRendered = function (_a) {
var data = _a.data;
// 如果节点
if (data && data.nodes) {
data.nodes.forEach(function (node) {
if (node.children) {
;
node.children.forEach(function (nodeId) {
_this.nodeGroupMap.set(nodeId, node.id);
});
}
});
// 初始化nodes时进行this.topGroupZIndex的校准更新
_this.checkAndCorrectTopGroupZIndex(data.nodes);
}
};
this.appendNodeToGroup = function (_a) {
var data = _a.data;
// 如果这个节点之前已经在group中了,则将其从之前的group中移除
var preGroupId = _this.nodeGroupMap.get(data.id);
if (preGroupId) {
var preGroup = _this.lf.getNodeModelById(preGroupId);
preGroup.removeChild(data.id);
_this.nodeGroupMap.delete(data.id);
preGroup.setAllowAppendChild(false);
}
// 然后再判断这个节点是否在某个group中,如果在,则将其添加到对应的group中
var nodeModel = _this.lf.getNodeModelById(data.id);
var bounds = nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.getBounds();
if (bounds && nodeModel) {
var group = _this.getGroup(bounds, data);
// 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) {
// 如果这个节点是分组,那么将其子节点也记录下来
;
data.children.forEach(function (nodeId) {
_this.nodeGroupMap.set(nodeId, data.id);
});
// 新增node时进行this.topGroupZIndex的校准更新
_this.checkAndCorrectTopGroupZIndex([data]);
_this.nodeSelected({
data: data,
isSelected: false,
isMultiple: false,
});
}
if (!group)
return;
var isAllowAppendIn = group.isAllowAppendIn(data);
if (!isAllowAppendIn) {
_this.lf.emit('group:not-allowed', {
group: group.getData(),
node: data,
});
return;
}
group.addChild(data.id);
_this.nodeGroupMap.set(data.id, group.id);
group.setAllowAppendChild(false);
}
};
this.deleteGroupChild = function (_a) {
var data = _a.data;
// 如果删除的是分组节点,则同时删除分组的子节点
if (data.children) {
;
data.children.forEach(function (nodeId) {
_this.nodeGroupMap.delete(nodeId);
_this.lf.deleteNode(nodeId);
});
}
var groupId = _this.nodeGroupMap.get(data.id);
if (groupId) {
var group = _this.lf.getNodeModelById(groupId);
group.removeChild(data.id);
_this.nodeGroupMap.delete(data.id);
}
};
this.setActiveGroup = function (_a) {
var data = _a.data;
var nodeModel = _this.lf.getNodeModelById(data.id);
var bounds = nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.getBounds();
if (nodeModel && bounds) {
var newGroup = _this.getGroup(bounds, data);
if (_this.activeGroup) {
_this.activeGroup.setAllowAppendChild(false);
}
if (!newGroup || (nodeModel.isGroup && newGroup.id === data.id))
return;
var isAllowAppendIn = newGroup.isAllowAppendIn(data);
if (!isAllowAppendIn) {
return;
}
_this.activeGroup = newGroup;
_this.activeGroup.setAllowAppendChild(true);
}
};
this.findNodeAndChildMaxZIndex = function (nodeModel) {
var maxZIndex = DEFAULT_BOTTOM_Z_INDEX;
if (nodeModel.isGroup) {
maxZIndex = Math.max(maxZIndex, nodeModel.zIndex);
}
if (nodeModel.children) {
;
nodeModel.children.forEach(function (nodeId) {
if (typeof nodeId === 'object') {
// 正常情况下, GroupNodeModel.children是一个id数组,这里只是做个兼容
// @ts-ignore
nodeId = nodeId.id;
}
var child = _this.lf.getNodeModelById(nodeId);
if (child === null || child === void 0 ? void 0 : child.isGroup) {
var childMaxZIndex = _this.findNodeAndChildMaxZIndex(child);
maxZIndex = Math.max(childMaxZIndex, maxZIndex);
}
});
}
return maxZIndex;
};
this.checkAndCorrectTopGroupZIndex = function (nodes) {
// 初始化时/增加新节点时,找出新增nodes的最大zIndex
var maxZIndex = DEFAULT_BOTTOM_Z_INDEX;
nodes.forEach(function (node) {
var nodeModel = _this.lf.getNodeModelById(node.id);
if (nodeModel) {
var currentNodeMaxZIndex = _this.findNodeAndChildMaxZIndex(nodeModel);
if (currentNodeMaxZIndex > maxZIndex) {
maxZIndex = currentNodeMaxZIndex;
}
}
});
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错乱问题
var allGroupNodes = _this.lf.graphModel.nodes.filter(function (node) { return node.isGroup; });
var max = _this.topGroupZIndex;
for (var i = 0; i < allGroupNodes.length; i++) {
var groupNode = allGroupNodes[i];
if (groupNode.zIndex > max) {
max = groupNode.zIndex;
}
}
_this.topGroupZIndex = max;
};
/**
* 1. 分组节点默认在普通节点下面。
* 2. 分组节点被选中后,会将分组节点以及其内部的其他分组节点放到其余分组节点的上面。
* 3. 分组节点取消选中后,不会将分组节点重置为原来的高度。
* 4. 由于LogicFlow核心目标是支持用户手动绘制流程图,所以不考虑一张流程图超过1000个分组节点的情况。
*/
this.nodeSelected = function (_a) {
var data = _a.data, isMultiple = _a.isMultiple, isSelected = _a.isSelected;
var nodeModel = _this.lf.getNodeModelById(data.id);
_this.toFrontGroup(nodeModel);
// 重置所有的group zIndex,防止group节点zIndex增长为正。
if (_this.topGroupZIndex > DEFAULT_TOP_Z_INDEX) {
_this.topGroupZIndex = DEFAULT_BOTTOM_Z_INDEX;
var allGroups = _this.lf.graphModel.nodes
.filter(function (node) { return node.isGroup; })
.sort(function (a, b) { return a.zIndex - b.zIndex; });
var preZIndex = 0;
for (var i = 0; i < allGroups.length; i++) {
var group = allGroups[i];
if (group.zIndex !== preZIndex) {
_this.topGroupZIndex++;
preZIndex = group.zIndex;
}
group.setZIndex(_this.topGroupZIndex);
}
}
// FIX #1004
// 如果节点被多选,
// 这个节点是分组,则将分组的所有子节点取消选中
// 这个节点是分组的子节点,且其所属分组节点已选,则取消选中
if (isMultiple && isSelected) {
if (nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.isGroup) {
;
nodeModel.children.forEach(function (child) {
var childModel = _this.lf.graphModel.getElement(child);
childModel === null || childModel === void 0 ? void 0 : childModel.setSelected(false);
});
}
else {
var groupId = _this.nodeGroupMap.get(data.id);
if (groupId) {
var groupModel = _this.lf.getNodeModelById(groupId);
(groupModel === null || groupModel === void 0 ? void 0 : groupModel.isSelected) && (nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.setSelected(false));
}
}
}
};
this.toFrontGroup = function (model) {
if (!model || !model.isGroup) {
return;
}
_this.topGroupZIndex++;
model.setZIndex(_this.topGroupZIndex);
if (model.children) {
;
model.children.forEach(function (nodeId) {
var node = _this.lf.getNodeModelById(nodeId);
_this.toFrontGroup(node);
});
}
};
lf.register(GroupNode_1.default);
this.lf = lf;
lf.graphModel.addNodeMoveRules(function (model, deltaX, deltaY) {
if (model.isGroup) {
// 如果移动的是分组,那么分组的子节点也跟着移动。
var nodeIds = _this.getNodeAllChild(model);
lf.graphModel.moveNodes(nodeIds, deltaX, deltaY, true);
return true;
}
var groupModel = lf.getNodeModelById(_this.nodeGroupMap.get(model.id));
if (groupModel && groupModel.isRestrict) {
// 如果移动的节点存在分组中,且这个分组禁止子节点移出去。
var _a = model.getBounds(), minX = _a.minX, minY = _a.minY, maxX = _a.maxX, maxY = _a.maxY;
return groupModel.isAllowMoveTo({
minX: minX + deltaX,
minY: minY + deltaY,
maxX: maxX + deltaX,
maxY: maxY + deltaY,
});
}
return true;
});
lf.graphModel.group = this;
lf.on('node:add,node:drop,node:dnd-add', this.appendNodeToGroup);
lf.on('node:delete', this.deleteGroupChild);
lf.on('node:dnd-drag,node:drag', this.setActiveGroup);
lf.on('node:click', this.nodeSelected);
lf.on('graph:rendered', this.graphRendered);
// https://github.com/didi/LogicFlow/issues/1346
// 重写 addElements() 方法,在 addElements() 原有基础上增加对 group 内部所有 nodes 和 edges 的复制功能
lf.addElements = function (_a, distance) {
var selectedNodes = _a.nodes, selectedEdges = _a.edges;
// ============== 变量初始化 ==============
var nodeIdMap = {};
var elements = {
nodes: [],
edges: [],
};
var groupInnerEdges = [];
// ============== 变量初始化 ==============
(0, lodash_es_1.forEach)(selectedNodes, function (node) {
var preId = node.id;
var children = node.children, rest = __rest(node, ["children"]);
var nodeModel = lf.addNode(rest);
if (!nodeModel) {
return {
nodes: [],
edges: [],
};
}
if (preId)
nodeIdMap[preId] = nodeModel.id;
elements.nodes.push(nodeModel); // group的nodeModel
// 递归创建group的nodeModel的children
var edgesArray = _this.createAllChildNodes(nodeIdMap, children, nodeModel, distance).edgesArray;
groupInnerEdges.push.apply(groupInnerEdges, __spreadArray([], __read(edgesArray), false));
});
groupInnerEdges.forEach(function (edge) {
_this.createEdgeModel(edge, nodeIdMap, distance);
});
// 构建的时候直接偏移,这里不需要再进行再度偏移
// groupInnerChildren.nodes.forEach(node => this.translateNodeData(node, distance));
// groupInnerChildren.edges.forEach(edge => this. translateEdgeData(edge, distance));
// 最外层的edges继续执行创建edgeModel的流程
// 由于最外层会调用 translateEdgeData(),因此这里不用传入distance进行偏移
(0, lodash_es_1.forEach)(selectedEdges, function (edge) {
var edgeModel = _this.createEdgeModel(edge, nodeIdMap, 0);
elements.edges.push(edgeModel);
});
// 返回elements进行选中效果,即触发element.selectElementById()
// shortcut.ts也会对最外层的nodes和edges进行偏移,即translateNodeData()
return elements;
};
}
/**
* 创建一个Group类型节点内部的所有子节点的副本
* 并且在遍历所有nodes的过程中顺便拿到所有edges(只在Group范围的edges)
*/
Group.prototype.createAllChildNodes = function (nodeIdMap, children, current, distance) {
var _this = this;
var lf = this.lf;
var edgesDataArray = [];
var edgesNodeModelArray = [];
var nodesArray = [];
children === null || children === void 0 ? void 0 : children.forEach(function (childId) {
var childNodeModel = lf.getNodeModelById(childId);
if (childNodeModel) {
var x = childNodeModel.x, y = childNodeModel.y, properties = childNodeModel.properties, type = childNodeModel.type, rotate = childNodeModel.rotate, children_1 = childNodeModel.children;
var nodeConfig = {
x: x + distance,
y: y + distance,
properties: properties,
type: type,
rotate: rotate,
// 如果不传递type,会自动触发NODE_ADD
// 有概率触发appendToGroup
};
var eventType = core_1.EventType.NODE_GROUP_COPY || 'node:group-copy-add';
var newChildModel = lf.addNode(nodeConfig, eventType);
current.addChild(newChildModel.id);
nodeIdMap[childId] = newChildModel.id;
nodesArray.push(newChildModel);
// 存储children内部节点相关的输入边
childNodeModel.incoming.edges.forEach(function (edge) {
edgesNodeModelArray.push(edge);
});
// 存储children内部节点相关的输出边
childNodeModel.outgoing.edges.forEach(function (edge) {
edgesNodeModelArray.push(edge);
});
if (children_1 instanceof Set) {
var _a = _this.createAllChildNodes(nodeIdMap, children_1, newChildModel, distance), childNodes = _a.nodesArray, childEdges = _a.edgesArray;
nodesArray.push.apply(nodesArray, __spreadArray([], __read(childNodes), false));
edgesDataArray.push.apply(edgesDataArray, __spreadArray([], __read(childEdges), false));
}
}
});
// 1. 判断每一条边的开始节点和目标节点是否在Group中
var filterEdgesArray = edgesNodeModelArray.filter(function (edge) {
return nodeIdMap[edge.sourceNodeId] && nodeIdMap[edge.targetNodeId];
});
// 2. 为每一条group的内部边构建出EdgeData数据
// 从GraphModel.ts的getSelectElements()可以知道EdgeConfig就是EdgeData
var filterEdgesDataArray = filterEdgesArray.map(function (item) {
return item.getData();
});
return {
nodesArray: nodesArray,
edgesArray: edgesDataArray.concat(filterEdgesDataArray), // ??? what's this
};
};
Group.prototype.createEdgeModel = function (edge, nodeIdMap, distance) {
var lf = this.lf;
var sourceId = edge.sourceNodeId;
var targetId = edge.targetNodeId;
if (nodeIdMap[sourceId])
sourceId = nodeIdMap[sourceId];
if (nodeIdMap[targetId])
targetId = nodeIdMap[targetId];
var type = edge.type, startPoint = edge.startPoint, endPoint = edge.endPoint, pointsList = edge.pointsList, text = edge.text;
// ====== 仿造shortcut.ts的 translateEdgeData()逻辑 ======
var newStartPoint = {
x: ((startPoint === null || startPoint === void 0 ? void 0 : startPoint.x) || 0) + distance,
y: ((startPoint === null || startPoint === void 0 ? void 0 : startPoint.y) || 0) + distance,
};
var newEndPoint = {
x: ((endPoint === null || endPoint === void 0 ? void 0 : endPoint.x) || 0) + distance,
y: ((endPoint === null || endPoint === void 0 ? void 0 : endPoint.y) || 0) + distance,
};
var newPointsList = [];
if (pointsList && pointsList.length > 0) {
newPointsList = pointsList.map(function (point) {
point.x += distance;
point.y += distance;
return point;
});
}
var edgeConfig = {
type: type,
startPoint: newStartPoint,
endPoint: newEndPoint,
sourceNodeId: sourceId,
targetNodeId: targetId,
pointsList: newPointsList,
};
if ((0, lodash_es_1.isObject)(text) && !(0, lodash_es_1.isEmpty)(text)) {
edgeConfig.text = __assign(__assign({}, text), { x: (text === null || text === void 0 ? void 0 : text.x) + distance, y: (text === null || text === void 0 ? void 0 : text.y) + distance });
}
// ====== 仿造shortcut.ts的 translateEdgeData()逻辑 ======
// 简化复制时的参数传入,防止创建出两个edge属于同个group这种情况
return lf.graphModel.addEdge(edgeConfig);
};
/**
* 获取一个节点内部所有的子节点,包裹分组的子节点
*/
Group.prototype.getNodeAllChild = function (model) {
var _this = this;
var nodeIds = [];
if (model.children) {
;
model.children.forEach(function (nodeId) {
nodeIds.push(nodeId);
var nodeModel = _this.lf.getNodeModelById(nodeId);
if (nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.isGroup) {
nodeIds = nodeIds.concat(_this.getNodeAllChild(nodeModel));
}
});
}
return nodeIds;
};
/**
* 获取自定位置其所属分组
* 当分组重合时,优先返回最上层的分组
*/
Group.prototype.getGroup = function (bounds, nodeData) {
var nodes = this.lf.graphModel.nodes;
var groups = nodes.filter(function (node) {
return node.isGroup &&
node.isInRange(bounds) &&
node.id !== nodeData.id;
});
if (groups.length === 0)
return;
if (groups.length === 1)
return groups[0];
var topGroup = groups[groups.length - 1];
for (var i = groups.length - 2; i >= 0; i--) {
if (groups[i].zIndex > topGroup.zIndex) {
topGroup = groups[i];
}
}
return topGroup;
};
/**
* 获取某个节点所属的groupModel
*/
Group.prototype.getNodeGroup = function (nodeId) {
var groupId = this.nodeGroupMap.get(nodeId);
if (groupId) {
return this.lf.getNodeModelById(groupId);
}
};
Group.prototype.render = function () { };
Group.prototype.destroy = function () { };
Group.pluginName = 'group';
return Group;
}());
exports.Group = Group;
__exportStar(require("./GroupNode"), exports);
exports.default = GroupNode_1.default;
;