UNPKG

@antv/g6

Version:

graph visualization frame work

403 lines (364 loc) 12.4 kB
/* * @Author: moyee * @Date: 2019-06-27 18:12:06 * @LastEditors: moyee * @LastEditTime: 2019-08-23 13:54:53 * @Description: 有group的情况下,拖动节点的Behavior */ const deepMix = require('@antv/util/lib/deep-mix'); const { delegateStyle } = require('../global'); const body = document.body; module.exports = { getDefaultCfg() { return { updateEdge: true, delegate: true, delegateStyle: {}, maxMultiple: 1.1, minMultiple: 1 }; }, getEvents() { return { 'node:dragstart': 'onDragStart', 'node:drag': 'onDrag', 'node:dragend': 'onDragEnd', 'canvas:mouseleave': 'onOutOfRange', mouseenter: 'onMouseEnter', mouseleave: 'onMouseLeave' }; }, onMouseEnter(evt) { const { target } = evt; const groupId = target.get('groupId'); if (groupId && this.origin) { const graph = this.graph; const customGroupControll = graph.get('customGroupControll'); const customGroup = customGroupControll.getDeletageGroupById(groupId); if (customGroup) { const { nodeGroup: currentGroup } = customGroup; const keyShape = currentGroup.get('keyShape'); this.inGroupId = groupId; customGroupControll.setGroupStyle(keyShape, 'hover'); } } }, /** * 拖动节点移除Group时的事件 * @param {Event} evt 事件句柄 */ onMouseLeave(evt) { const { target } = evt; const groupId = target.get('groupId'); if (groupId && this.origin) { const graph = this.graph; const customGroupControll = graph.get('customGroupControll'); const customGroup = customGroupControll.getDeletageGroupById(groupId); if (customGroup) { const { nodeGroup: currentGroup } = customGroup; const keyShape = currentGroup.get('keyShape'); customGroupControll.setGroupStyle(keyShape, 'default'); } } if (!groupId) { this.inGroupId = null; } }, onDragStart(e) { if (!this.shouldBegin.call(this, e)) { return; } const { item } = e; const graph = this.graph; this.targets = []; // 获取所有选中的元素 const nodes = graph.findAllByState('node', 'selected'); const currentNodeId = item.get('id'); // 当前拖动的节点是否是选中的节点 const dragNodes = nodes.filter(node => { const nodeId = node.get('id'); return currentNodeId === nodeId; }); // 只拖动当前节点 if (dragNodes.length === 0) { this.target = item; // 拖动节点时,如果在Group中,则Group高亮 const model = item.getModel(); const { groupId } = model; if (groupId) { const customGroupControll = graph.get('customGroupControll'); const customGroup = customGroupControll.getDeletageGroupById(groupId); if (customGroup) { const { nodeGroup: currentGroup } = customGroup; const keyShape = currentGroup.get('keyShape'); customGroupControll.setGroupStyle(keyShape, 'hover'); // 初始拖动时候,如果是在当前群组中拖动,则赋值为当前groupId this.inGroupId = groupId; } } } else { // 拖动多个节点 if (nodes.length > 1) { nodes.forEach(node => { this.targets.push(node); }); } else { this.targets.push(item); } } this.origin = { x: e.x, y: e.y }; this.point = {}; this.originPoint = {}; }, onDrag(e) { if (!this.origin) { return; } if (!this.get('shouldUpdate').call(this, e)) { return; } // 当targets中元素时,则说明拖动的是多个选中的元素 if (this.targets.length > 0) { this._updateDelegate(e); } else { // 只拖动单个元素 this._update(this.target, e, true); const { item } = e; const graph = this.graph; const model = item.getModel(); const { groupId } = model; if (groupId) { const customGroupControll = graph.get('customGroupControll'); const customGroup = customGroupControll.getDeletageGroupById(groupId); if (customGroup) { const { nodeGroup: currentGroup } = customGroup; const keyShape = currentGroup.get('keyShape'); // 当前 if (this.inGroupId !== groupId) { customGroupControll.setGroupStyle(keyShape, 'default'); } else { customGroupControll.setGroupStyle(keyShape, 'hover'); } } } } }, onDragEnd(e) { if (!this.origin || !this.shouldEnd.call(this, e)) { return; } if (this.shape) { this.shape.remove(); this.shape = null; } if (this.target) { const delegateShape = this.target.get('delegateShape'); if (delegateShape) { delegateShape.remove(); this.target.set('delegateShape', null); } } if (this.targets.length > 0) { // 获取所有已经选中的节点 this.targets.forEach(node => this._update(node, e)); } else if (this.target) { this._update(this.target, e); } this.point = {}; this.origin = null; this.originPoint = {}; this.targets.length = 0; this.target = null; // 终止时需要判断此时是否在监听画布外的 mouseup 事件,若有则解绑 const fn = this.fn; if (fn) { body.removeEventListener('mouseup', fn, false); this.fn = null; } this.setCurrentGroupStyle(e); }, setCurrentGroupStyle(evt) { const { item } = evt; const graph = this.graph; const autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); const model = item.getModel(); // 节点所在的GroupId const { groupId, id } = model; const customGroupControll = graph.get('customGroupControll'); const customGroup = customGroupControll.customGroup; const groupNodes = graph.get('groupNodes'); if (this.inGroupId && groupId) { const currentGroup = customGroup[groupId].nodeGroup; const keyShape = currentGroup.get('keyShape'); const itemBBox = item.getBBox(); const currentGroupBBox = keyShape.getBBox(); const { x, y } = itemBBox; const { minX, minY, maxX, maxY } = currentGroupBBox; // 在自己的group中拖动,判断是否拖出了自己的group // this.inGroupId !== groupId,则说明拖出了原来的group,拖到了其他group上面, // 则删除item中的groupId字段,同时删除group中的nodeID if ( !(x < maxX * this.maxMultiple && x > minX * this.minMultiple && y < maxY * this.maxMultiple && y > minY * this.minMultiple) || this.inGroupId !== groupId) { // 拖出了group,则删除item中的groupId字段,同时删除group中的nodeID const currentGroupNodes = groupNodes[groupId]; groupNodes[groupId] = currentGroupNodes.filter(node => node !== id); customGroupControll.dynamicChangeGroupSize(evt, currentGroup, keyShape); // 同时删除groupID中的节点 delete model.groupId; } // 拖动到其他的group上面 if (this.inGroupId !== groupId) { // 拖动新的group后,更新groupNodes及model中的groupId const nodeInGroup = customGroup[this.inGroupId].nodeGroup; const targetKeyShape = nodeInGroup.get('keyShape'); // 将该节点添加到inGroupId中 if (groupNodes[this.inGroupId].indexOf(id) === -1) { groupNodes[this.inGroupId].push(id); } // 更新节点的groupId为拖动上去的group Id model.groupId = this.inGroupId; // 拖入节点后,根据最新的节点数量,重新计算群组大小 customGroupControll.dynamicChangeGroupSize(evt, nodeInGroup, targetKeyShape); } customGroupControll.setGroupStyle(keyShape, 'default'); } else if (this.inGroupId && !groupId) { // 将节点拖动到群组中 const nodeInGroup = customGroup[this.inGroupId].nodeGroup; const keyShape = nodeInGroup.get('keyShape'); // 将该节点添加到inGroupId中 if (groupNodes[this.inGroupId].indexOf(id) === -1) { groupNodes[this.inGroupId].push(id); } // 更新节点的groupId为拖动上去的group Id model.groupId = this.inGroupId; // 拖入节点后,根据最新的节点数量,重新计算群组大小 customGroupControll.dynamicChangeGroupSize(evt, nodeInGroup, keyShape); } else if (!this.inGroupId && groupId) { // 拖出到群组之外了,则删除数据中的groupId for (const gnode in groupNodes) { const currentGroupNodes = groupNodes[gnode]; groupNodes[gnode] = currentGroupNodes.filter(node => node !== id); } const currentGroup = customGroup[groupId].nodeGroup; const keyShape = currentGroup.get('keyShape'); customGroupControll.dynamicChangeGroupSize(evt, currentGroup, keyShape); delete model.groupId; } this.inGroupId = null; graph.paint(); graph.setAutoPaint(autoPaint); }, // 若在拖拽时,鼠标移出画布区域,此时放开鼠标无法终止 drag 行为。在画布外监听 mouseup 事件,放开则终止 onOutOfRange(e) { const self = this; if (this.origin) { const canvasElement = self.graph.get('canvas').get('el'); const fn = ev => { if (ev.target !== canvasElement) { self.onDragEnd(e); } }; this.fn = fn; body.addEventListener('mouseup', fn, false); } }, _update(item, e, force) { const origin = this.origin; const model = item.get('model'); const nodeId = item.get('id'); if (!this.point[nodeId]) { this.point[nodeId] = { x: model.x, y: model.y }; } const x = e.x - origin.x + this.point[nodeId].x; const y = e.y - origin.y + this.point[nodeId].y; // 拖动单个未选中元素 if (force) { this._updateDelegate(e, x, y); return; } const pos = { x, y }; if (this.get('updateEdge')) { this.graph.updateItem(item, pos); } else { item.updatePosition(pos); this.graph.paint(); } }, /** * 更新拖动元素时的delegate * @param {Event} e 事件句柄 * @param {number} x 拖动单个元素时候的x坐标 * @param {number} y 拖动单个元素时候的y坐标 */ _updateDelegate(e, x, y) { const { item } = e; const graph = this.graph; const groupType = graph.get('groupType'); const bbox = item.get('keyShape').getBBox(); if (!this.shape) { const parent = graph.get('group'); const attrs = deepMix({}, delegateStyle, this.delegateStyle); // 拖动多个 if (this.targets.length > 0) { const nodes = graph.findAllByState('node', 'selected'); if (nodes.length === 0) { nodes.push(item); } const customGroupControll = graph.get('customGroupControll'); const { x, y, width, height } = customGroupControll.calculationGroupPosition(nodes); this.originPoint = { x, y, width, height }; // model上的x, y是相对于图形中心的,delegateShape是g实例,x,y是绝对坐标 this.shape = parent.addShape('rect', { attrs: { width, height, x, y, ...attrs } }); } else if (this.target) { this.shape = parent.addShape('rect', { attrs: { width: bbox.width, height: bbox.height, x: x - bbox.width / 2, y: y - bbox.height / 2, ...attrs } }); this.target.set('delegateShape', this.shape); } this.shape.set('capture', false); } if (this.targets.length > 0) { const clientX = e.x - this.origin.x + this.originPoint.minX; const clientY = e.y - this.origin.y + this.originPoint.minY; this.shape.attr({ x: clientX, y: clientY }); } else if (this.target) { if (groupType === 'circle') { this.shape.attr({ x: x - bbox.width / 2, y: y - bbox.height / 2 }); } else if (groupType === 'rect') { this.shape.attr({ x, y }); } } this.graph.paint(); } };