|
@@ -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,
|
|
@@ -20,6 +21,10 @@ enum ResizingDirection {
|
|
|
BottomLeft
|
|
|
}
|
|
|
|
|
|
+export enum FramePortPosition {
|
|
|
+ Top, Middle, Bottom
|
|
|
+};
|
|
|
+
|
|
|
export class GraphFrame {
|
|
|
private readonly CollapsedWidth = 200;
|
|
|
private static _FrameCounter = 0;
|
|
@@ -47,8 +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 _ports: NodePort[] = []; // Ports on Outside of Frame
|
|
|
+ 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;
|
|
@@ -73,11 +80,18 @@ 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++)
|
|
|
- this._ports.push(localPort);
|
|
|
+ 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: FrameNodePort) => {
|
|
|
+ this.moveFramePortUp(nodePort);
|
|
|
+ });
|
|
|
+
|
|
|
+ localPort.onFramePortMoveDownObservable.add((nodePort: FrameNodePort) => {
|
|
|
+ this.moveFramePortDown(nodePort);
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
public set isCollapsed(value: boolean) {
|
|
@@ -102,14 +116,22 @@ 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++);
|
|
|
- this._ports.push(localPort);
|
|
|
+ localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++);
|
|
|
+ this._frameOutPorts.push(localPort);
|
|
|
+
|
|
|
+ localPort.onFramePortMoveUpObservable.add((nodePort: FrameNodePort) => {
|
|
|
+ this.moveFramePortUp(nodePort);
|
|
|
+ });
|
|
|
+
|
|
|
+ localPort.onFramePortMoveDownObservable.add((nodePort: FrameNodePort) => {
|
|
|
+ this.moveFramePortDown(nodePort);
|
|
|
+ })
|
|
|
} else {
|
|
|
- localPort = this._ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
|
|
|
+ localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
|
|
|
}
|
|
|
|
|
|
port.delegatedPort = localPort;
|
|
@@ -118,10 +140,18 @@ export class GraphFrame {
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, this.id, GraphFrame._FramePortCounter++)
|
|
|
- this._ports.push(localPort);
|
|
|
+ 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: FrameNodePort) => {
|
|
|
+ this.moveFramePortUp(nodePort);
|
|
|
+ });
|
|
|
+
|
|
|
+ localPort.onFramePortMoveDownObservable.add((nodePort: FrameNodePort) => {
|
|
|
+ this.moveFramePortDown(nodePort);
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -138,12 +168,39 @@ export class GraphFrame {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ for(let i = 0; i < this._frameInPorts.length; i++) {
|
|
|
+ const port = this._frameInPorts[i];
|
|
|
+ if(i === 0){
|
|
|
+ port.framePortPosition = FramePortPosition.Top;
|
|
|
+ } else if(i === this._frameInPorts.length -1){
|
|
|
+ port.framePortPosition = FramePortPosition.Bottom;
|
|
|
+ } else {
|
|
|
+ port.framePortPosition = FramePortPosition.Middle;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for(let i = 0; i < this._frameOutPorts.length; i++) {
|
|
|
+ const port = this._frameInPorts[i];
|
|
|
+ if(i === 0){
|
|
|
+ port.framePortPosition = FramePortPosition.Top
|
|
|
+ } else if(i === this._frameInPorts.length -1){
|
|
|
+ port.framePortPosition = FramePortPosition.Bottom
|
|
|
+ } else {
|
|
|
+ port.framePortPosition = FramePortPosition.Middle
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
} else {
|
|
|
this.element.classList.remove("collapsed");
|
|
|
this._outputPortContainer.innerHTML = "";
|
|
|
this._inputPortContainer.innerHTML = "";
|
|
|
|
|
|
- this._ports.forEach(p => {
|
|
|
+ this._frameInPorts.forEach(p => {
|
|
|
+ p.dispose();
|
|
|
+ });
|
|
|
+
|
|
|
+ this._frameOutPorts.forEach(p => {
|
|
|
p.dispose();
|
|
|
});
|
|
|
|
|
@@ -152,7 +209,8 @@ export class GraphFrame {
|
|
|
port.refresh();
|
|
|
})
|
|
|
|
|
|
- this._ports = [];
|
|
|
+ this._frameInPorts = [];
|
|
|
+ this._frameOutPorts = [];
|
|
|
this._controlledPorts = [];
|
|
|
|
|
|
for (var node of this._nodes) {
|
|
@@ -182,7 +240,7 @@ export class GraphFrame {
|
|
|
}
|
|
|
|
|
|
public get ports(){
|
|
|
- return this._ports;
|
|
|
+ return this._frameInPorts.concat(this._frameOutPorts);
|
|
|
}
|
|
|
|
|
|
public get name() {
|
|
@@ -425,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';
|
|
@@ -442,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) {
|
|
@@ -549,57 +617,82 @@ export class GraphFrame {
|
|
|
evt.stopPropagation();
|
|
|
}
|
|
|
|
|
|
- public moveFramePortUp(nodePort: NodePort){
|
|
|
+ private moveFramePortUp(nodePort: FrameNodePort){
|
|
|
if(nodePort.isInput) {
|
|
|
if(this._inputPortContainer.children.length < 2) {
|
|
|
return;
|
|
|
}
|
|
|
const elementsArray = Array.from(this._inputPortContainer.childNodes);
|
|
|
- this._moveFramePortUp(elementsArray, nodePort);
|
|
|
+ this._movePortUp(elementsArray, nodePort);
|
|
|
} else {
|
|
|
if(this._outputPortContainer.children.length < 2) {
|
|
|
return;
|
|
|
}
|
|
|
const elementsArray = Array.from(this._outputPortContainer.childNodes);
|
|
|
- this._moveFramePortUp(elementsArray, nodePort);
|
|
|
+ this._movePortUp(elementsArray, nodePort);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- private _moveFramePortUp(elementsArray: ChildNode[], nodePort: NodePort) {
|
|
|
- const indexInContainer = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
|
|
|
- if(indexInContainer === 0){
|
|
|
+ private _movePortUp(elementsArray: ChildNode[], nodePort: FrameNodePort) {
|
|
|
+ // update UI
|
|
|
+ const indexInElementArray = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
|
|
|
+ if(indexInElementArray === 0){
|
|
|
return;
|
|
|
}
|
|
|
- const secondPort = elementsArray[indexInContainer];
|
|
|
- const firstPort = elementsArray[indexInContainer -1];
|
|
|
- firstPort.parentElement?.insertBefore(secondPort, firstPort);
|
|
|
+ const secondPortElement = elementsArray[indexInElementArray];
|
|
|
+ const firstPortElement = elementsArray[indexInElementArray -1];
|
|
|
+ firstPortElement.parentElement?.insertBefore(secondPortElement, firstPortElement);
|
|
|
+
|
|
|
+ // update Frame Port Container
|
|
|
+ const indexInContainer = this._frameInPorts.findIndex(framePort => framePort === nodePort);
|
|
|
+ [this._frameInPorts[indexInContainer -1], this._frameInPorts[indexInContainer]] = [this._frameInPorts[indexInContainer], this._frameInPorts[indexInContainer -1]]; // swap idicies
|
|
|
+
|
|
|
+ // notify nodePort if it is now at Top (indexInElementArray === 1)
|
|
|
+ if (indexInElementArray === 1) {
|
|
|
+ nodePort.onFramePortPositionChangedObservable.notifyObservers(FramePortPosition.Top);
|
|
|
+ } else {
|
|
|
+ nodePort.onFramePortPositionChangedObservable.notifyObservers(FramePortPosition.Middle);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public moveFramePortDown(nodePort: NodePort){
|
|
|
+ private moveFramePortDown(nodePort: FrameNodePort){
|
|
|
if(nodePort.isInput) {
|
|
|
if(this._inputPortContainer.children.length < 2) {
|
|
|
return;
|
|
|
}
|
|
|
const elementsArray = Array.from(this._inputPortContainer.childNodes);
|
|
|
- this._moveFramePortDown(elementsArray, nodePort);
|
|
|
+ this._movePortDown(elementsArray, nodePort);
|
|
|
} else {
|
|
|
if(this._outputPortContainer.children.length < 2) {
|
|
|
return;
|
|
|
}
|
|
|
const elementsArray = Array.from(this._outputPortContainer.childNodes);
|
|
|
- this._moveFramePortDown(elementsArray, nodePort);
|
|
|
+ this._movePortDown(elementsArray, nodePort);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private _moveFramePortDown(elementsArray: ChildNode[], nodePort: NodePort) {
|
|
|
- const indexInContainer = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
|
|
|
- if(indexInContainer === elementsArray.length -1){
|
|
|
+ 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){
|
|
|
return;
|
|
|
}
|
|
|
- const firstPort = elementsArray[indexInContainer];
|
|
|
- const secondPort = elementsArray[indexInContainer + 1];
|
|
|
+ const firstPort = elementsArray[indexInElementArray];
|
|
|
+ const secondPort = elementsArray[indexInElementArray + 1];
|
|
|
firstPort.parentElement?.insertBefore(secondPort, firstPort);
|
|
|
+
|
|
|
+ // update Frame Port Container
|
|
|
+ const indexInContainer = this._frameInPorts.findIndex(framePort => framePort === nodePort);
|
|
|
+ [this._frameInPorts[indexInContainer], this._frameInPorts[indexInContainer + 1]] = [this._frameInPorts[indexInContainer + 1], this._frameInPorts[indexInContainer]]; // swap idicies
|
|
|
+
|
|
|
+ // notify nodePort if it is now at bottom (indexInContainer === elementsArray.length-2)
|
|
|
+ if(indexInContainer === elementsArray.length-2) {
|
|
|
+ nodePort.onFramePortPositionChangedObservable.notifyObservers(FramePortPosition.Bottom);
|
|
|
+ } else {
|
|
|
+ nodePort.onFramePortPositionChangedObservable.notifyObservers(FramePortPosition.Middle);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
private initResizing = (evt: PointerEvent) => {
|
|
@@ -1104,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);
|