nope/resources/ui/graph/addons/selectionbox.extension.ts
2020-10-25 21:14:51 +01:00

158 lines
4.8 KiB
TypeScript

/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-03-12 14:17:14
* @modify date 2020-03-12 14:17:14
* @desc [description]
*/
import { IUndoRedoGraph } from '../interfaces/IGraph';
// Handle the right clic rectangle selection of nodes
// ========
// Everything is in there
/**
* Handle the right clic rectangle selection of nodes
* @param network The Network, which should be used for Selection Boxes
*/
export function makeMeMultiSelect<N, E>(network: IUndoRedoGraph<N,E>, DELAY = 200) {
const NO_CLICK = 0;
const RIGHT_CLICK = 3;
// Disable default right-click dropdown menu
const container = network.network.body.container;
// States
let drag = false;
let DOMRect: any = {};
// Selector
const canvasify = (DOMx, DOMy) => {
const { x, y } = network.network.DOMtoCanvas({ x: DOMx, y: DOMy });
return [x, y];
};
const correctRange = (start, end) =>
start < end ? [start, end] : [end, start];
const selectFromDOMRect = () => {
const [sX, sY] = canvasify(DOMRect.startX, DOMRect.startY);
const [eX, eY] = canvasify(DOMRect.endX, DOMRect.endY);
const [startX, endX] = correctRange(sX, eX);
const [startY, endY] = correctRange(sY, eY);
const nodes = network.nodes.filter(node => {
return (network.network.findNode(node.id).length == 1 && startX <= node.x && node.x <= endX && startY <= node.y && node.y <= endY)
}).map(node => node.id);
network.network.selectNodes(nodes);
}
let enableSlectionBockTimer;
let start_pos: {layerX: number, layerY: number } | null = null;
let mouse_pos: {layerX: number, layerY: number } | null = null;
// Listeners
const org_onmousedown = container.onmousedown;
container.onmousedown = function(event){
const { which, layerX, layerY } = event;
// Store the Initial Position
start_pos = {
layerX,
layerY
}
// When mousedown, save the initial rectangle state
if(which === RIGHT_CLICK) {
Object.assign(DOMRect, {
startX: layerX,
startY: layerY,
endX: layerX,
endY: layerY
});
enableSlectionBockTimer = setTimeout( ()=> {
if (Math.abs(mouse_pos.layerX - start_pos.layerX) > 5 || Math.abs(mouse_pos.layerY - start_pos.layerY) > 5){
drag = true;
}
}, DELAY)
} else if (typeof org_onmousedown === 'function') {
org_onmousedown(event);
}
};
const org_onmousemove = container.onmousemove;
container.onmousemove = function(event){
const { which, layerX, layerY } = event;
// Store the Mouse Position
mouse_pos = {
layerX,
layerY
}
// When mousedown, save the initial rectangle state
// Make selection rectangle disappear when accidently mouseupped outside 'container'
if(which === NO_CLICK && drag) {
drag = false;
network.network.redraw();
}
// When mousemove, update the rectangle state
else if(drag) {
Object.assign(DOMRect, {
endX: layerX,
endY: layerY
});
network.network.redraw();
} else if (typeof org_onmousemove === 'function'){
org_onmousemove(event);
}
}
const org_onmouseup = container.onmouseup;
container.onmouseup = function(event){
const { which, pageX, pageY } = event;
// When mousedown, save the initial rectangle state
if(which === RIGHT_CLICK && drag) {
selectFromDOMRect();
if (enableSlectionBockTimer){
clearTimeout(enableSlectionBockTimer)
}
setTimeout(()=> {
drag = false;
network.network.redraw();
})
} else if (typeof org_onmouseup === 'function') {
org_onmouseup(event);
}
};
network.on('oncontext', (params) => {
params.event.preventDefault();
if ( drag ) {
params.event.prevent = true;
}
})
// Drawer
network.on('afterDrawing', ctx => {
if(drag) {
const [startX, startY] = canvasify(DOMRect.startX, DOMRect.startY);
const [endX, endY] = canvasify(DOMRect.endX, DOMRect.endY);
ctx.setLineDash([5]);
ctx.strokeStyle = 'rgba(78, 146, 237, 0.75)';
ctx.strokeRect(startX, startY, endX - startX, endY - startY);
ctx.setLineDash([]);
ctx.fillStyle = 'rgba(151, 194, 252, 0.45)';
ctx.fillRect(startX, startY, endX - startX, endY - startY);
}
});
};