Explorar o código

refactored frame ports into child class of NodePort called FrameNodePort

Kyle Belfort %!s(int64=5) %!d(string=hai) anos
pai
achega
3c755ca83d

+ 11 - 11
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -16,7 +16,7 @@ import { GraphFrame } from '../../diagram/graphFrame';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { Engine } from 'babylonjs/Engines/engine';
 import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
-import { NodePortPropertyTabComponent } from '../../diagram/properties/nodePortPropertyComponent';
+import { FrameNodePortPropertyTabComponent } from '../../diagram/properties/frameNodePortPropertyComponent';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
 import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
@@ -26,32 +26,32 @@ import { Vector2LineComponent } from '../../sharedComponents/vector2LineComponen
 import { Vector3LineComponent } from '../../sharedComponents/vector3LineComponent';
 import { Vector4LineComponent } from '../../sharedComponents/vector4LineComponent';
 import { Observer } from 'babylonjs/Misc/observable';
-import { NodePort } from '../../diagram/nodePort';
+import { FrameNodePort } from '../../diagram/frameNodePort';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
     globalState: GlobalState;
 }
 
-export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame>, currentNodePort: Nullable<NodePort> }> {
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame>, currentFrameNodePort: Nullable<FrameNodePort> }> {
     private _onBuiltObserver: Nullable<Observer<void>>;
 
     constructor(props: IPropertyTabComponentProps) {
         super(props)
 
-        this.state = { currentNode: null, currentFrame: null, currentNodePort: null };
+        this.state = { currentNode: null, currentFrame: null, currentFrameNodePort: null };
     }
 
     componentDidMount() {
         this.props.globalState.onSelectionChangedObservable.add(selection => {
             if (selection instanceof GraphNode) {
-                this.setState({ currentNode: selection, currentFrame: null, currentNodePort: null });
+                this.setState({ currentNode: selection, currentFrame: null, currentFrameNodePort: null });
             } else if (selection instanceof GraphFrame) {
-                this.setState({ currentNode: null, currentFrame: selection, currentNodePort: null });
-            } else if(selection instanceof NodePort) {
-                this.setState({ currentNode: null, currentFrame: null, currentNodePort: selection });
+                this.setState({ currentNode: null, currentFrame: selection, currentFrameNodePort: null });
+            } else if(selection instanceof FrameNodePort) {
+                this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: selection });
             } else {
-                this.setState({ currentNode: null, currentFrame: null, currentNodePort: null });
+                this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: null });
             }
         });
 
@@ -175,9 +175,9 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             );
         }
 
