replace ghost nodes by real nodes on drag end

This commit is contained in:
David Mosbach 2023-08-26 04:40:44 +02:00
parent 89c1d44141
commit 0e408faabc

View File

@ -428,6 +428,7 @@ var selection : WF.WFNode | WF.WFGhostNode | WF.WFEdge | null = null; // The cur
var rightSelection : WF.WFNode | WF.WFEdge | null = null; // The currently right clicked node/edge. var rightSelection : WF.WFNode | WF.WFEdge | null = null; // The currently right clicked node/edge.
var edgeTo : WF.WFNode | null = null; // Target of an edge to be created. var edgeTo : WF.WFNode | null = null; // Target of an edge to be created.
var edgeFrom : WF.WFNode | null = null; // Start on an edge to be created. var edgeFrom : WF.WFNode | null = null; // Start on an edge to be created.
var edgeTarget : WF.WFNode | null = null; // Possible source/target for an edge after dragging the respective ghost node.
//Utility elements //Utility elements
const curtain = <HTMLElement>document.getElementById('curtain'); const curtain = <HTMLElement>document.getElementById('curtain');
const submenuBackdrop = <HTMLElement>document.getElementById('submenu-backdrop'); const submenuBackdrop = <HTMLElement>document.getElementById('submenu-backdrop');
@ -572,14 +573,16 @@ export function addState() {
var nodeId = stateIdCounter ++; var nodeId = stateIdCounter ++;
var x = newStateCoords.x; var x = newStateCoords.x;
var y = newStateCoords.y; var y = newStateCoords.y;
var state : WF.WFNode = { id: 'state_' + nodeId, var state = new WF.WFNode ({
x: x, id: 'state_' + nodeId,
y: y, x: x,
name: 'state_' + nodeId, y: y,
fx: x, name: 'state_' + nodeId,
fy: y, fx: x,
val: 5, fy: y,
stateData: new WF.StateData({ abbreviation: `S${nodeId}`, final: 'false' }) }; val: 5,
stateData: { abbreviation: `S${nodeId}`, final: 'false' }
});
workflow.states.push(state); workflow.states.push(state);
updateGraph(); updateGraph();
select(state); select(state);
@ -587,8 +590,8 @@ export function addState() {
} }
export function addEdge() { export function addEdge() {
var x = newStateCoords.x; var x = newStateCoords.x - 20;
var y = newStateCoords.y; var y = newStateCoords.y + 20;
var ghostState = new WF.WFGhostNode({ var ghostState = new WF.WFGhostNode({
id: `@@ghost@(${x},${y})`, id: `@@ghost@(${x},${y})`,
x: x, x: x,
@ -596,11 +599,13 @@ export function addEdge() {
fx: x, fx: x,
fy: y, fy: y,
val: 7 }); val: 7 });
var x = newStateCoords.x + 20;
var y = newStateCoords.y - 20;
var ghostState2 = new WF.WFGhostNode({ var ghostState2 = new WF.WFGhostNode({
id: `@@ghost@(${x+50},${y})`, id: `@@ghost@(${x},${y})`,
x: x + 50, x: x,
y: y, y: y,
fx: x + 50, fx: x,
fy: y, fy: y,
val: 7 }); val: 7 });
workflow.states.push(ghostState, ghostState2); workflow.states.push(ghostState, ghostState2);
@ -712,14 +717,15 @@ function removeAction(action: WF.WFEdge) {
* Removes a state from the workflow. * Removes a state from the workflow.
* @param {*} state The state to remove. * @param {*} state The state to remove.
*/ */
function removeState(state: WF.WFNode) { function removeState(state: WF.WFNode | WF.WFGhostNode) {
workflow.actions workflow.actions
.filter(edge => edge.source === state || edge.target === state) .filter(edge => edge.source === state || edge.target === state)
.forEach(edge => removeAction(edge)); .forEach(edge => removeAction(edge));
workflow.states.splice(workflow.states.indexOf(state), 1); workflow.states.splice(workflow.states.indexOf(state), 1);
var abbreviation = state.stateData && state.stateData.abbreviation; if (state instanceof WF.WFNode) {
abbreviation && stateAbbreviations.splice(stateAbbreviations.indexOf(abbreviation), 1); stateAbbreviations.splice(stateAbbreviations.indexOf(state.stateData.abbreviation), 1);
nodeIndex.remove(state.id); nodeIndex.remove(state.id);
}
} }
var selfLoops: Map<string, WF.WFEdge[]> = new Map(); // All edges whose targets equal their sources. var selfLoops: Map<string, WF.WFEdge[]> = new Map(); // All edges whose targets equal their sources.
@ -1186,6 +1192,13 @@ function getEdgeColour(edge: LinkObject) {
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.stroke(); ctx.stroke();
ctx.restore(); ctx.restore();
} else if (edgeTarget === node) {
ctx.save();
ctx.lineCap = 'round';
ctx.lineWidth = 2;
ctx.strokeStyle = nodeColourDefaultFinal.value();
ctx.stroke();
ctx.restore();
} else if (node === selection || node === rightSelection) { } else if (node === selection || node === rightSelection) {
ctx.save(); ctx.save();
ctx.lineCap = 'round'; ctx.lineCap = 'round';
@ -1207,9 +1220,37 @@ function getEdgeColour(edge: LinkObject) {
ctx.fillText(wfNode.text, wfNode.x, wfNode.y); ctx.fillText(wfNode.text, wfNode.x, wfNode.y);
} }
}) })
.onNodeDrag((node: NodeObject, delta: { x: number, y: number }) => {
edgeTarget = null;
if (!(node instanceof WF.WFGhostNode)) return;
const fineTuningThreshold = 0;
if (Math.sqrt(Math.round(Math.abs(delta.x * delta.y))) > fineTuningThreshold) return;
for (const node2 of workflow.states) {
if (!(node2 instanceof WF.WFNode)) continue;
if (Math.sqrt(Math.pow(node.x - node2.x, 2) + Math.pow(node.y - node2.y, 2)) <= 2*node2.val) {
edgeTarget = node2;
break;
}
}
console.log('close:', edgeTarget);
})
.onNodeDragEnd((node: NodeObject) => { .onNodeDragEnd((node: NodeObject) => {
node.fx = node.x; node.fx = node.x;
node.fy = node.y; node.fy = node.y;
if (node instanceof WF.WFGhostNode && edgeTarget) {
var edgesFrom : WF.WFEdge[] = [];
var edgesTo : WF.WFEdge[] = [];
workflow.actions.forEach(edge => {
edge.source === node && edgesFrom.push(edge);
edge.target === node && edgesTo.push(edge);
});
if (!(edgesFrom || edgesTo)) throw new Error('Could not find an edge for the dragged ghost node');
edgesFrom.forEach(edge => edge.source = <WF.WFNode>edgeTarget);
edgesTo.forEach(edge => edge.target = <WF.WFNode>edgeTarget);
removeState(node);
updateGraph();
}
}) })
.onNodeClick((node: NodeObject, _: MouseEvent) => { .onNodeClick((node: NodeObject, _: MouseEvent) => {
const wfNode = node as (WF.WFNode | WF.WFGhostNode); const wfNode = node as (WF.WFNode | WF.WFGhostNode);