锁定/解锁节点
lock()
、unlock()
和 hasLocked()
三个 API,方便用户锁定某个节点。默认情况下,当锁定某个节点后,拖动节点时锁定的节点不会有任何反应,但拖动画布和缩放画布时,仍然会对锁定的节点有影响,如果不想让锁定的节点收到拖动画布和缩放画布的影响,可以通过自定义 Behavior 的方式来实现。
拖动画布时候不处理锁定的节点
F6 内置的 drag-canvas
不区分节点是否锁定,全部一视同仁。绝大数情况下,这种行为是完全没问题的,但某些业务可能会要求锁定的节点,拖动画布时也不能移动,对于这种情况,可以通过重新定义拖动画布的 Behavior 来实现。
import F6 from '@antv/g6';
const Util = F6.Util;
const abs = Math.abs;
const DRAG_OFFSET = 10;
const body = document.body;
const ALLOW_EVENTS = [16, 17, 18];
F6.registerBehavior('drag-canvas-exclude-lockedNode', {
getDefaultCfg() {
return {
direction: 'both',
};
},
getEvents() {
return {
'canvas:mousedown': 'onMouseDown',
'canvas:mousemove': 'onMouseMove',
'canvas:mouseup': 'onTap',
'canvas:tap': 'onTap',
'canvas:mouseleave': 'onOutOfRange',
keyup: 'onKeyUp',
keydown: 'onKeyDown',
};
},
updateViewport(e) {
const origin = this.origin;
const clientX = +e.clientX;
const clientY = +e.clientY;
if (isNaN(clientX) || isNaN(clientY)) {
return;
}
let dx = clientX - origin.x;
let dy = clientY - origin.y;
if (this.get('direction') === 'x') {
dy = 0;
} else if (this.get('direction') === 'y') {
dx = 0;
}
this.origin = {
x: clientX,
y: clientY,
};
// 和内置 drag-canvas 不同的地方是在这里
const lockedNodes = this.graph.findAll('node', (node) => !node.hasLocked());
lockedNodes.forEach((node) => {
node.get('group').translate(dx, dy);
});
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;
}
if (this.origin && !this.dragging) {
if (abs(this.origin.x - e.clientX) + abs(this.origin.y - e.clientY) < DRAG_OFFSET) {
return;
}
if (this.shouldBegin.call(this, e)) {
e.type = 'dragstart';
graph.emit('canvas:dragstart', e);
this.dragging = true;
}
}
if (this.dragging) {
e.type = 'drag';
graph.emit('canvas:drag', e);
}
if (this.shouldUpdate.call(this, e)) {
this.updateViewport(e);
}
},
onTap(e) {
if (this.keydown) {
return;
}
if (!this.dragging) {
this.origin = null;
return;
}
e = Util.cloneEvent(e);
const graph = this.graph;
if (this.shouldEnd.call(this, e)) {
this.updateViewport(e);
}
e.type = 'dragend';
graph.emit('canvas:dragend', e);
this.endDrag();
},
endDrag() {
if (this.dragging) {
this.origin = null;
this.dragging = false;
// 终止时需要判断此时是否在监听画布外的 mouseup 事件,若有则解绑
const fn = this.fn;
if (fn) {
body.removeEventListener('mouseup', fn, false);
this.fn = null;
}
}
},
onOutOfRange(e) {
if (this.dragging) {
const self = this;
const canvasElement = self.graph.get('canvas').get('el');
const fn = (ev) => {
if (ev.target !== canvasElement) {
self.onTap(e);
}
};
this.fn = fn;
body.addEventListener('mouseup', fn, false);
}
},
onKeyDown(e) {
const code = e.keyCode || e.which;
if (!code) {
return;
}
if (ALLOW_EVENTS.indexOf(code) > -1) {
this.keydown = true;
} else {
this.keydown = false;
}
},
onKeyUp() {
this.keydown = false;
},
});
缩放画布时不处理锁定的节点
默认情况下,F6 内置的 zoom-canvas
在缩放画布时候也会对锁定的节点缩放,如果缩放过程中不需要操作锁定的节点,则可以通过下面的方式来实现。
const DELTA = 0.05;
F6.registerBehavior('zoom-canvas-exclude-lockedNode', {
getDefaultCfg() {
return {
sensitivity: 2,
minZoom: 0.1,
maxZoom: 10,
};
},
getEvents() {
return {
wheel: 'onWheel',
};
},
onWheel(e) {
e.preventDefault();
if (!this.shouldUpdate.call(this, e)) {
return;
}
const graph = this.graph;
const canvas = graph.get('canvas');
const point = canvas.getPointByClient(e.clientX, e.clientY);
const sensitivity = this.get('sensitivity');
let ratio = graph.getZoom();
// 兼容 IE、Firefox 及 Chrome
if (e.wheelDelta < 0) {
ratio = 1 - DELTA * sensitivity;
} else {
ratio = 1 + DELTA * sensitivity;
}
const zoom = ratio * graph.getZoom();
if (zoom > this.get('maxZoom') || zoom < this.get('minZoom')) {
return;
}
graph.zoom(ratio, { x: point.x, y: point.y });
const lockedNodes = this.graph.findAll('node', (node) => !node.hasLocked());
lockedNodes.forEach((node) => {
const matrix = Util.clone(node.get('group').getMatrix());
const center = node.getModel();
matrix = Util.transform(matrix, [
['t', -center.x, -center.y],
['s', ratio, ratio],
['t', center.x, center.y],
]);
node.get('group').setMatrix(matrix);
});
graph.paint();
graph.emit('wheelzoom', e);
},
});