From ebce6fbdf8a32cf383e027b5b71cbf2cc7443a19 Mon Sep 17 00:00:00 2001 From: MWicenec Date: Fri, 13 Oct 2023 15:30:45 +0800 Subject: [PATCH] simplified port position saving --- src/Field.ts | 31 +++------- src/GraphRenderer.ts | 142 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 141 insertions(+), 32 deletions(-) diff --git a/src/Field.ts b/src/Field.ts index a8921f21f..9f8c9e956 100644 --- a/src/Field.ts +++ b/src/Field.ts @@ -16,10 +16,8 @@ export class Field { private positional : ko.Observable; private keyAttribute : ko.Observable; - private inputX : number; - private inputY : number; - private outputX : number; - private outputY : number; + private x : number; + private y : number; // port-specific attributes private id : ko.Observable; @@ -40,10 +38,8 @@ export class Field { this.positional = ko.observable(positional); this.keyAttribute = ko.observable(keyAttribute); - this.inputX = 0; - this.inputY = 0; - this.outputX = 0; - this.outputY = 0; + this.x = 0; + this.y = 0; this.id = ko.observable(id); this.parameterType = ko.observable(parameterType); @@ -100,22 +96,13 @@ export class Field { return this.description() == "" ? "No description available" + " (" + this.type() + ", default value:'" + this.defaultValue() + "')" : this.description() + " (" + this.type() + ", default value:'" + this.defaultValue() + "')"; }, this); - getInputPosition = () : {x:number, y:number} => { - return {x: this.inputX, y: this.inputY}; + getPortPosition = () : {x:number, y:number} => { + return {x: this.x, y: this.y}; } - getOutputPosition = () : {x:number, y:number} => { - return {x: this.outputX, y: this.outputY}; - } - - setInputPosition = (x: number, y: number) : void => { - this.inputX = x; - this.inputY = y; - } - - setOutputPosition = (x: number, y: number) : void => { - this.outputX = x; - this.outputY = y; + setPortPosition = (x: number, y: number) : void => { + this.x = x; + this.y = y; } isReadonly = () : boolean => { diff --git a/src/GraphRenderer.ts b/src/GraphRenderer.ts index 75c732923..d429e4913 100644 --- a/src/GraphRenderer.ts +++ b/src/GraphRenderer.ts @@ -76,7 +76,6 @@ ko.bindingHandlers.graphRendererPortPosition = { const data = ko.utils.unwrapObservable(valueAccessor()).data; const dataType: string = ko.utils.unwrapObservable(valueAccessor()).type; - const portOnEmbeddedApp = false //used to identify when we are calculating the port position for a port on an embedded application // determine the 'node' and 'field' attributes (for this way of using this binding) let node : Node @@ -158,10 +157,10 @@ ko.bindingHandlers.graphRendererPortPosition = { //for branch nodes the ports are inset from the outer radius a little bit in their design let nodeRadius = node.getRadius() - if(portOnEmbeddedApp){ - // if we are working with ports of an embedded app, we need to use the parent construct to calculate the angle, but we want to use the radius of the embedded app to place the port - nodeRadius = eagle.logicalGraph().findNodeByKeyQuiet(data.getNodeKey()).getRadius() - } + // if(portOnEmbeddedApp){ + // // if we are working with ports of an embedded app, we need to use the parent construct to calculate the angle, but we want to use the radius of the embedded app to place the port + // nodeRadius = eagle.logicalGraph().findNodeByKeyQuiet(data.getNodeKey()).getRadius() + // } // determine port position const currentNodePos = node.getPosition(); @@ -206,9 +205,9 @@ ko.bindingHandlers.graphRendererPortPosition = { } if (dataType === 'inputPort'){ - field.setInputPosition(portPosition.x, portPosition.y); + field.setPortPosition(portPosition.x, portPosition.y); } else if (dataType === 'outputPort'){ - field.setOutputPosition(portPosition.x, portPosition.y); + field.setPortPosition(portPosition.x, portPosition.y); } let x @@ -251,9 +250,132 @@ export class GraphRenderer { static nodeDragElement : any = null // static isDraggingPortValid : Eagle.LinkValid = Eagle.LinkValid.Unknown; - static graphMousePos = { x: -1, y: -1 }; + static getPortPositions(node: Node,field:Field,dataType:string) : void { + //the update function is called initially and then whenever a change to a utilised observable occurs + const eagle : Eagle = Eagle.getInstance(); + + const portOnEmbeddedApp = false //used to identify when we are calculating the port position for a port on an embedded application + + // clearing the saved port angles array + node.resetPortAngles() + + // determine all the adjacent nodes + const adjacentNodes: Node[] = []; + let connectedField:boolean=false; + + switch(dataType){ + case 'comment': + const adjacentNode: Node = eagle.logicalGraph().findNodeByKeyQuiet(node.getSubjectKey()); + + if (adjacentNode === null){ + console.warn("Could not find adjacentNode for comment with subjectKey", node.getSubjectKey()); + return; + } + + adjacentNodes.push(adjacentNode); + break; + + case 'inputApp': + case 'inputPort': + for(const edge of eagle.logicalGraph().getEdges()){ + if(field.getId()===edge.getDestPortId()){ + const adjacentNode: Node = eagle.logicalGraph().findNodeByKeyQuiet(edge.getSrcNodeKey()); + connectedField=true + adjacentNodes.push(adjacentNode); + continue; + } + } + break; + + case 'outputApp': + case 'outputPort': + for(const edge of eagle.logicalGraph().getEdges()){ + if(field.getId()===edge.getSrcPortId()){ + const adjacentNode: Node = eagle.logicalGraph().findNodeByKeyQuiet(edge.getDestNodeKey()); + connectedField=true + adjacentNodes.push(adjacentNode); + continue; + } + } + break; + } + + //for branch nodes the ports are inset from the outer radius a little bit in their design + let nodeRadius = node.getRadius() + if(portOnEmbeddedApp){ + // if we are working with ports of an embedded app, we need to use the parent construct to calculate the angle, but we want to use the radius of the embedded app to place the port + nodeRadius = eagle.logicalGraph().findNodeByKeyQuiet(field.getNodeKey()).getRadius() + } + + // determine port position + const currentNodePos = node.getPosition(); + let portPosition; + + if(connectedField || dataType === 'comment'){ + + // calculate angles to all adjacent nodes + const angles: number[] = []; + for (const adjacentNode of adjacentNodes){ + const adjacentNodePos = adjacentNode.getPosition() + const edgeAngle = GraphRenderer.calculateConnectionAngle(currentNodePos, adjacentNodePos) + angles.push(edgeAngle); + } + + // average the angles + const averageAngle = GraphRenderer.averageAngles(angles); + + node.addPortAngle(averageAngle); + portPosition = GraphRenderer.calculatePortPos(averageAngle, nodeRadius, nodeRadius) + }else{ + // find a default position for the port when not connected + switch (dataType){ + case 'inputApp': + case 'inputPort': + portPosition=GraphRenderer.calculatePortPos(Math.PI, nodeRadius, nodeRadius) + break; + case 'outputApp': + case 'outputPort': + portPosition=GraphRenderer.calculatePortPos(0, nodeRadius, nodeRadius) + break; + default: + console.warn("disconnected field with dataType:", dataType); + portPosition=GraphRenderer.calculatePortPos(Math.PI/2, nodeRadius, nodeRadius) + break; + } + } + + //a little 1px reduction is needed to center ports for some reason + if(!node.isBranch()){ + portPosition = {x:portPosition.x-1,y:portPosition.y-1} + } + + if (dataType === 'inputPort'){ + field.setPortPosition(portPosition.x, portPosition.y); + } else if (dataType === 'outputPort'){ + field.setPortPosition(portPosition.x, portPosition.y); + } + + let x + let y + + if (dataType === 'inputApp' || dataType === 'outputApp'){ + //we are saving the embedded application's position data here using the offset we calculated + const newPos = {x: node.getPosition().x-nodeRadius+portPosition.x, y:node.getPosition().y-nodeRadius+portPosition.y} + node.setPosition(newPos.x,newPos.y) + portPosition = {x:portPosition.x-nodeRadius,y:portPosition.y-nodeRadius} + x = portPosition.x + y = portPosition.y + }else{ + + x = portPosition.x + currentNodePos.x + eagle.globalOffsetX() - nodeRadius + y = portPosition.y + currentNodePos.y + eagle.globalOffsetY() - nodeRadius + } + + //applying the offset to the element + // $(element).css({'top':y+'px','left':x+'px'}) + } static averageAngles(angles: number[]) : number { let x: number = 0; @@ -359,12 +481,12 @@ export class GraphRenderer { let srcPortOffset; let destPortOffset; if (srcField){ - srcPortOffset = srcField.getOutputPosition(); + srcPortOffset = srcField.getPortPosition(); } else { srcPortOffset = GraphRenderer.calculatePortPos(srcPortAngle, srcNodeRadius, srcNodeRadius); } if (destField){ - destPortOffset = destField.getInputPosition(); + destPortOffset = destField.getPortPosition(); } else { destPortOffset = GraphRenderer.calculatePortPos(destPortAngle, destNodeRadius, destNodeRadius); }