-        if (this.state.currentNodePort) {
+        if (this.state.currentFrameNodePort) {
             return (
-                <NodePortPropertyTabComponent globalState={this.props.globalState} nodePort={this.state.currentNodePort}/>
+                <FrameNodePortPropertyTabComponent globalState={this.props.globalState} frameNodePort={this.state.currentFrameNodePort}/>
             );
         }
 

+ 119 - 0
nodeEditor/src/diagram/frameNodePort.ts

@@ -0,0 +1,119 @@
+import { NodePort } from "./nodePort";
+import { Nullable, Observable, NodeMaterialConnectionPoint } from 'babylonjs';
+import { GraphNode } from './graphNode';
+import { FramePortPosition } from './graphFrame';
+import { GlobalState } from '../globalState';
+import { IDisplayManager } from './display/displayManager';
+
+export class FrameNodePort extends NodePort {
+    private _onFramePortMoveUpObservable = new Observable<FrameNodePort>();
+    private _onFramePortMoveDownObservable = new Observable<FrameNodePort>();
+    private _onFramePortPositionChangedObservable = new Observable<FramePortPosition>();
+    private _portLabel: Element;
+    private _isInput: boolean;
+    private _framePortPosition: FramePortPosition
+    private _framePortId: Nullable<number>;
+
+    public get onFramePortMoveUpObservable() {
+        return this._onFramePortMoveUpObservable;
+    }
+
+    public get onFramePortMoveDownObservable() {
+        return this._onFramePortMoveDownObservable;
+    }
+
+    public get onFramePortPositionChangedObservable() {
+        return this._onFramePortPositionChangedObservable;
+    }
+
+    public get isInput() {
+        return this._isInput;
+    }
+
+    public get portLabel() {
+        return this._portLabel.innerHTML;
+    }
+
+    public get framePortId() {
+        return this._framePortId;
+    }
+
+    public set portLabel(newLabel: string) {
+        this._portLabel.innerHTML = newLabel;
+    }
+
+    public get framePortPosition() {
+        return this._framePortPosition;
+    }
+
+    public set framePortPosition(position: FramePortPosition) {
+        this._framePortPosition = position;
+        this.onFramePortPositionChangedObservable.notifyObservers(position);
+    }
+
+    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState, isInput: boolean, framePortId: number) {
+        super(portContainer, connectionPoint,node, globalState);
+        this._element = portContainer.ownerDocument!.createElement("div");
+        this._element.classList.add("port");
+        portContainer.appendChild(this._element);
+        this._globalState = globalState;
+
+        this._portLabel = portContainer.children[0];
+        this._isInput = isInput;
+        this._framePortId = framePortId;
+
+
+        this._img = portContainer.ownerDocument!.createElement("img");
+        this._element.appendChild(this._img );
+
+        (this._element as any).port = this;
+
+        // Drag support
+        this._element.ondragstart= () => false;
+
+        this._onCandidateLinkMovedObserver = globalState.onCandidateLinkMoved.add(coords => {
+            const rect = this._element.getBoundingClientRect();
+
+            if (!coords || rect.left > coords.x || rect.right < coords.x || rect.top > coords.y || rect.bottom < coords.y) {
+                this._element.classList.remove("selected"); 
+                return;
+            }
+
+            this._element.classList.add("selected"); 
+            this._globalState.onCandidatePortSelectedObservable.notifyObservers(this);
+        });
+
+        this._onSelectionChangedObserver = this._globalState.onSelectionChangedObservable.add((selection) => {
+            if (selection === this) {
+                this._img.classList.add("selected");
+            } else {
+                this._img.classList.remove("selected");
+            }
+        });
+
+        this.refresh();
+    }
+
+    public static CreateFrameNodePortElement(connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, 
+        displayManager: Nullable<IDisplayManager>, globalState: GlobalState, isInput: boolean, framePortId: number) {
+        let portContainer = root.ownerDocument!.createElement("div");
+        let block = connectionPoint.ownerBlock;
+
+        portContainer.classList.add("portLine");
+        if(framePortId !== null) {
+            portContainer.dataset.framePortId = `${framePortId}`;
+        }
+        root.appendChild(portContainer);
+
+        if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
+            let portLabel = root.ownerDocument!.createElement("div");
+            portLabel.classList.add("port-label");
+            portLabel.innerHTML = connectionPoint.name;        
+            portContainer.appendChild(portLabel);
+        }
+
+        return new FrameNodePort(portContainer, connectionPoint, node, globalState, isInput, framePortId);
+    }
+
+} 
+

+ 4 - 3
nodeEditor/src/diagram/graphCanvas.tsx

@@ -14,6 +14,7 @@ import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { DataStorage } from 'babylonjs/Misc/dataStorage';
 import { GraphFrame } from './graphFrame';
 import { IEditorData } from '../nodeLocationInfo';
+import { FrameNodePort } from './frameNodePort';
 
 require("./graphCanvas.scss");
 
@@ -47,7 +48,7 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
     private _selectedLink: Nullable<NodeLink> = null;
     private _selectedPort: Nullable<NodePort> = null;
     private _candidateLink: Nullable<NodeLink> = null;
-    private _candidatePort: Nullable<NodePort> = null;
+    private _candidatePort: Nullable<NodePort | FrameNodePort> = null;
     private _gridSize = 20;
     private _selectionBox: Nullable<HTMLDivElement> = null;   
     private _selectedFrame: Nullable<GraphFrame> = null;   
@@ -195,7 +196,7 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
             }
         });
 
