|
@@ -5,15 +5,15 @@ import { Nullable } from 'babylonjs/types';
|
|
import { Observer, Observable } from 'babylonjs/Misc/observable';
|
|
import { Observer, Observable } from 'babylonjs/Misc/observable';
|
|
import { GraphFrame } from './graphFrame';
|
|
import { GraphFrame } from './graphFrame';
|
|
|
|
|
|
-export class NodeLink {
|
|
|
|
|
|
+export class NodeLink {
|
|
private _graphCanvas: GraphCanvasComponent;
|
|
private _graphCanvas: GraphCanvasComponent;
|
|
private _portA: NodePort;
|
|
private _portA: NodePort;
|
|
- private _portB?: NodePort;
|
|
|
|
|
|
+ private _portB?: NodePort;
|
|
private _nodeA: GraphNode;
|
|
private _nodeA: GraphNode;
|
|
private _nodeB?: GraphNode;
|
|
private _nodeB?: GraphNode;
|
|
private _path: SVGPathElement;
|
|
private _path: SVGPathElement;
|
|
private _selectionPath: SVGPathElement;
|
|
private _selectionPath: SVGPathElement;
|
|
- private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame>>>;
|
|
|
|
|
|
+ private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame>>>;
|
|
private _isVisible = true;
|
|
private _isVisible = true;
|
|
|
|
|
|
public onDisposedObservable = new Observable<NodeLink>();
|
|
public onDisposedObservable = new Observable<NodeLink>();
|
|
@@ -52,29 +52,32 @@ export class NodeLink {
|
|
return this._nodeB;
|
|
return this._nodeB;
|
|
}
|
|
}
|
|
|
|
|
|
- public update(endX = 0, endY = 0, straight = false) {
|
|
|
|
|
|
+ public update(endX = 0, endY = 0, straight = false) {
|
|
const rectA = this._portA.element.getBoundingClientRect();
|
|
const rectA = this._portA.element.getBoundingClientRect();
|
|
const rootRect = this._graphCanvas.canvasContainer.getBoundingClientRect();
|
|
const rootRect = this._graphCanvas.canvasContainer.getBoundingClientRect();
|
|
const zoom = this._graphCanvas.zoom;
|
|
const zoom = this._graphCanvas.zoom;
|
|
const xOffset = rootRect.left;
|
|
const xOffset = rootRect.left;
|
|
const yOffset = rootRect.top;
|
|
const yOffset = rootRect.top;
|
|
-
|
|
|
|
|
|
+
|
|
var startX = (rectA.left - xOffset + 0.5 * rectA.width) / zoom;
|
|
var startX = (rectA.left - xOffset + 0.5 * rectA.width) / zoom;
|
|
- var startY = (rectA.top - yOffset + 0.5 * rectA.height) / zoom;
|
|
|
|
|
|
+ var startY = (rectA.top - yOffset + 0.5 * rectA.height) / zoom;
|
|
|
|
|
|
if (this._portB) {
|
|
if (this._portB) {
|
|
const rectB = this._portB.element.getBoundingClientRect();
|
|
const rectB = this._portB.element.getBoundingClientRect();
|
|
endX = (rectB.left - xOffset + 0.5 * rectB.width) / zoom;
|
|
endX = (rectB.left - xOffset + 0.5 * rectB.width) / zoom;
|
|
- endY = (rectB.top - yOffset + 0.5 * rectB.height) / zoom;
|
|
|
|
|
|
+ endY = (rectB.top - yOffset + 0.5 * rectB.height) / zoom;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
if (straight) {
|
|
if (straight) {
|
|
- this._path.setAttribute("d", `M${startX},${startY} L${endX},${endY}`);
|
|
|
|
|
|
+ this._path.setAttribute("d", `M${startX},${startY} L${endX},${endY}`);
|
|
this._path.setAttribute("stroke-dasharray", "10, 10");
|
|
this._path.setAttribute("stroke-dasharray", "10, 10");
|
|
this._path.setAttribute("stroke-linecap", "round");
|
|
this._path.setAttribute("stroke-linecap", "round");
|
|
} else {
|
|
} else {
|
|
- this._path.setAttribute("d", `M${startX},${startY} C${startX + 80},${startY} ${endX - 80},${endY} ${endX},${endY}`);
|
|
|
|
- this._selectionPath.setAttribute("d", `M${startX},${startY} C${startX + 80},${startY} ${endX - 80},${endY} ${endX},${endY}`);
|
|
|
|
|
|
+ const deltaX = endX - startX;
|
|
|
|
+ const deltaY = endY - startY;
|
|
|
|
+ const tangentLength = Math.min(Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 0.5, 300);
|
|
|
|
+ this._path.setAttribute("d", `M${startX},${startY} C${startX + tangentLength},${startY} ${endX - tangentLength},${endY} ${endX},${endY}`);
|
|
|
|
+ this._selectionPath.setAttribute("d", `M${startX},${startY} C${startX + tangentLength},${startY} ${endX - tangentLength},${endY} ${endX},${endY}`);
|
|
}
|
|
}
|
|
this._path.setAttribute("stroke", this._portA.element.style.backgroundColor!);
|
|
this._path.setAttribute("stroke", this._portA.element.style.backgroundColor!);
|
|
}
|
|
}
|
|
@@ -90,30 +93,30 @@ export class NodeLink {
|
|
var svg = graphCanvas.svgCanvas;
|
|
var svg = graphCanvas.svgCanvas;
|
|
|
|
|
|
// Create path
|
|
// Create path
|
|
- this._path = document.createElementNS('http://www.w3.org/2000/svg',"path");
|
|
|
|
|
|
+ this._path = document.createElementNS('http://www.w3.org/2000/svg', "path");
|
|
this._path.setAttribute("fill", "none");
|
|
this._path.setAttribute("fill", "none");
|
|
this._path.classList.add("link");
|
|
this._path.classList.add("link");
|
|
|
|
|
|
svg.appendChild(this._path);
|
|
svg.appendChild(this._path);
|
|
|
|
|
|
- this._selectionPath = document.createElementNS('http://www.w3.org/2000/svg',"path");
|
|
|
|
|
|
+ this._selectionPath = document.createElementNS('http://www.w3.org/2000/svg', "path");
|
|
this._selectionPath.setAttribute("fill", "none");
|
|
this._selectionPath.setAttribute("fill", "none");
|
|
this._selectionPath.classList.add("selection-link");
|
|
this._selectionPath.classList.add("selection-link");
|
|
|
|
|
|
svg.appendChild(this._selectionPath);
|
|
svg.appendChild(this._selectionPath);
|
|
|
|
|
|
- this._selectionPath.onmousedown = ()=> this.onClick();
|
|
|
|
|
|
+ this._selectionPath.onmousedown = () => this.onClick();
|
|
|
|
|
|
if (this._portB) {
|
|
if (this._portB) {
|
|
// Update
|
|
// Update
|
|
this.update();
|
|
this.update();
|
|
}
|
|
}
|
|
|
|
|
|
- this._onSelectionChangedObserver = this._graphCanvas.globalState.onSelectionChangedObservable.add(selection => {
|
|
|
|
- if (selection === this) {
|
|
|
|
|
|
+ this._onSelectionChangedObserver = this._graphCanvas.globalState.onSelectionChangedObservable.add((selection) => {
|
|
|
|
+ if (selection === this) {
|
|
this._path.classList.add("selected");
|
|
this._path.classList.add("selected");
|
|
this._selectionPath.classList.add("selected");
|
|
this._selectionPath.classList.add("selected");
|
|
- } else {
|
|
|
|
|
|
+ } else {
|
|
this._path.classList.remove("selected");
|
|
this._path.classList.remove("selected");
|
|
this._selectionPath.classList.remove("selected");
|
|
this._selectionPath.classList.remove("selected");
|
|
}
|
|
}
|
|
@@ -133,7 +136,7 @@ export class NodeLink {
|
|
|
|
|
|
if (this._selectionPath.parentElement) {
|
|
if (this._selectionPath.parentElement) {
|
|
this._selectionPath.parentElement.removeChild(this._selectionPath);
|
|
this._selectionPath.parentElement.removeChild(this._selectionPath);
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
if (this._nodeB) {
|
|
if (this._nodeB) {
|
|
this._nodeA.links.splice(this._nodeA.links.indexOf(this), 1);
|
|
this._nodeA.links.splice(this._nodeA.links.indexOf(this), 1);
|
|
@@ -144,5 +147,5 @@ export class NodeLink {
|
|
}
|
|
}
|
|
|
|
|
|
this.onDisposedObservable.notifyObservers(this);
|
|
this.onDisposedObservable.notifyObservers(this);
|
|
- }
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|