UNPKG

@logicflow/extension

Version:
273 lines (272 loc) 10 kB
"use strict"; /** * 自动布局插件 * 依赖flowPath插件 * 未完善 */ 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); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AutoLayout = void 0; var POSITION_TYPE = { LEFT_TOP: -1, LEFT: 0, LEFT_BOTTOM: 1, }; var AutoLayout = /** @class */ (function () { function AutoLayout(_a) { var lf = _a.lf; var _this = this; this.levelHeight = []; this.newNodeMap = new Map(); this.lf = lf; /** * 用于记录上一次调用layout时计算出的trunk * 当旧trunk和新trunk长度一致时,用于选择旧trunk, * a->b->c->d * |->e * e后面新增f节点时候,旧逻辑会返回新trunk[a,b,e,f] * 界面布局变成 * a->b->e->f * |->c->d * 其实只想要这样 尽量少变化 * a->b->c->d * |->e->f * */ this.trunk = []; // 给lf添加方法 lf.layout = function (startNodeType) { var data = _this.lf.getGraphRawData(); _this.lf.setStartNodeType(startNodeType); var path = _this.lf.getPathes(); _this.levelHeight = []; _this.newNodeMap = new Map(); return _this.layout(data, path); }; } // 1) 将所有节点和边的坐标删除。节点上的文本改成偏移量。 // 2) 找到长度最长的路径,作为基准路径。 // 3) 依次计算 // 拿到最长的路径。 // nodes: [], edges: [], AutoLayout.prototype.layout = function (data, path) { var _this = this; var trunk = []; // TODO: 完成类型定义 path.forEach(function (p) { var elements = p.elements; if (elements.length > trunk.length) { trunk = elements; } else if (elements.length === trunk.length) { // 考虑是否替换为旧的trunk if (JSON.stringify(elements) === JSON.stringify(_this.trunk)) { trunk = _this.trunk; } } }); // 记录上一次trunk this.trunk = trunk; var nodeMap = this.formatData(data); var newGraphData = { nodes: [], edges: [], }; // 从后向前布局 for (var i = trunk.length - 1; i >= 0; i--) { this.setNodePosition(trunk[i], nodeMap, newGraphData, i, 1); } this.lf.graphModel.graphDataToModel(newGraphData); }; // 1) 需要知道下一层级已占高度。 // 2) 基于自己的高度,判断下一个层级的高度 AutoLayout.prototype.setNodePosition = function (nodeId, nodeMap, newGraphData, xLevel, yLevel) { var _this = this; var n = nodeMap[nodeId]; var text = n.text, type = n.type, next = n.next, properties = n.properties; var x = xLevel * 160 + 40; var y = yLevel * 120; var nodeData = { id: nodeId, x: x, text: text, y: y, type: type, properties: properties, }; if (text && typeof text === 'object') { nodeData.text = __assign(__assign({}, text), { x: x + text.x, y: y + text.y }); } this.newNodeMap.set(nodeData.id, { x: nodeData.x, y: nodeData.y, type: type, }); newGraphData.nodes.push(nodeData); n.isFixed = true; this.addLevelHeight(xLevel, 1); if (next && next.length > 0) { next.forEach(function (nextInfo) { // 如果下一个节点还没有被定位,那么设置其定位 var n1 = nodeMap[nextInfo.nodeId]; if (!n1.isFixed) { var nextYLevel = _this.getLevelHeight(xLevel + 1); _this.addLevelHeight(xLevel, 1); _this.setNodePosition(nextInfo.nodeId, nodeMap, newGraphData, xLevel + 1, nextYLevel + 1); } else { // todo: 如果下一个节点是已经定位的,则需要考虑边的规避 } // 设置连接到下一个节点的边 // 1) 起始位置为source节点的下方,结束位置为target节点左边。 // 2) 计算折线 newGraphData.edges.push(__assign({ id: nextInfo.edgeId, type: nextInfo.edgeType, sourceNodeId: nodeId, targetNodeId: nextInfo.nodeId, properties: nextInfo.properties, text: nextInfo.text }, _this.getEdgeDataPoints(nodeId, nextInfo.nodeId))); }); } return nodeData; }; /** * 1. 处理边上的文本 * 2. 主干节点之间直接的边 * 3. 一个节点被多个连接作为目标节点,合理分配锚点位置。 */ AutoLayout.prototype.getEdgeDataPoints = function (sourceNodeId, targetNodeId) { var source = this.newNodeMap.get(sourceNodeId); var target = this.newNodeMap.get(targetNodeId); var _a = this.getShape(sourceNodeId), width = _a.width, height = _a.height; var _b = this.getShape(targetNodeId), targetWidth = _b.width, targetHeight = _b.height; var positionType = this.getRelativePosition(source, target); var startPoint = { x: source.x, y: source.y, }; var endPoint = { x: target.x, y: target.y, }; switch (positionType) { case POSITION_TYPE.LEFT: startPoint.x = source.x + width / 2; endPoint.x = target.x - targetWidth / 2; break; case POSITION_TYPE.LEFT_TOP: startPoint.y = source.y + height / 2; endPoint.x = target.x - targetWidth / 2; break; case POSITION_TYPE.LEFT_BOTTOM: startPoint.x = source.x + width / 2; endPoint.y = target.y + targetHeight / 2; break; default: break; } return { startPoint: startPoint, endPoint: endPoint, }; }; /** * 获取边的连接节点相对位置。 * source一定在target左边。 * 1. 如果source和target在同一x, y坐标内容。 * 2. 如果source在target左上方。 * 3. 如果source在target左下方。 */ AutoLayout.prototype.getRelativePosition = function (source, target) { var y = source.y; var y1 = target.y; var positionType; if (y < y1) { positionType = -1; } else if (y === y1) { positionType = 0; } else { positionType = 1; } return positionType; }; /** * 获取边节点图形的宽高。 */ AutoLayout.prototype.getShape = function (nodeId) { var _a, _b; var nodeModel = this.lf.getNodeModelById(nodeId); return { height: (_a = nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.height) !== null && _a !== void 0 ? _a : 0, width: (_b = nodeModel === null || nodeModel === void 0 ? void 0 : nodeModel.width) !== null && _b !== void 0 ? _b : 0, }; }; AutoLayout.prototype.formatData = function (data) { var nodeMap = data.nodes.reduce(function (nMap, node) { var type = node.type, properties = node.properties, text = node.text, x = node.x, y = node.y; if (text && typeof text === 'object') { // 坐标转换为偏移量 text.x = text.x - x; text.y = text.y - y; } nMap[node.id] = { type: type, properties: properties, text: text, prev: [], next: [], }; return nMap; }, {}); data.edges.forEach(function (edge) { var sourceNodeId = edge.sourceNodeId, targetNodeId = edge.targetNodeId, id = edge.id, properties = edge.properties, text = edge.text; var newText = text; if (typeof text === 'object') { newText = text.value; } nodeMap[sourceNodeId].next.push({ edgeId: id, nodeId: targetNodeId, edgeType: edge.type, properties: properties, text: newText, }); nodeMap[targetNodeId].prev.push({ edgeId: id, nodeId: sourceNodeId, properties: properties, text: newText, }); }); return nodeMap; }; AutoLayout.prototype.addLevelHeight = function (level, height, isNegative) { if (height === void 0) { height = 1; } if (isNegative === void 0) { isNegative = false; } var l = this.levelHeight[level]; if (!l) { l = { positiveHeight: 0, negativeHeight: 0, }; this.levelHeight[level] = l; } isNegative ? (l.negativeHeight -= height) : (l.positiveHeight += height); }; AutoLayout.prototype.getLevelHeight = function (level, isNegative) { if (isNegative === void 0) { isNegative = false; } var val = this.levelHeight[level]; if (!val) { return 0; } return isNegative ? val.negativeHeight : val.positiveHeight; }; AutoLayout.pluginName = 'AutoLayout'; return AutoLayout; }()); exports.AutoLayout = AutoLayout;