-        props.globalState.onCandidatePortSelected.add(port => {
+        props.globalState.onCandidatePortSelectedObservable.add(port => {
             this._candidatePort = port;
         });
 
@@ -598,7 +599,7 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
                 this.processCandidatePort();          
                 this.props.globalState.onCandidateLinkMoved.notifyObservers(null);
             } else { // is a click event on NodePort
-                if(this._candidateLink.portA.frameId !== null) { //only on Frame Ports
+                if(this._candidateLink.portA instanceof FrameNodePort) { //only on Frame Ports
                     this.props.globalState.onSelectionChangedObservable.notifyObservers(this._candidateLink.portA);
                 }
             }

+ 34 - 30
nodeEditor/src/diagram/graphFrame.ts

@@ -8,6 +8,7 @@ import { Color3 } from 'babylonjs/Maths/math.color';
 import { NodePort } from './nodePort';
 import { SerializationTools } from '../serializationTools';
 import { StringTools } from '../stringTools';
+import { FrameNodePort } from './frameNodePort';
 
 enum ResizingDirection {
         Right,
@@ -51,9 +52,10 @@ export class GraphFrame {
     private _mouseStartPointX: Nullable<number> = null;
     private _mouseStartPointY: Nullable<number> = null;
     private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>>;
+    private _onGraphNodeRemovalObserver: Nullable<Observer<GraphNode>>; 
     private _isCollapsed = false;
-    private _frameInPorts: NodePort[] = [];
-    private _frameOutPorts: NodePort[] = [];
+    private _frameInPorts: FrameNodePort[] = [];
+    private _frameOutPorts: FrameNodePort[] = [];
     private _controlledPorts: NodePort[] = []; // Ports on Nodes that are shown on outside of frame
     private _id: number;
     private _comments: string;
@@ -78,21 +80,17 @@ export class GraphFrame {
     }
 
     private _createInputPort(port: NodePort, node: GraphNode) {
-        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._inputPortContainer, null, this._ownerCanvas.globalState, true, this.id, GraphFrame._FramePortCounter++)
+        let localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, node, this._inputPortContainer, null, this._ownerCanvas.globalState, true, GraphFrame._FramePortCounter++)
         this._frameInPorts.push(localPort);
 
         port.delegatedPort = localPort;
         this._controlledPorts.push(port);
-        localPort.onFramePortMoveUpObservable.add((nodePort: NodePort) => {
-            if(this.id === nodePort.frameId) {
+        localPort.onFramePortMoveUpObservable.add((nodePort: FrameNodePort) => {
                 this.moveFramePortUp(nodePort);
-            }
         });
 
-        localPort.onFramePortMoveDownObservable.add((nodePort: NodePort) => {
-            if(this.id === nodePort.frameId) {
+        localPort.onFramePortMoveDownObservable.add((nodePort: FrameNodePort) => {
                 this.moveFramePortDown(nodePort);
-            }
         })
     }
 
@@ -118,23 +116,19 @@ export class GraphFrame {
 
                         for (var link of node.links) {
                             if (link.portA === port && this.nodes.indexOf(link.nodeB!) === -1) {
-                                let localPort: NodePort;
+                                let localPort: FrameNodePort;
 
                                 if (!portAdded) {
                                     portAdded = true;
-                                    localPort = NodePort.CreatePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, this.id, GraphFrame._FramePortCounter++);
+                                    localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++);
                                     this._frameOutPorts.push(localPort);
 
-                                    localPort.onFramePortMoveUpObservable.add((nodePort: NodePort) => {
-                                        if(this.id === nodePort.frameId) {
+                                    localPort.onFramePortMoveUpObservable.add((nodePort: FrameNodePort) => {
                                             this.moveFramePortUp(nodePort);
-                                        }
                                     });
                             
-                                    localPort.onFramePortMoveDownObservable.add((nodePort: NodePort) => {
-                                        if(this.id === nodePort.frameId) {
+                                    localPort.onFramePortMoveDownObservable.add((nodePort: FrameNodePort) => {
                                             this.moveFramePortDown(nodePort);
-                                        }
                                     })
                                 } else {
                                     localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
@@ -146,21 +140,17 @@ export class GraphFrame {
                             }
                         }
                     } else {
-                        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, this.id, GraphFrame._FramePortCounter++)
+                        let localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++)
                         this._frameOutPorts.push(localPort);
                         port.delegatedPort = localPort;
                         this._controlledPorts.push(port);
 
-                        localPort.onFramePortMoveUpObservable.add((nodePort: NodePort) => {
-                            if(this.id === nodePort.frameId) {
+                        localPort.onFramePortMoveUpObservable.add((nodePort: FrameNodePort) => {
                                 this.moveFramePortUp(nodePort);
-                            }
                         });
                 
-                        localPort.onFramePortMoveDownObservable.add((nodePort: NodePort) => {
-                            if(this.id === nodePort.frameId) {
+                        localPort.onFramePortMoveDownObservable.add((nodePort: FrameNodePort) => {
                                 this.moveFramePortDown(nodePort);
-                            }
                         });
                     }
                 }
@@ -493,7 +483,17 @@ export class GraphFrame {
             } else {
                 this.element.classList.remove("selected");
             }
-        }); 
+        });
+
+        this._onGraphNodeRemovalObserver = canvas.globalState.onGraphNodeRemovalObservable.add((node: GraphNode) => {
+            // remove node from this._nodes
+            const index = this._nodes.indexOf(node);
+            if (index === -1) {
+                return;
+            } else {
+                this._nodes.splice(index, 1);
+            }
+        });
 
         this._commentsElement = document.createElement('div');
         this._commentsElement.className = 'frame-comments';
@@ -510,7 +510,7 @@ export class GraphFrame {
 
     public refresh() {
         this._nodes = [];
-        this._ownerCanvas.globalState.onFrameCreated.notifyObservers(this);
+        this._ownerCanvas.globalState.onFrameCreatedObservable.notifyObservers(this);
     }
 
     public addNode(node: GraphNode) {
@@ -617,7 +617,7 @@ export class GraphFrame {
         evt.stopPropagation();
     }
 
-    private moveFramePortUp(nodePort: NodePort){
+    private moveFramePortUp(nodePort: FrameNodePort){
         if(nodePort.isInput) {
             if(this._inputPortContainer.children.length < 2) {
                 return;
@@ -634,7 +634,7 @@ export class GraphFrame {
 
     }
 
-    private _movePortUp(elementsArray: ChildNode[], nodePort: NodePort) {
+    private _movePortUp(elementsArray: ChildNode[], nodePort: FrameNodePort) {
         // update UI
         const indexInElementArray = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
         if(indexInElementArray === 0){
@@ -656,7 +656,7 @@ export class GraphFrame {
         }
     }
     
-    private moveFramePortDown(nodePort: NodePort){
+    private moveFramePortDown(nodePort: FrameNodePort){
         if(nodePort.isInput) {
             if(this._inputPortContainer.children.length < 2) {
                 return;
@@ -672,7 +672,7 @@ export class GraphFrame {
         }
     }
 
-    private _movePortDown(elementsArray: ChildNode[], nodePort: NodePort) {
+    private _movePortDown(elementsArray: ChildNode[], nodePort: FrameNodePort) {
         // update UI
         const indexInElementArray = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
         if(indexInElementArray === elementsArray.length -1){
@@ -1197,6 +1197,10 @@ export class GraphFrame {
             this._ownerCanvas.globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
         }
 
+        if(this._onGraphNodeRemovalObserver) {
+            this._ownerCanvas.globalState.onGraphNodeRemovalObservable.remove(this._onGraphNodeRemovalObserver);
+        }
+
         this.element.parentElement!.removeChild(this.element);
 
         this._ownerCanvas.frames.splice(this._ownerCanvas.frames.indexOf(this), 1);

+ 8 - 5
nodeEditor/src/diagram/graphNode.ts

@@ -33,7 +33,7 @@ export class GraphNode {
     private _globalState: GlobalState;
     private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>>;   
     private _onSelectionBoxMovedObserver: Nullable<Observer<ClientRect | DOMRect>>;  
-    private _onFrameCreatedObserver: Nullable<Observer<GraphFrame>>;  
+    private _onFrameCreatedObserver: Nullable<Observer<GraphFrame>>; 
     private _onUpdateRequiredObserver: Nullable<Observer<void>>;  
     private _ownerCanvas: GraphCanvasComponent; 
     private _isSelected: boolean;
@@ -183,7 +183,7 @@ export class GraphNode {
             this.isSelected = overlap;
         });
 
-        this._onFrameCreatedObserver = this._globalState.onFrameCreated.add(frame => {      
+        this._onFrameCreatedObserver = this._globalState.onFrameCreatedObservable.add(frame => {      
             if (this._ownerCanvas.frames.some(f => f.nodes.indexOf(this) !== -1)) {
                 return;
             }
@@ -407,17 +407,20 @@ export class GraphNode {
 
         // Connections
         for (var input of this.block.inputs) {
-            this._inputPorts.push(NodePort.CreatePortElement(input,  this, this._inputsContainer, this._displayManager, this._globalState, true, null, undefined));
+            this._inputPorts.push(NodePort.CreatePortElement(input,  this, this._inputsContainer, this._displayManager, this._globalState));
         }
 
         for (var output of this.block.outputs) {
-            this._outputPorts.push(NodePort.CreatePortElement(output,  this, this._outputsContainer, this._displayManager, this._globalState, false, null, undefined));
+            this._outputPorts.push(NodePort.CreatePortElement(output,  this, this._outputsContainer, this._displayManager, this._globalState));
         }
 
         this.refresh();
     }
 
     public dispose() {
+        // notify frame observers that this node is being deleted
+        this._globalState.onGraphNodeRemovalObservable.notifyObservers(this);
+
         if (this._onSelectionChangedObserver) {
             this._globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
         }
@@ -435,7 +438,7 @@ export class GraphNode {
         }
 
         if (this._onFrameCreatedObserver) {
-            this._globalState.onFrameCreated.remove(this._onFrameCreatedObserver);
+            this._globalState.onFrameCreatedObservable.remove(this._onFrameCreatedObserver);
         }
 
         for (var port of this._inputPorts) {

+ 3 - 2
nodeEditor/src/diagram/nodeLink.ts

@@ -4,11 +4,12 @@ import { NodePort } from './nodePort';
 import { Nullable } from 'babylonjs/types';
 import { Observer, Observable } from 'babylonjs/Misc/observable';
 import { GraphFrame } from './graphFrame';
+import { FrameNodePort } from './frameNodePort';
 
 export class NodeLink {
     private _graphCanvas: GraphCanvasComponent;
-    private _portA: NodePort;
-    private _portB?: NodePort;
+    private _portA: NodePort | FrameNodePort;
+    private _portB?: NodePort | FrameNodePort;
     private _nodeA: GraphNode;
     private _nodeB?: GraphNode;
     private _path: SVGPathElement;

+ 14 - 79
nodeEditor/src/diagram/nodePort.ts

@@ -3,29 +3,22 @@ import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/
 import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
 import { GlobalState } from '../globalState';
 import { Nullable } from 'babylonjs/types';
-import { Observer, Observable } from 'babylonjs/Misc/observable';
+import { Observer } from 'babylonjs/Misc/observable';
 import { Vector2 } from 'babylonjs/Maths/math.vector';
 import { IDisplayManager } from './display/displayManager';
 import { GraphNode } from './graphNode';
 import { NodeLink } from './nodeLink';
-import { GraphFrame, FramePortPosition } from './graphFrame';
+import { GraphFrame } from './graphFrame';
+import { FrameNodePort } from './frameNodePort';
 
 export class NodePort {
-    private _onFramePortMoveUpObservable = new Observable<NodePort>();
-    private _onFramePortMoveDownObservable = new Observable<NodePort>();
-    private _onFramePortPositionChangedObservable = new Observable<FramePortPosition>();
-    private _element: HTMLDivElement;
-    private _img: HTMLImageElement;
-    private _globalState: GlobalState;
-    private _onCandidateLinkMovedObserver: Nullable<Observer<Nullable<Vector2>>>;
-    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>>;  
-    private _portLabel: Element;
-    private _frameId: Nullable<number>
-    private _isInput: boolean;
-    private _framePortPosition: FramePortPosition
-    private _framePortId: Nullable<number>;
+    protected _element: HTMLDivElement;
+    protected _img: HTMLImageElement;
+    protected _globalState: GlobalState;
+    protected _onCandidateLinkMovedObserver: Nullable<Observer<Nullable<Vector2>>>;
+    protected _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort | FrameNodePort>>>;  
     
-    public delegatedPort: Nullable<NodePort> = null;
+    public delegatedPort: Nullable<FrameNodePort> = null;
 
     public get element(): HTMLDivElement {
         if (this.delegatedPort) {
@@ -35,47 +28,6 @@ export class NodePort {
         return this._element;
     }
 
-    public get onFramePortMoveUpObservable() {
-        return this._onFramePortMoveUpObservable;
-    }
-
-    public get onFramePortMoveDownObservable() {
-        return this._onFramePortMoveDownObservable;
-    }
-
-    public get onFramePortPositionChangedObservable() {
-        return this._onFramePortPositionChangedObservable;
-    }
-
-    public get frameId() {
-        return this._frameId;
-    }
-
-    public get isInput() {
-        return this._isInput;
-    }
-
-    public get portLabel() {
-        return this._portLabel.innerHTML;
-    }
-
-    public get framePortId() {
-        return this._framePortId;
-    }
-
-    public set portLabel(newLabel: string) {
-        this._portLabel.innerHTML = newLabel;
-    }
-
-    public get framePortPosition() {
-        return this._framePortPosition;
-    }
-
-    public set framePortPosition(position: FramePortPosition) {
-        this._framePortPosition = position;
-        this.onFramePortPositionChangedObservable.notifyObservers(position);
-    }
-
     public refresh() {
         this._element.style.background = BlockTools.GetColorFromConnectionNodeType(this.connectionPoint.type);
         switch (this.connectionPoint.type) {
@@ -100,19 +52,12 @@ export class NodePort {
         }
     }
 
-    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState, isInput: boolean, frameId: Nullable<number>, framePortId: number | undefined) {
+    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState) {
         this._element = portContainer.ownerDocument!.createElement("div");
         this._element.classList.add("port");
         portContainer.appendChild(this._element);
         this._globalState = globalState;
 
-        this._portLabel = portContainer.children[0];
-        this._frameId = frameId
-        this._isInput = isInput;
-        if(framePortId !== undefined) {
-            this._framePortId = framePortId;
-        }
-
         this._img = portContainer.ownerDocument!.createElement("img");
         this._element.appendChild(this._img );
 
@@ -130,15 +75,7 @@ export class NodePort {
             }
 
             this._element.classList.add("selected"); 
-            this._globalState.onCandidatePortSelected.notifyObservers(this);
-        });
-
-        this._onSelectionChangedObserver = this._globalState.onSelectionChangedObservable.add((selection) => {
-            if (selection === this) {
-                this._img.classList.add("selected");
-            } else {
-                this._img.classList.remove("selected");
-            }
+            this._globalState.onCandidatePortSelectedObservable.notifyObservers(this);
         });
 
         this.refresh();
@@ -153,14 +90,12 @@ export class NodePort {
     }
 
     public static CreatePortElement(connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, 
-            displayManager: Nullable<IDisplayManager>, globalState: GlobalState, isInput: boolean,  frameId: Nullable<number> = null, framePortId: number | undefined) {
+            displayManager: Nullable<IDisplayManager>, globalState: GlobalState) {
         let portContainer = root.ownerDocument!.createElement("div");
         let block = connectionPoint.ownerBlock;
 
         portContainer.classList.add("portLine");
-        if(framePortId !== null) {
-            portContainer.dataset.framePortId = `${framePortId}`;
-        }
+
         root.appendChild(portContainer);
 
         if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
@@ -170,6 +105,6 @@ export class NodePort {
             portContainer.appendChild(portLabel);
         }
     
-        return new NodePort(portContainer, connectionPoint, node, globalState, isInput, frameId, framePortId);
+        return new NodePort(portContainer, connectionPoint, node, globalState);
     }
 }

+ 11 - 11
nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx

@@ -4,32 +4,32 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { GlobalState } from '../../globalState';
 import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
 import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
-import { NodePort } from '../nodePort';
 import { FramePortPosition } from '../graphFrame';
 import { Nullable } from 'babylonjs/types';
 import { Observer } from 'babylonjs/Misc/observable';
+import { FrameNodePort } from '../frameNodePort';
 
-export interface INodePortPropertyTabComponentProps {
+export interface IFrameNodePortPropertyTabComponentProps {
     globalState: GlobalState
-    nodePort: NodePort;
+    frameNodePort: FrameNodePort;
 }
 
-export class NodePortPropertyTabComponent extends React.Component<INodePortPropertyTabComponentProps, {framePortPosition: FramePortPosition}> {    
+export class FrameNodePortPropertyTabComponent extends React.Component<IFrameNodePortPropertyTabComponentProps, {framePortPosition: FramePortPosition}> {    
     private _onFramePortPositionChangedObserver: Nullable<Observer<FramePortPosition>>;
 
-    constructor(props: INodePortPropertyTabComponentProps) {
+    constructor(props: IFrameNodePortPropertyTabComponentProps) {
         super(props);
         this.state = {
-            framePortPosition: this.props.nodePort.framePortPosition
+            framePortPosition: this.props.frameNodePort.framePortPosition
         };
 
-        this._onFramePortPositionChangedObserver = this.props.nodePort.onFramePortPositionChangedObservable.add((position) => {
+        this._onFramePortPositionChangedObserver = this.props.frameNodePort.onFramePortPositionChangedObservable.add((position) => {
             this.setState({framePortPosition: position})
         });
     }
 
     componentWillUnmount() {
-        this.props.nodePort.onFramePortPositionChangedObservable.remove(this._onFramePortPositionChangedObserver)
+        this.props.frameNodePort.onFramePortPositionChangedObservable.remove(this._onFramePortPositionChangedObserver)
     }
 
     render() {      
@@ -43,13 +43,13 @@ export class NodePortPropertyTabComponent extends React.Component<INodePortPrope
             </div>
             <div>
                 <LineContainerComponent title="GENERAL">
-                    <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portLabel" target={this.props.nodePort}/>
+                    <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portLabel" target={this.props.frameNodePort}/>
                      {this.state.framePortPosition !== FramePortPosition.Top && <ButtonLineComponent label="Move Node Up" onClick={() => {
-                                this.props.nodePort.onFramePortMoveUpObservable.notifyObservers(this.props.nodePort);
+                                this.props.frameNodePort.onFramePortMoveUpObservable.notifyObservers(this.props.frameNodePort);
                             }} />}
 
                     {this.state.framePortPosition !== FramePortPosition.Bottom && <ButtonLineComponent label="Move Node Down" onClick={() => {
-                                this.props.nodePort.onFramePortMoveDownObservable.notifyObservers(this.props.nodePort);
+                                this.props.frameNodePort.onFramePortMoveDownObservable.notifyObservers(this.props.frameNodePort);
                             }} />}
                 </LineContainerComponent>
             </div>

+ 4 - 2
nodeEditor/src/globalState.ts

@@ -11,6 +11,7 @@ import { Vector2 } from 'babylonjs/Maths/math.vector';
 import { NodePort } from './diagram/nodePort';
 import { NodeLink } from './diagram/nodeLink';
 import { GraphFrame } from './diagram/graphFrame';
+import { FrameNodePort } from './diagram/frameNodePort';
 
 export class GlobalState {
     nodeMaterial: NodeMaterial;
@@ -35,8 +36,9 @@ export class GlobalState {
     onAnimationCommandActivated = new Observable<void>();
     onCandidateLinkMoved = new Observable<Nullable<Vector2>>();
     onSelectionBoxMoved = new Observable<ClientRect | DOMRect>();
-    onFrameCreated = new Observable<GraphFrame>();
-    onCandidatePortSelected = new Observable<Nullable<NodePort>>();
+    onFrameCreatedObservable = new Observable<GraphFrame>();
+    onCandidatePortSelectedObservable = new Observable<Nullable<NodePort | FrameNodePort>>();
+    onGraphNodeRemovalObservable = new Observable<GraphNode>();
     onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
     onGridSizeChanged = new Observable<void>();
     previewMeshType: PreviewMeshType;