UNPKG

@antv/g6

Version:

graph visualization frame work

1,342 lines (1,130 loc) 40.3 kB
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /* * @Author: moyee * @Date: 2019-07-30 12:10:26 * @LastEditors: moyee * @LastEditTime: 2019-08-23 11:44:32 * @Description: Group Controller */ var isString = require('@antv/util/lib/type/is-string'); var deepMix = require('@antv/util/lib/deep-mix'); var CustomGroup = /*#__PURE__*/ function () { var _proto = CustomGroup.prototype; _proto.getDefaultCfg = function getDefaultCfg() { return { default: { lineWidth: 1, stroke: '#A3B1BF', // lineDash: [ 5, 5 ], strokeOpacity: 0.9, fill: '#F3F9FF', fillOpacity: 0.8, opacity: 0.8, disCoefficient: 0.6, minDis: 40, maxDis: 100 }, hover: { stroke: '#faad14', fill: '#ffe58f', fillOpacity: 0.3, opacity: 0.3, lineWidth: 3 }, // 收起状态样式 collapse: { r: 30, width: 80, height: 40, // lineDash: [ 5, 5 ], stroke: '#A3B1BF', lineWidth: 3, fill: '#F3F9FF', offsetX: -15, offsetY: 5 }, icon: 'https://gw.alipayobjects.com/zos/rmsportal/MXXetJAxlqrbisIuZxDO.svg', operatorBtn: { collapse: { img: 'https://gw.alipayobjects.com/zos/rmsportal/uZVdwjJGqDooqKLKtvGA.svg', width: 16, height: 16 }, expand: { width: 16, height: 16, img: 'https://gw.alipayobjects.com/zos/rmsportal/MXXetJAxlqrbisIuZxDO.svg' } }, visible: false }; }; function CustomGroup(graph) { // const { cfg = {} } = options; this.graph = graph; var groupStyle = graph.get('groupStyle'); this.styles = deepMix({}, this.getDefaultCfg(), groupStyle); // 创建的群组集合 this.customGroup = {}; this.delegateInGroup = {}; this.nodePoint = []; } /** * 生成群组 * @param {string} groupId 群组ID * @param {array} nodes 群组中的节点集合 * @param {string} type 群组类型,默认为circle,支持rect * @param {number} zIndex 群组层级,默认为0 * @param {boolean} updateDataModel 是否更新节点数据,默认为false,只有当手动创建group时才为true * @param {object} title 分组标题配置 * @memberof ItemGroup * @return {object} null */ _proto.create = function create(groupId, nodes, type, zIndex, updateDataModel, title) { if (type === void 0) { type = 'circle'; } if (zIndex === void 0) { zIndex = 0; } if (updateDataModel === void 0) { updateDataModel = false; } if (title === void 0) { title = {}; } var graph = this.graph; var customGroup = graph.get('customGroup'); var hasGroupIds = customGroup.get('children').map(function (data) { return data.get('id'); }); if (hasGroupIds.indexOf(groupId) > -1) { return console.warn("\u5DF2\u7ECF\u5B58\u5728ID\u4E3A " + groupId + " \u7684\u5206\u7EC4\uFF0C\u8BF7\u91CD\u65B0\u8BBE\u7F6E\u5206\u7EC4ID\uFF01"); } var nodeGroup = customGroup.addGroup({ id: groupId, zIndex: zIndex }); var autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); var defaultStyle = this.styles.default; // 计算群组左上角左边、宽度、高度及x轴方向上的最大值 var _this$calculationGrou = this.calculationGroupPosition(nodes), x = _this$calculationGrou.x, y = _this$calculationGrou.y, width = _this$calculationGrou.width, height = _this$calculationGrou.height, maxX = _this$calculationGrou.maxX; var paddingValue = this.getGroupPadding(groupId); var groupBBox = graph.get('groupBBoxs'); groupBBox[groupId] = { x: x, y: y, width: width, height: height, maxX: maxX }; // 根据groupId获取group数据,判断是否需要添加title var groupTitle = null; // 只有手动创建group时执行以下逻辑 if (updateDataModel) { var groups = graph.get('groups'); // 如果是手动创建group,则原始数据中是没有groupId信息的,需要将groupId添加到node中 nodes.forEach(function (nodeId) { var node = graph.findById(nodeId); var model = node.getModel(); if (!model.groupId) { model.groupId = groupId; } }); // 如果是手动创建 group,则将 group 也添加到 groups 中 if (!groups.find(function (data) { return data.id === groupId; })) { groups.push({ id: groupId, title: title }); graph.set({ groups: groups }); } } var groupData = graph.get('groups').filter(function (data) { return data.id === groupId; }); if (groupData && groupData.length > 0) { groupTitle = groupData[0].title; } // group title 坐标 var titleX = 0; var titleY = 0; // step 1:绘制群组外框 var keyShape = null; if (type === 'circle') { var r = width > height ? width / 2 : height / 2; var cx = (width + 2 * x) / 2; var cy = (height + 2 * y) / 2; var lastR = r + paddingValue; keyShape = nodeGroup.addShape('circle', { attrs: _extends({}, defaultStyle, { x: cx, y: cy, r: lastR }), capture: true, zIndex: zIndex, groupId: groupId }); titleX = cx; titleY = cy - lastR; // 更新群组及属性样式 this.setDeletageGroupByStyle(groupId, nodeGroup, { width: width, height: height, x: cx, y: cy, r: lastR }); } else { var rectPadding = paddingValue * defaultStyle.disCoefficient; keyShape = nodeGroup.addShape('rect', { attrs: _extends({}, defaultStyle, { x: x - rectPadding, y: y - rectPadding, width: width + rectPadding * 2, height: height + rectPadding * 2 }), capture: true, zIndex: zIndex, groupId: groupId }); titleX = x - rectPadding + 15; titleY = y - rectPadding + 15; // 更新群组及属性样式 this.setDeletageGroupByStyle(groupId, nodeGroup, { x: x - rectPadding, y: y - rectPadding, width: width + rectPadding, height: height + rectPadding, btnOffset: maxX - 3 }); } // 添加group标题 if (groupTitle) { var _groupTitle = groupTitle, _groupTitle$offsetX = _groupTitle.offsetX, offsetX = _groupTitle$offsetX === void 0 ? 0 : _groupTitle$offsetX, _groupTitle$offsetY = _groupTitle.offsetY, offsetY = _groupTitle$offsetY === void 0 ? 0 : _groupTitle$offsetY, _groupTitle$text = _groupTitle.text, text = _groupTitle$text === void 0 ? groupTitle : _groupTitle$text, titleStyle = _objectWithoutPropertiesLoose(_groupTitle, ["offsetX", "offsetY", "text"]); var textShape = nodeGroup.addShape('text', { attrs: _extends({ text: text, stroke: '#444', x: titleX + offsetX, y: titleY + offsetY }, titleStyle), className: 'group-title' }); textShape.set('capture', false); } nodeGroup.set('keyShape', keyShape); // 设置graph中groupNodes的值 graph.get('groupNodes')[groupId] = nodes; graph.setAutoPaint(autoPaint); graph.paint(); } /** * 修改Group样式 * @param {Item} keyShape 群组的keyShape * @param {Object | String} style 样式 */ ; _proto.setGroupStyle = function setGroupStyle(keyShape, style) { if (!keyShape || keyShape.get('destroyed')) { return; } var styles = {}; var _this$styles = this.styles, hoverStyle = _this$styles.hover, defaultStyle = _this$styles.default; if (isString(style)) { if (style === 'default') { styles = deepMix({}, defaultStyle); } else if (style === 'hover') { styles = deepMix({}, hoverStyle); } } else { styles = deepMix({}, defaultStyle, style); } for (var s in styles) { keyShape.attr(s, styles[s]); } } /** * 根据GroupID计算群组位置,包括左上角左边及宽度和高度 * * @param {object} nodes 符合条件的node集合:选中的node或具有同一个groupID的node * @return {object} 根据节点计算出来的包围盒坐标 * @memberof ItemGroup */ ; _proto.calculationGroupPosition = function calculationGroupPosition(nodes) { var graph = this.graph; var minx = Infinity; var maxx = -Infinity; var miny = Infinity; var maxy = -Infinity; // 获取已节点的所有最大最小x y值 for (var _iterator = nodes, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref; if (_isArray) { if (_i >= _iterator.length) break; _ref = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref = _i.value; } var id = _ref; var element = isString(id) ? graph.findById(id) : id; var bbox = element.getBBox(); var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY; if (minX < minx) { minx = minX; } if (minY < miny) { miny = minY; } if (maxX > maxx) { maxx = maxX; } if (maxY > maxy) { maxy = maxY; } } var x = Math.floor(minx); var y = Math.floor(miny); var width = Math.ceil(maxx) - x; var height = Math.ceil(maxy) - y; return { x: x, y: y, width: width, height: height, maxX: Math.ceil(maxx) }; } /** * 当group中含有group时,获取padding值 * @param {string} groupId 节点分组ID * @return {number} 在x和y方向上的偏移值 */ ; _proto.getGroupPadding = function getGroupPadding(groupId) { var graph = this.graph; var defaultStyle = this.styles.default; // 检测操作的群组中是否包括子群组 var groups = graph.get('groups'); var hasSubGroup = !!groups.filter(function (g) { return g.parentId === groupId; }).length > 0; var paddingValue = hasSubGroup ? defaultStyle.maxDis : defaultStyle.minDis; return paddingValue; } /** * 设置群组对象及属性值 * * @param {string} groupId 群组ID * @param {Group} deletage 群组元素 * @param {object} property 属性值,里面包括width、height和maxX * @memberof ItemGroup */ ; _proto.setDeletageGroupByStyle = function setDeletageGroupByStyle(groupId, deletage, property) { var width = property.width, height = property.height, x = property.x, y = property.y, r = property.r, btnOffset = property.btnOffset; var customGroupStyle = this.customGroup[groupId]; if (!customGroupStyle) { // 首次赋值 this.customGroup[groupId] = { nodeGroup: deletage, groupStyle: { width: width, height: height, x: x, y: y, r: r, btnOffset: btnOffset } }; } else { // 更新时候merge配置项 var groupStyle = customGroupStyle.groupStyle; var styles = deepMix({}, groupStyle, property); this.customGroup[groupId] = { nodeGroup: deletage, groupStyle: styles }; } } /** * 根据群组ID获取群组及属性对象 * * @param {string} groupId 群组ID * @return {Item} 群组 * @memberof ItemGroup */ ; _proto.getDeletageGroupById = function getDeletageGroupById(groupId) { return this.customGroup[groupId]; } /** * 收起和展开群组 * @param {string} groupId 群组ID */ ; _proto.collapseExpandGroup = function collapseExpandGroup(groupId) { var customGroup = this.getDeletageGroupById(groupId); var nodeGroup = customGroup.nodeGroup; var hasHidden = nodeGroup.get('hasHidden'); // 该群组已经处于收起状态,需要展开 if (hasHidden) { nodeGroup.set('hasHidden', false); this.expandGroup(groupId); } else { nodeGroup.set('hasHidden', true); this.collapseGroup(groupId); } } /** * 将临时节点递归地设置到groupId及父节点上 * @param {string} groupId 群组ID * @param {string} tmpNodeId 临时节点ID */ ; _proto.setGroupTmpNode = function setGroupTmpNode(groupId, tmpNodeId) { var graph = this.graph; var graphNodes = graph.get('groupNodes'); var groups = graph.get('groups'); if (graphNodes[groupId].indexOf(tmpNodeId) < 0) { graphNodes[groupId].push(tmpNodeId); } // 获取groupId的父群组 var parentGroup = groups.filter(function (g) { return g.id === groupId; }); var parentId = null; if (parentGroup.length > 0) { parentId = parentGroup[0].parentId; } // 如果存在父群组,则把临时元素也添加到父群组中 if (parentId) { this.setGroupTmpNode(parentId, tmpNodeId); } } /** * 收起群组,隐藏群组中的节点及边,群组外部相邻的边都连接到群组上 * * @param {string} id 群组ID * @memberof ItemGroup */ ; _proto.collapseGroup = function collapseGroup(id) { var _this = this; var customGroup = this.getDeletageGroupById(id); var nodeGroup = customGroup.nodeGroup; // 收起群组后的默认样式 var collapse = this.styles.collapse; var graph = this.graph; var groupType = graph.get('groupType'); var autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); var nodesInGroup = graph.get('groupNodes')[id]; var _this$calculationGrou2 = this.calculationGroupPosition(nodesInGroup), w = _this$calculationGrou2.width, h = _this$calculationGrou2.height; // 更新Group的大小 var keyShape = nodeGroup.get('keyShape'); var r = collapse.r, width = collapse.width, height = collapse.height, offsetX = collapse.offsetX, offsetY = collapse.offsetY, otherStyle = _objectWithoutPropertiesLoose(collapse, ["r", "width", "height", "offsetX", "offsetY"]); for (var style in otherStyle) { keyShape.attr(style, otherStyle[style]); } var options = { groupId: id, id: id + "-custom-node", x: keyShape.attr('x'), y: keyShape.attr('y'), style: { r: r }, shape: 'circle' }; var titleShape = nodeGroup.findByClassName('group-title'); // 收起群组时候动画 if (groupType === 'circle') { var radius = keyShape.attr('r'); keyShape.animate({ onFrame: function onFrame(ratio) { return { r: radius - ratio * (radius - r) }; } }, 500, 'easeCubic'); if (titleShape) { titleShape.attr({ x: keyShape.attr('x') + offsetX, y: keyShape.attr('y') + offsetY }); } } else if (groupType === 'rect') { keyShape.animate({ onFrame: function onFrame(ratio) { return { width: w - ratio * (w - width), height: h - ratio * (h - height) }; } }, 500, 'easeCubic'); if (titleShape) { titleShape.attr({ x: keyShape.attr('x') + 10, y: keyShape.attr('y') + height / 2 + 5 }); } options = { groupId: id, id: id + "-custom-node", x: keyShape.attr('x') + width / 2, y: keyShape.attr('y') + height / 2, size: [width, height], shape: 'rect' }; } var edges = graph.getEdges(); // 获取所有source在群组外,target在群组内的边 var sourceOutTargetInEdges = edges.filter(function (edge) { var model = edge.getModel(); return !nodesInGroup.includes(model.source) && nodesInGroup.includes(model.target); }); // 获取所有source在群组外,target在群组内的边 var sourceInTargetOutEdges = edges.filter(function (edge) { var model = edge.getModel(); return nodesInGroup.includes(model.source) && !nodesInGroup.includes(model.target); }); // 获取群组中节点之间的所有边 var edgeAllInGroup = edges.filter(function (edge) { var model = edge.getModel(); return nodesInGroup.includes(model.source) && nodesInGroup.includes(model.target); }); // 隐藏群组中的所有节点 nodesInGroup.forEach(function (nodeId) { var node = graph.findById(nodeId); var model = node.getModel(); var groupId = model.groupId; if (groupId && groupId !== id) { // 存在群组,则隐藏 var currentGroup = _this.getDeletageGroupById(groupId); var _nodeGroup = currentGroup.nodeGroup; _nodeGroup.hide(); } node.hide(); }); edgeAllInGroup.forEach(function (edge) { var source = edge.getSource(); var target = edge.getTarget(); if (source.isVisible() && target.isVisible()) { edge.show(); } else { edge.hide(); } }); // 群组中存在source和target其中有一个在群组内,一个在群组外的情况 if (sourceOutTargetInEdges.length > 0 || sourceInTargetOutEdges.length > 0) { var delegateNode = graph.add('node', options); delegateNode.set('capture', false); delegateNode.hide(); this.delegateInGroup[id] = { delegateNode: delegateNode }; // 将临时添加的节点加入到群组中,以便拖动节点时候线跟着拖动 this.setGroupTmpNode(id, id + "-custom-node"); this.updateEdgeInGroupLinks(id, sourceOutTargetInEdges, sourceInTargetOutEdges); } graph.paint(); graph.setAutoPaint(autoPaint); } /** * 收起群组时生成临时的节点,用于连接群组外的节点 * * @param {string} groupId 群组ID * @param {array} sourceOutTargetInEdges 出度的边 * @param {array} sourceInTargetOutEdges 入度的边 * @memberof ItemGroup */ ; _proto.updateEdgeInGroupLinks = function updateEdgeInGroupLinks(groupId, sourceOutTargetInEdges, sourceInTargetOutEdges) { var graph = this.graph; // 更新source在外的节点 var edgesOuts = {}; sourceOutTargetInEdges.map(function (edge) { var model = edge.getModel(); var id = edge.get('id'); var target = model.target; edgesOuts[id] = target; graph.updateItem(edge, { target: groupId + "-custom-node" }); return true; }); // 更新target在外的节点 var edgesIn = {}; sourceInTargetOutEdges.map(function (edge) { var model = edge.getModel(); var id = edge.get('id'); var source = model.source; edgesIn[id] = source; graph.updateItem(edge, { source: groupId + "-custom-node" }); return true; }); // 缓存群组groupId下的edge和临时生成的node节点 this.delegateInGroup[groupId] = deepMix({ sourceOutTargetInEdges: sourceOutTargetInEdges, sourceInTargetOutEdges: sourceInTargetOutEdges, edgesOuts: edgesOuts, edgesIn: edgesIn }, this.delegateInGroup[groupId]); } /** * 展开群组,恢复群组中的节点及边 * * @param {string} id 群组ID * @memberof ItemGroup */ ; _proto.expandGroup = function expandGroup(id) { var _this2 = this; var graph = this.graph; var groupType = graph.get('groupType'); var autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); // 显示之前隐藏的节点和群组 var nodesInGroup = graph.get('groupNodes')[id]; var noCustomNodes = nodesInGroup.filter(function (node) { return node.indexOf('custom-node') === -1; }); var _this$calculationGrou3 = this.calculationGroupPosition(noCustomNodes), width = _this$calculationGrou3.width, height = _this$calculationGrou3.height; var _this$getDeletageGrou = this.getDeletageGroupById(id), nodeGroup = _this$getDeletageGrou.nodeGroup; var keyShape = nodeGroup.get('keyShape'); var _this$styles2 = this.styles, defaultStyle = _this$styles2.default, collapse = _this$styles2.collapse; for (var style in defaultStyle) { keyShape.attr(style, defaultStyle[style]); } var titleShape = nodeGroup.findByClassName('group-title'); // 检测操作的群组中是否包括子群组 var paddingValue = this.getGroupPadding(id); if (groupType === 'circle') { var r = width > height ? width / 2 : height / 2; keyShape.animate({ onFrame: function onFrame(ratio) { return { r: collapse.r + ratio * (r - collapse.r + paddingValue) }; } }, 500, 'easeCubic'); } else if (groupType === 'rect') { var w = collapse.width, h = collapse.height; keyShape.animate({ onFrame: function onFrame(ratio) { return { width: w + ratio * (width - w + paddingValue * defaultStyle.disCoefficient * 2), height: h + ratio * (height - h + paddingValue * defaultStyle.disCoefficient * 2) }; } }, 500, 'easeCubic'); } if (titleShape) { // 根据groupId获取group数据,判断是否需要添加title var groupTitle = null; var groupData = graph.get('groups').filter(function (data) { return data.id === id; }); if (groupData && groupData.length > 0) { groupTitle = groupData[0].title; } var _groupTitle2 = groupTitle, _groupTitle2$offsetX = _groupTitle2.offsetX, offsetX = _groupTitle2$offsetX === void 0 ? 0 : _groupTitle2$offsetX, _groupTitle2$offsetY = _groupTitle2.offsetY, offsetY = _groupTitle2$offsetY === void 0 ? 0 : _groupTitle2$offsetY; if (groupType === 'circle') { titleShape.animate({ onFrame: function onFrame(ratio) { return { x: keyShape.attr('x') + offsetX, y: keyShape.attr('y') - ratio * keyShape.attr('r') + offsetY }; } }, 600, 'easeCubic'); } else if (groupType === 'rect') { titleShape.animate({ onFrame: function onFrame(ratio) { return { x: keyShape.attr('x') + ratio * (15 + offsetX), y: keyShape.attr('y') + ratio * (15 + offsetY) }; } }, 600, 'easeCubic'); } } // 群组动画一会后再显示节点和边 setTimeout(function () { nodesInGroup.forEach(function (nodeId) { var node = graph.findById(nodeId); var model = node.getModel(); var groupId = model.groupId; if (groupId && groupId !== id) { // 存在群组,则显示 var currentGroup = _this2.getDeletageGroupById(groupId); var _nodeGroup2 = currentGroup.nodeGroup; _nodeGroup2.show(); var hasHidden = _nodeGroup2.get('hasHidden'); if (!hasHidden) { node.show(); } } else { node.show(); } }); var edges = graph.getEdges(); // 获取群组中节点之间的所有边 var edgeAllInGroup = edges.filter(function (edge) { var model = edge.getModel(); return nodesInGroup.includes(model.source) || nodesInGroup.includes(model.target); }); edgeAllInGroup.forEach(function (edge) { var source = edge.getSource(); var target = edge.getTarget(); if (source.isVisible() && target.isVisible()) { edge.show(); } }); }, 300); var delegates = this.delegateInGroup[id]; if (delegates) { var sourceOutTargetInEdges = delegates.sourceOutTargetInEdges, sourceInTargetOutEdges = delegates.sourceInTargetOutEdges, edgesOuts = delegates.edgesOuts, edgesIn = delegates.edgesIn, delegateNode = delegates.delegateNode; // 恢复source在外的节点 sourceOutTargetInEdges.map(function (edge) { var id = edge.get('id'); var sourceOuts = edgesOuts[id]; graph.updateItem(edge, { target: sourceOuts }); return true; }); // 恢复target在外的节点 sourceInTargetOutEdges.map(function (edge) { var id = edge.get('id'); var sourceIn = edgesIn[id]; graph.updateItem(edge, { source: sourceIn }); return true; }); // 删除群组中的临时节点ID var tmpNodeModel = delegateNode.getModel(); this.deleteTmpNode(id, tmpNodeModel.id); graph.remove(delegateNode); delete this.delegateInGroup[id]; } graph.setAutoPaint(autoPaint); graph.paint(); }; _proto.deleteTmpNode = function deleteTmpNode(groupId, tmpNodeId) { var graph = this.graph; var groups = graph.get('groups'); var nodesInGroup = graph.get('groupNodes')[groupId]; var index = nodesInGroup.indexOf(tmpNodeId); nodesInGroup.splice(index, 1); // 获取groupId的父群组 var parentGroup = groups.filter(function (g) { return g.id === groupId; }); var parentId = null; if (parentGroup.length > 0) { parentId = parentGroup[0].parentId; } // 如果存在父群组,则把临时元素也添加到父群组中 if (parentId) { this.deleteTmpNode(parentId, tmpNodeId); } } /** * 删除节点分组 * @param {string} groupId 节点分组ID * @memberof ItemGroup */ ; _proto.remove = function remove(groupId) { var graph = this.graph; var customGroup = this.getDeletageGroupById(groupId); if (!customGroup) { console.warn("\u8BF7\u786E\u8BA4\u8F93\u5165\u7684groupId " + groupId + " \u662F\u5426\u6709\u8BEF\uFF01"); return; } var nodeGroup = customGroup.nodeGroup; var autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); var groupNodes = graph.get('groupNodes'); var nodes = groupNodes[groupId]; // 删除原群组中node中的groupID nodes.forEach(function (nodeId) { var node = graph.findById(nodeId); var model = node.getModel(); var gId = model.groupId; if (!gId) { return; } if (groupId === gId) { delete model.groupId; // 使用没有groupID的数据更新节点 graph.updateItem(node, model); } }); nodeGroup.destroy(); // 删除customGroup中groupId的数据 delete this.customGroup[groupId]; // 删除groups数据中的groupId var groups = graph.get('groups'); if (groups.length > 0) { var filterGroup = groups.filter(function (group) { return group.id !== groupId; }); graph.set('groups', filterGroup); } var parentGroupId = null; var parentGroupData = null; for (var _iterator2 = groups, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { var _ref2; if (_isArray2) { if (_i2 >= _iterator2.length) break; _ref2 = _iterator2[_i2++]; } else { _i2 = _iterator2.next(); if (_i2.done) break; _ref2 = _i2.value; } var group = _ref2; if (groupId !== group.id) { continue; } parentGroupId = group.parentId; parentGroupData = group; break; } if (parentGroupData) { delete parentGroupData.parentId; } // 删除groupNodes中的groupId数据 delete groupNodes[groupId]; if (parentGroupId) { groupNodes[parentGroupId] = groupNodes[parentGroupId].filter(function (node) { return !nodes.includes(node); }); } graph.setAutoPaint(autoPaint); graph.paint(); } /** * 更新节点分组位置及里面的节点和边的位置 * @param {string} groupId 节点分组ID * @param {object} position delegate的坐标位置 */ ; _proto.updateGroup = function updateGroup(groupId, position) { var graph = this.graph; var groupType = graph.get('groupType'); // 更新群组里面节点和线的位置 this.updateItemInGroup(groupId, position); // 判断是否拖动出了parent group外面,如果拖出了parent Group外面,则更新数据,去掉group关联 // 获取groupId的父Group的ID var _graph$save = graph.save(), groups = _graph$save.groups; var parentGroupId = null; var parentGroupData = null; for (var _iterator3 = groups, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { var _ref3; if (_isArray3) { if (_i3 >= _iterator3.length) break; _ref3 = _iterator3[_i3++]; } else { _i3 = _iterator3.next(); if (_i3.done) break; _ref3 = _i3.value; } var group = _ref3; if (groupId !== group.id) { continue; } parentGroupId = group.parentId; parentGroupData = group; break; } if (parentGroupId) { var _this$getDeletageGrou2 = this.getDeletageGroupById(parentGroupId), parentGroup = _this$getDeletageGrou2.nodeGroup; // const parentGroup = customGroup[parentGroupId].nodeGroup; var parentKeyShape = parentGroup.get('keyShape'); this.setGroupStyle(parentKeyShape, 'default'); var parentGroupBBox = parentKeyShape.getBBox(); var minX = parentGroupBBox.minX, minY = parentGroupBBox.minY, maxX = parentGroupBBox.maxX, maxY = parentGroupBBox.maxY; // 检查是否拖出了父Group var _this$getDeletageGrou3 = this.getDeletageGroupById(groupId), currentGroup = _this$getDeletageGrou3.nodeGroup; // const currentGroup = customGroup[groupId].nodeGroup; var currentKeyShape = currentGroup.get('keyShape'); var currentKeyShapeBBox = currentKeyShape.getBBox(); var x = currentKeyShapeBBox.x, y = currentKeyShapeBBox.y; if (!(x < maxX && x > minX && y < maxY && y > minY)) { // 拖出了parent group,则取消parent group ID delete parentGroupData.parentId; // 同时删除groupID中的节点 var groupNodes = graph.get('groupNodes'); var currentGroupNodes = groupNodes[groupId]; var parentGroupNodes = groupNodes[parentGroupId]; groupNodes[parentGroupId] = parentGroupNodes.filter(function (node) { return currentGroupNodes.indexOf(node) === -1; }); var _this$calculationGrou4 = this.calculationGroupPosition(groupNodes[parentGroupId]), x1 = _this$calculationGrou4.x, y1 = _this$calculationGrou4.y, width = _this$calculationGrou4.width, height = _this$calculationGrou4.height; var paddingValue = this.getGroupPadding(parentGroupId); var groupTitleShape = parentGroup.findByClassName('group-title'); var titleX = 0; var titleY = 0; if (groupType === 'circle') { var r = width > height ? width / 2 : height / 2; var cx = (width + 2 * x1) / 2; var cy = (height + 2 * y1) / 2; parentKeyShape.attr({ r: r + paddingValue, x: cx, y: cy }); titleX = cx; titleY = cy - parentKeyShape.attr('r'); } else if (groupType === 'rect') { var defaultStyle = this.styles.default; var rectPadding = paddingValue * defaultStyle.disCoefficient; parentKeyShape.attr({ x: x1 - rectPadding, y: y1 - rectPadding }); titleX = x1 - rectPadding + 15; titleY = y1 - rectPadding + 15; } if (groupTitleShape) { var titleConfig = parentGroupData.title; var offsetX = 0; var offsetY = 0; if (titleConfig) { offsetX = titleConfig.offsetX; offsetY = titleConfig.offsetY; } groupTitleShape.attr({ x: titleX + offsetX, y: titleY + offsetY }); } } } } /** * 更新节点分组中节点和边的位置 * @param {string} groupId 节点分组ID * @param {object} position delegate的坐标位置 */ ; _proto.updateItemInGroup = function updateItemInGroup(groupId, position) { var _this3 = this; var graph = this.graph; var groupType = graph.get('groupType'); var groupNodes = graph.get('groupNodes'); // step 1:先修改groupId中的节点位置 var nodeInGroup = groupNodes[groupId]; var _this$getDeletageGrou4 = this.getDeletageGroupById(groupId), nodeGroup = _this$getDeletageGrou4.nodeGroup; var originBBox = nodeGroup.getBBox(); var otherGroupId = []; nodeInGroup.forEach(function (nodeId, index) { var node = graph.findById(nodeId); var model = node.getModel(); var nodeGroupId = model.groupId; if (nodeGroupId && !otherGroupId.includes(nodeGroupId)) { otherGroupId.push(nodeGroupId); } if (!_this3.nodePoint[index]) { _this3.nodePoint[index] = { x: model.x, y: model.y }; } // 群组拖动后节点的位置:deletateShape的最终位置-群组起始位置+节点位置 var x = position.x - originBBox.x + _this3.nodePoint[index].x; var y = position.y - originBBox.y + _this3.nodePoint[index].y; _this3.nodePoint[index] = { x: x, y: y }; graph.updateItem(node, { x: x, y: y }); }); // step 2:修改父group中其他节点的位置 // otherGroupId中是否包括当前groupId,如果不包括,则添加进去 if (!otherGroupId.includes(groupId)) { otherGroupId.push(groupId); } // 更新完群组位置后,重新设置群组起始位置 otherGroupId.forEach(function (id) { // 更新群组位置 var _this3$getDeletageGro = _this3.getDeletageGroupById(id), nodeGroup = _this3$getDeletageGro.nodeGroup; var groupKeyShape = nodeGroup.get('keyShape'); var noCustomNodes = groupNodes[id].filter(function (node) { return node.indexOf('custom-node') === -1; }); var _this3$calculationGro = _this3.calculationGroupPosition(noCustomNodes), x = _this3$calculationGro.x, y = _this3$calculationGro.y, width = _this3$calculationGro.width, height = _this3$calculationGro.height; var titleX = 0; var titleY = 0; if (groupType === 'circle') { var cx = (width + 2 * x) / 2; var cy = (height + 2 * y) / 2; groupKeyShape.attr({ x: cx, y: cy }); titleX = cx; titleY = cy - groupKeyShape.attr('r'); } else if (groupType === 'rect') { // 节点分组状态 var hasHidden = nodeGroup.get('hasHidden'); var paddingValue = _this3.getGroupPadding(id); var keyshapePosition = {}; var defaultStyle = _this3.styles.default; var rectPadding = paddingValue * defaultStyle.disCoefficient; titleX = x - rectPadding + 15; titleY = y - rectPadding + 15; if (hasHidden) { // 无标题,或节点分组是展开的情况 keyshapePosition = { x: x - rectPadding, y: y - rectPadding }; titleY = titleY + 10; } else { keyshapePosition = { x: x - rectPadding, y: y - rectPadding, width: width + rectPadding * 2, height: height + rectPadding * 2 }; } groupKeyShape.attr(keyshapePosition); } // 如果存在标题,则更新标题位置 _this3.updateGroupTitle(nodeGroup, id, titleX, titleY); }); } /** * 更新节点分组的 Title * @param {Group} group 当前 Group 实例 * @param {string} groupId 分组ID * @param {number} x x坐标 * @param {number} y y坐标 */ ; _proto.updateGroupTitle = function updateGroupTitle(group, groupId, x, y) { var graph = this.graph; var groupTitleShape = group.findByClassName('group-title'); if (groupTitleShape) { var titleConfig = null; var groupData = graph.get('groups').filter(function (data) { return data.id === groupId; }); if (groupData && groupData.length > 0) { titleConfig = groupData[0].title; } var offsetX = 0; var offsetY = 0; if (titleConfig) { offsetX = titleConfig.offsetX || 0; offsetY = titleConfig.offsetY || 0; } groupTitleShape.attr({ x: x + offsetX, y: y + offsetY }); } } /** * 拖动节点时候动态改变节点分组大小 * @param {Event} evt 事件句柄 * @param {Group} currentGroup 当前操作的群组 * @param {Item} keyShape 当前操作的keyShape * @description 节点拖入拖出后动态改变群组大小 */ ; _proto.dynamicChangeGroupSize = function dynamicChangeGroupSize(evt, currentGroup, keyShape) { var item = evt.item; var model = item.getModel(); // 节点所在的GroupId var groupId = model.groupId; var graph = this.graph; var groupType = graph.get('groupType'); var groupNodes = graph.get('groupNodes'); var nodes = groupNodes[groupId]; // 拖出节点后,根据最新的节点数量,重新计算群组大小 // 如果只有一个节点,拖出后,则删除该组 if (nodes.length === 0) { // step 1: 从groupNodes中删除 delete groupNodes[groupId]; // step 2: 从groups数据中删除 var groupsData = graph.get('groups'); graph.set('groups', groupsData.filter(function (gdata) { return gdata.id !== groupId; })); // step 3: 删除原来的群组 currentGroup.remove(); } else { var _this$calculationGrou5 = this.calculationGroupPosition(nodes), x = _this$calculationGrou5.x, y = _this$calculationGrou5.y, width = _this$calculationGrou5.width, height = _this$calculationGrou5.height; // 检测操作的群组中是否包括子群组 var paddingValue = this.getGroupPadding(groupId); var titleX = 0; var titleY = 0; if (groupType === 'circle') { var r = width > height ? width / 2 : height / 2; var cx = (width + 2 * x) / 2; var cy = (height + 2 * y) / 2; keyShape.attr({ r: r + paddingValue, x: cx, y: cy }); titleX = cx; titleY = cy - keyShape.attr('r'); } else if (groupType === 'rect') { var defaultStyle = this.styles.default; var rectPadding = paddingValue * defaultStyle.disCoefficient; keyShape.attr({ x: x - rectPadding, y: y - rectPadding, width: width + rectPadding * 2, height: height + rectPadding * 2 }); titleX = x - rectPadding + 15; titleY = y - rectPadding + 15; } // 如果存在标题,则更新标题位置 this.updateGroupTitle(currentGroup, groupId, titleX, titleY); } this.setGroupStyle(keyShape, 'default'); }; _proto.resetNodePoint = function resetNodePoint() { this.nodePoint.length = 0; }; _proto.destroy = function destroy() { this.graph = null; this.styles = {}; this.customGroup = {}; this.delegateInGroup = {}; this.resetNodePoint(); }; return CustomGroup; }(); module.exports = CustomGroup;