From 8cc2151e8d337cd206ecce2100689a1935dff6e6 Mon Sep 17 00:00:00 2001 From: "zhanning.bzn" Date: Fri, 11 Oct 2019 17:40:06 +0800 Subject: [PATCH] default behavior support custom config --- demos/layout-force.html | 60 +++++++++++++++++++----------- src/behavior/activate-relations.js | 41 ++++++++++++++++++-- src/behavior/brush-select.js | 56 ++++++++++++++++++++++++++-- src/behavior/click-select.js | 14 +++++-- src/behavior/drag-canvas.js | 28 +++++++++++++- src/behavior/drag-node.js | 14 +++++-- 6 files changed, 176 insertions(+), 37 deletions(-) diff --git a/demos/layout-force.html b/demos/layout-force.html index cde6006b61..fb3ac2cdbc 100644 --- a/demos/layout-force.html +++ b/demos/layout-force.html @@ -1525,10 +1525,17 @@ type: 'force' }, modes: { - default: ['drag-node', 'activate-relations'] + default: [ + { + type: 'drag-node', + enableDelegate: true + }, { + type: 'brush-select', + trigger: 'Shift' + }, 'click-select', 'activate-relations'] }, defaultNode: { - size: [10, 10], + size: [30, 30], style: { fill: 'steelblue' } @@ -1545,18 +1552,23 @@ }, nodeStateStyles: { inactive: { - fillOpacity: 0.5 + fillOpacity: 0.1 }, active: { - fillOpacity: 1 + fillOpacity: 0.8, + fill: 'green' + }, + + selected: { + fill: 'red' } }, edgeStateStyles: { inactive: { - fillOpacity: 0.5 + fillOpacity: 0.1 }, active: { - fillOpacity: 1 + fillOpacity: 8 } } }); @@ -1569,22 +1581,26 @@ }) }); graph.render(); - function refreshDragedNodePosition(e) { - const model = e.item.get('model'); - model.fx = e.x; - model.fy = e.y; - } - graph.on('node:dragstart', e => { - graph.layout(); - refreshDragedNodePosition(e); - }); - graph.on('node:drag', e => { - refreshDragedNodePosition(e); - }); - graph.on('node:dragend', e => { - e.item.get('model').fx = null; - e.item.get('model').fy = null; - }); + // function refreshDragedNodePosition(e) { + // const model = e.item.get('model'); + // model.fx = e.x; + // model.fy = e.y; + // } + // graph.on('node:dragstart', e => { + // graph.layout(); + // refreshDragedNodePosition(e); + // }); + // graph.on('node:drag', e => { + // refreshDragedNodePosition(e); + // }); + // graph.on('node:dragend', e => { + // e.item.get('model').fx = null; + // e.item.get('model').fy = null; + // }); + // graph.on('node:click', evt => { + // const { item } = evt; + // graph.setItemState(item, 'selected', true) + // }) diff --git a/src/behavior/activate-relations.js b/src/behavior/activate-relations.js index 92543a6154..24e4981bd9 100644 --- a/src/behavior/activate-relations.js +++ b/src/behavior/activate-relations.js @@ -4,6 +4,7 @@ module.exports = { trigger: 'mouseenter', // 可选 mouseenter || click activeState: 'active', inactiveState: 'inactive', + resetSelected: false, shouldUpdate() { return true; } }; }, @@ -26,11 +27,18 @@ module.exports = { if (!this.shouldUpdate(e.item, { event: e, action: 'activate' })) { return; } + const self = this; const activeState = this.get('activeState'); const inactiveState = this.get('inactiveState'); const autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); graph.getNodes().forEach(function(node) { + const hasSelected = node.hasState('selected'); + if (self.resetSelected) { + if (hasSelected) { + graph.setItemState(node, 'selected', false); + } + } graph.setItemState(node, activeState, false); inactiveState && graph.setItemState(node, inactiveState, true); }); @@ -42,14 +50,34 @@ module.exports = { graph.setItemState(item, activeState, true); graph.getEdges().forEach(function(edge) { if (edge.getSource() === item) { - inactiveState && graph.setItemState(edge.getTarget(), inactiveState, false); - graph.setItemState(edge.getTarget(), activeState, true); + const target = edge.getTarget(); + const hasSelected = target.hasState('selected'); + if (self.resetSelected) { + // inactiveState && graph.setItemState(target, inactiveState, false); + // graph.setItemState(target, activeState, true); + if (hasSelected) { + graph.setItemState(target, 'selected', false); + } + } + inactiveState && graph.setItemState(target, inactiveState, false); + graph.setItemState(target, activeState, true); graph.setItemState(edge, activeState, true); graph.setItemState(edge, inactiveState, false); edge.toFront(); } else if (edge.getTarget() === item) { - inactiveState && graph.setItemState(edge.getSource(), inactiveState, false); - graph.setItemState(edge.getSource(), activeState, true); + // inactiveState && graph.setItemState(edge.getSource(), inactiveState, false); + // graph.setItemState(edge.getSource(), activeState, true); + + const source = edge.getSource(); + const hasSelected = source.hasState('selected'); + if (self.resetSelected) { + if (hasSelected) { + graph.setItemState(source, 'selected', false); + } + } + + inactiveState && graph.setItemState(source, inactiveState, false); + graph.setItemState(source, activeState, true); graph.setItemState(edge, activeState, true); graph.setItemState(edge, inactiveState, false); edge.toFront(); @@ -64,10 +92,15 @@ module.exports = { if (!this.shouldUpdate(e.item, { event: e, action: 'deactivate' })) { return; } + const self = this; const autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); graph.getNodes().forEach(function(node) { + const hasSelected = node.hasState('selected'); graph.clearItemStates(node); + if (hasSelected) { + graph.setItemState(node, 'selected', !self.resetSelected); + } }); graph.getEdges().forEach(function(edge) { graph.clearItemStates(edge); diff --git a/src/behavior/brush-select.js b/src/behavior/brush-select.js index 92ea34ffdf..75c4583f1c 100644 --- a/src/behavior/brush-select.js +++ b/src/behavior/brush-select.js @@ -1,7 +1,8 @@ const min = Math.min; const max = Math.max; const abs = Math.abs; -const hypot = Math.hypot; +const DEFAULT_TRIGGER = 'shift'; +const ALLOW_EVENTS = [ 'drag', 'shift', 'ctrl', 'alt' ]; module.exports = { getDefaultCfg() { @@ -15,17 +16,36 @@ module.exports = { onSelect() {}, onDeselect() {}, selectedState: 'selected', + trigger: DEFAULT_TRIGGER, includeEdges: true, selectedEdges: [], selectedNodes: [] }; }, getEvents() { + let trigger; + // 检测输入是否合法 + if (ALLOW_EVENTS.indexOf(this.trigger.toLowerCase()) > -1) { + trigger = this.trigger; + } else { + trigger = DEFAULT_TRIGGER; + console.warn('Behavior brush-select的trigger参数不合法,请输入drag、shift、ctrl或alt'); + } + if (trigger === 'drag') { + return { + mousedown: 'onMouseDown', + mousemove: 'onMouseMove', + mouseup: 'onMouseUp', + 'canvas:click': 'clearStates' + }; + } return { mousedown: 'onMouseDown', mousemove: 'onMouseMove', mouseup: 'onMouseUp', - 'canvas:click': 'clearStates' + 'canvas:click': 'clearStates', + keyup: 'onKeyUp', + keydown: 'onKeyDown' }; }, onMouseDown(e) { @@ -35,6 +55,10 @@ module.exports = { return; } + if (this.trigger !== 'drag' && !this.keydown) { + return; + } + if (this.selectedNodes && this.selectedNodes.length !== 0) { this.clearStates(); } @@ -49,10 +73,14 @@ module.exports = { this.dragging = true; }, onMouseMove(e) { - const originPoint = this.originPoint; - if (!this.dragging || hypot(originPoint.x - e.canvasX, originPoint.y - e.canvasY) < 10) { + if (!this.dragging) { return; } + + if (this.trigger !== 'drag' && !this.keydown) { + return; + } + this._updateBrush(e); this.graph.paint(); }, @@ -60,6 +88,11 @@ module.exports = { if (!this.brush) { return; } + + if (this.trigger !== 'drag' && !this.keydown) { + return; + } + const graph = this.graph; const autoPaint = graph.get('autoPaint'); graph.setAutoPaint(false); @@ -155,5 +188,20 @@ module.exports = { x: min(e.canvasX, originPoint.x), y: min(e.canvasY, originPoint.y) }); + }, + onKeyDown(e) { + const code = e.key; + if (code && code.toLowerCase() === this.trigger.toLowerCase()) { + this.keydown = true; + } else { + this.keydown = false; + } + }, + onKeyUp() { + if (this.brush) { + this.brush.hide(); + this.dragging = false; + } + this.keydown = false; } }; diff --git a/src/behavior/click-select.js b/src/behavior/click-select.js index 51f0740965..6b644aafdd 100644 --- a/src/behavior/click-select.js +++ b/src/behavior/click-select.js @@ -1,13 +1,21 @@ const Util = require('../util'); +const DEFAULT_TRIGGER = 'shift'; +const ALLOW_EVENTS = [ 'shift', 'ctrl', 'alt' ]; module.exports = { getDefaultCfg() { return { multiple: true, - keyCode: 16 + trigger: DEFAULT_TRIGGER }; }, getEvents() { + if (!this.multiple) { + return { + 'node:click': 'onClick', + 'canvas:click': 'onCanvasClick' + }; + } return { 'node:click': 'onClick', 'canvas:click': 'onCanvasClick', @@ -59,8 +67,8 @@ module.exports = { graph.setAutoPaint(autoPaint); }, onKeyDown(e) { - const code = e.keyCode || e.which; - if (code === this.keyCode) { + const code = e.key; + if (ALLOW_EVENTS.indexOf(code.toLowerCase() > -1)) { this.keydown = true; } else { this.keydown = false; diff --git a/src/behavior/drag-canvas.js b/src/behavior/drag-canvas.js index 7c43789fbd..0fd27eff3d 100644 --- a/src/behavior/drag-canvas.js +++ b/src/behavior/drag-canvas.js @@ -2,6 +2,7 @@ const Util = require('../util'); const abs = Math.abs; const DRAG_OFFSET = 10; const body = document.body; +const ALLOW_EVENTS = [ 16, 17, 18 ]; module.exports = { getDefaultCfg() { @@ -15,7 +16,9 @@ module.exports = { 'canvas:mousemove': 'onMouseMove', 'canvas:mouseup': 'onMouseUp', 'canvas:click': 'onMouseUp', - 'canvas:mouseleave': 'onOutOfRange' + 'canvas:mouseleave': 'onOutOfRange', + keyup: 'onKeyUp', + keydown: 'onKeyDown' }; }, updateViewport(e) { @@ -40,10 +43,18 @@ module.exports = { this.graph.paint(); }, onMouseDown(e) { + if (this.keydown) { + return; + } + this.origin = { x: e.clientX, y: e.clientY }; this.dragging = false; }, onMouseMove(e) { + if (this.keydown) { + return; + } + e = Util.cloneEvent(e); const graph = this.graph; if (!this.origin) { return; } @@ -66,6 +77,10 @@ module.exports = { } }, onMouseUp(e) { + if (this.keydown) { + return; + } + if (!this.dragging) { this.origin = null; return; @@ -104,5 +119,16 @@ module.exports = { this.fn = fn; body.addEventListener('mouseup', fn, false); } + }, + onKeyDown(e) { + const code = e.keyCode || e.which; + if (ALLOW_EVENTS.indexOf(code) > -1) { + this.keydown = true; + } else { + this.keydown = false; + } + }, + onKeyUp() { + this.keydown = false; } }; diff --git a/src/behavior/drag-node.js b/src/behavior/drag-node.js index 71923ff4d7..6f8c673987 100644 --- a/src/behavior/drag-node.js +++ b/src/behavior/drag-node.js @@ -14,7 +14,9 @@ module.exports = { getDefaultCfg() { return { updateEdge: true, - delegateStyle: {} + delegateStyle: {}, + // 是否开启delegate + enableDelegate: false }; }, getEvents() { @@ -78,10 +80,16 @@ module.exports = { // 当targets中元素时,则说明拖动的是多个选中的元素 if (this.targets.length > 0) { - this._updateDelegate(e); + if (this.enableDelegate) { + this._updateDelegate(e); + } else { + this.targets.forEach(target => { + this._update(target, e, this.enableDelegate); + }); + } } else { // 只拖动单个元素 - this._update(this.target, e, true); + this._update(this.target, e, this.enableDelegate); } }, onDragEnd(e) {