UNPKG

@antv/g6

Version:

graph visualization frame work

302 lines (272 loc) 7.52 kB
/* * @Author: moyee * @Date: 2019-06-27 18:12:06 * @LastEditors: moyee * @LastEditTime: 2019-08-22 18:41:45 * @Description: 拖动节点的Behavior */ const isString = require('@antv/util/lib/type/is-string'); const deepMix = require('@antv/util/lib/deep-mix'); const { delegateStyle } = require('../global'); const body = document.body; module.exports = { getDefaultCfg() { return { updateEdge: true, delegateStyle: {}, // 是否开启delegate enableDelegate: false }; }, getEvents() { return { 'node:dragstart': 'onDragStart', 'node:drag': 'onDrag', 'node:dragend': 'onDragEnd', 'canvas:mouseleave': 'onOutOfRange' }; }, onDragStart(e) { if (!this.shouldBegin.call(this, e)) { return; } const { item } = e; const hasLocked = item.hasLocked(); if (hasLocked) { return; } 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; } else { // 拖动多个节点 if (nodes.length > 1) { nodes.forEach(node => { const hasLocked = node.hasLocked(); if (!hasLocked) { 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; } const graph = this.graph; const autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); // 当targets中元素时,则说明拖动的是多个选中的元素 if (this.targets.length > 0) { if (this.enableDelegate) { this._updateDelegate(e); } else { this.targets.forEach(target => { this._update(target, e, this.enableDelegate); }); } } else { // 只拖动单个元素 this._update(this.target, e, this.enableDelegate); } graph.paint(); graph.setAutoPaint(autoPaint); }, onDragEnd(e) { if (!this.origin || !this.shouldEnd.call(this, e)) { return; } const graph = this.graph; const autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); 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; } 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 bbox = e.item.get('keyShape').getBBox(); if (!this.shape) { // 拖动多个 const parent = this.graph.get('group'); const attrs = deepMix({}, delegateStyle, this.delegateStyle); if (this.targets.length > 0) { const { x, y, width, height, minX, minY } = this.calculationGroupPosition(); this.originPoint = { x, y, width, height, minX, minY }; // 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.x, y: y + bbox.y, ...attrs } }); this.target.set('delegateShape', this.shape); } this.shape.set('capture', false); } else { 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) { this.shape.attr({ x: x + bbox.x, y: y + bbox.y }); } } // this.graph.paint(); }, /** * 计算delegate位置,包括左上角左边及宽度和高度 * @memberof ItemGroup * @return {object} 计算出来的delegate坐标信息及宽高 */ calculationGroupPosition() { const graph = this.graph; const nodes = graph.findAllByState('node', 'selected'); let minx = Infinity; let maxx = -Infinity; let miny = Infinity; let maxy = -Infinity; // 获取已节点的所有最大最小x y值 for (const id of nodes) { const element = isString(id) ? graph.findById(id) : id; const bbox = element.getBBox(); const { minX, minY, maxX, maxY } = bbox; if (minX < minx) { minx = minX; } if (minY < miny) { miny = minY; } if (maxX > maxx) { maxx = maxX; } if (maxY > maxy) { maxy = maxY; } } const x = Math.floor(minx) - 20; const y = Math.floor(miny) + 10; const width = Math.ceil(maxx) - x; const height = Math.ceil(maxy) - y; return { x, y, width, height, minX: minx, minY: miny }; } };