File

projects/atft/src/lib/actor/data-center/layout/dagre-edge.component.ts

Extends

LineConnectorComponent

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods
Inputs
Outputs
Accessors

Constructor

constructor(rendererService: RendererService, parent: AbstractObject3D<any>, animationService: AnimationService, injector: Injector)
Parameters :
Name Type Optional
rendererService RendererService No
parent AbstractObject3D<any> No
animationService AnimationService No
injector Injector No

Inputs

endType
Type : LineEndType
Default value : LineEndType.arrow
from
Type : string
startType
Type : LineEndType
Default value : LineEndType.circle
to
Type : string
type
Type : EdgeType
animated
Type : boolean
Default value : true
Inherited from LineConnectorComponent
dashSize
Type : number
Default value : 3
Inherited from LineConnectorComponent
gapSize
Type : number
Default value : 0.5
Inherited from LineConnectorComponent
lineType
Type : LineType
Default value : LineType.dashed
Inherited from LineConnectorComponent
lineWidth
Type : number
Default value : 2
Inherited from LineConnectorComponent
materialColor
Type : number
Default value : 0xFFFFFF
Inherited from LineConnectorComponent
opacity
Type : number
Default value : 1
Inherited from LineConnectorComponent
solid
Type : boolean
Default value : false
Inherited from LineConnectorComponent
source
Type : AbstractObject3D<THREE.Object3D>
Inherited from AbstractConnector
target
Type : AbstractObject3D<THREE.Object3D>
Inherited from AbstractConnector
layer
Type : number
Default value : 0
Inherited from AbstractObject3D
name
Type : string
Default value : uuidv4()
Inherited from AbstractObject3D
rotateX
Type : number
Inherited from AbstractObject3D

Rotation in Euler angles (radians) with order X, Y, Z.

rotateY
Type : number
Inherited from AbstractObject3D
rotateZ
Type : number
Inherited from AbstractObject3D
scaleX
Type : number
Default value : 1
Inherited from AbstractObject3D
scaleY
Type : number
Default value : 1
Inherited from AbstractObject3D
scaleZ
Type : number
Default value : 1
Inherited from AbstractObject3D
translateX
Type : number
Inherited from AbstractObject3D

Translate the geometry. This is typically done as a one time operation, and not during a loop.

translateY
Type : number
Inherited from AbstractObject3D
translateZ
Type : number
Inherited from AbstractObject3D

Outputs

changed
Type : EventEmitter
Inherited from AbstractObject3D

Methods

Protected addEdge
addEdge()
Returns : void
Protected appendLineEnds
appendLineEnds(lineObject: THREE.Object3D)
Parameters :
Name Type Optional
lineObject THREE.Object3D No
Returns : void
Protected getConnectorEndGeometry
getConnectorEndGeometry(type: LineEndType)
Parameters :
Name Type Optional
type LineEndType No
Returns : THREE.BufferGeometry | undefined
Protected getPositions
getPositions()
Inherited from LineConnectorComponent
Returns : number[]
Protected newObject3DInstance
newObject3DInstance()
Inherited from AbstractObject3D
Returns : THREE.Object3D
ngOnDestroy
ngOnDestroy()
Inherited from AbstractObject3D
Returns : void
ngOnInit
ngOnInit()
Inherited from AbstractObject3D
Returns : void
Protected removeEdge
removeEdge()
Returns : void
Protected syncGraph
syncGraph()
Returns : void
Protected syncGraphEdges
syncGraphEdges(g: dagre.graphlib.Graph)
Parameters :
Name Type Optional
g dagre.graphlib.Graph No
Returns : void
Private updateEnd
updateEnd(lineSide: THREE.Mesh, prevPoint: THREE.Vector3, endPoint: THREE.Vector3)
Parameters :
Name Type Optional
lineSide THREE.Mesh No
prevPoint THREE.Vector3 No
endPoint THREE.Vector3 No
Returns : void
Private updateEnds
updateEnds()
Returns : void
Private animate
animate()
Inherited from LineConnectorComponent
Returns : void
Public createLineMesh
createLineMesh()
Inherited from AbstractConnector
Returns : Line2
Public ngOnChanges
ngOnChanges(changes: SimpleChanges)
Inherited from AbstractObject3D
Parameters :
Name Type Optional
changes SimpleChanges No
Returns : void
updateLineGeometry
updateLineGeometry()
Inherited from AbstractConnector
Returns : void
Private watchObjects
watchObjects()
Inherited from AbstractConnector
Returns : void
Public addChild
addChild(object: AbstractObject3D<any>)
Inherited from AbstractObject3D
Parameters :
Name Type Optional
object AbstractObject3D<any> No
Returns : void
Protected afterInit
afterInit()
Inherited from AbstractObject3D
Returns : void
Public applyRotation
applyRotation()
Inherited from AbstractObject3D
Returns : void
Public applyScale
applyScale()
Inherited from AbstractObject3D
Returns : void
Public applyTranslation
applyTranslation()
Inherited from AbstractObject3D
Returns : void
Public findByName
findByName(name: string)
Inherited from AbstractObject3D
Parameters :
Name Type Optional
name string No
Returns : any
Public getChildren
getChildren()
Inherited from AbstractObject3D
Public getObject
getObject()
Inherited from AbstractObject3D
Returns : T
Public ngAfterViewInit
ngAfterViewInit()
Inherited from AbstractObject3D
Returns : void
Protected recursionByName
recursionByName(currentNode: AbstractObject3D<any>, name: string)
Inherited from AbstractObject3D
Parameters :
Name Type Optional
currentNode AbstractObject3D<any> No
name string No
Returns : any
Public removeChild
removeChild(object: AbstractObject3D<any>)
Inherited from AbstractObject3D
Parameters :
Name Type Optional
object AbstractObject3D<any> No
Returns : void
Public removeChildByName
removeChildByName(name: string)
Inherited from AbstractObject3D
Parameters :
Name Type Optional
name string No
Returns : void
Public updateParent
updateParent()
Inherited from AbstractObject3D
Returns : void

Properties

Protected dagreLayout
Type : DagreLayoutComponent
Protected graphUpdated
Type : Subscription
Protected lineEnd
Type : THREE.Mesh
Protected lineStart
Type : THREE.Mesh
Protected positions
Type : Array<number>
Protected animation
Type : Subscription
Inherited from LineConnectorComponent
Protected clock
Default value : new THREE.Clock()
Inherited from LineConnectorComponent
Protected line
Type : Line2
Inherited from LineConnectorComponent
Private matLine
Type : LineMaterial
Inherited from LineConnectorComponent
Protected time
Type : number
Default value : 0
Inherited from LineConnectorComponent
Protected timeScale
Type : number
Default value : 5
Inherited from LineConnectorComponent
Protected sourceSub
Type : Subscription
Inherited from AbstractConnector
Protected targetSub
Type : Subscription
Inherited from AbstractConnector
Protected childlren
Type : Array<AbstractObject3D<any>>
Default value : []
Inherited from AbstractObject3D
Protected object
Type : T
Inherited from AbstractObject3D

Accessors

type
settype(val: EdgeType)
Parameters :
Name Type Optional
val EdgeType No
Returns : void
import {Component, Injector, Input, OnDestroy, OnInit, Optional, SkipSelf} from '@angular/core';
import * as dagre from 'dagre';
import {Subscription} from 'rxjs';
import * as THREE from 'three';
import {AnimationService} from '../../../animation';
import {AbstractObject3D, LineConnectorComponent} from '../../../object';
import {RendererService} from '../../../renderer';
import {provideParent} from '../../../util';
import {DagreLayoutComponent} from './dagre-layout.component';

export enum LineEndType {
  none = 'none',
  circle = 'circle',
  arrow = 'arrow'
}

export enum EdgeType {
  sequence = 'sequence',
  association = 'association',
  message = 'message',
  line = 'line'
}

@Component({
  selector: 'atft-dagre-edge',
  providers: [provideParent(DagreEdgeComponent)],
  template: '<ng-content></ng-content>'
})
export class DagreEdgeComponent extends LineConnectorComponent implements OnInit, OnDestroy {

  @Input() from!: string;
  @Input() to!: string;
  @Input() startType: LineEndType = LineEndType.circle;
  @Input() endType: LineEndType = LineEndType.arrow;

  @Input()
  set type(val: EdgeType) {
    switch (val) {

      case EdgeType.association:
        this.animated = false;
        this.solid = false;
        this.startType = LineEndType.none;
        this.endType = LineEndType.arrow;
        break;

      case EdgeType.message:
        this.animated = true;
        this.solid = false;
        this.dashSize = 1;
        this.startType = LineEndType.circle;
        this.endType = LineEndType.arrow;
        break;

      case EdgeType.line:
        this.animated = false;
        this.solid = true;
        this.startType = LineEndType.none;
        this.endType = LineEndType.none;
        break;

      case EdgeType.sequence:
        this.animated = false;
        this.solid = true;
        this.startType = LineEndType.none;
        this.endType = LineEndType.arrow;
        break;

      default:
        this.animated = true;
        this.solid = false;
        this.dashSize = 4;
        this.startType = LineEndType.circle;
        this.endType = LineEndType.arrow;
    }
  }

  protected lineStart!: THREE.Mesh;
  protected lineEnd!: THREE.Mesh;
  protected positions!: Array<number>;
  protected dagreLayout: DagreLayoutComponent;
  protected graphUpdated: Subscription;

  constructor(
    protected override rendererService: RendererService,
    @SkipSelf() @Optional() protected override parent: AbstractObject3D<any>,
    protected override animationService: AnimationService,
    protected injector: Injector
  ) {
    super(rendererService, parent, animationService);
    this.dagreLayout = this.injector.get<DagreLayoutComponent>(DagreLayoutComponent);
    if (!this.dagreLayout) {
      console.warn('DagreEdgeComponent.constructor: atft-dagre-layout not found!');
    }
    this.syncGraph = this.syncGraph.bind(this);
    this.graphUpdated = this.dagreLayout.updated.subscribe(this.syncGraph);
  }

  protected override newObject3DInstance(): THREE.Object3D {
    const lineObject = super.newObject3DInstance();
    // console.log('DagreEdgeComponent.newObject3DInstance');
    this.appendLineEnds(lineObject);
    return lineObject;
  }

  protected appendLineEnds(lineObject: THREE.Object3D) {
    // 1. Init Material
    const material = new THREE.MeshBasicMaterial({
      color: this.materialColor,
      opacity: this.opacity,
      transparent: this.opacity < 1,
      depthWrite: true
    });

    // 2. Create start
    const startGeometry = this.getConnectorEndGeometry(this.startType);
    if (startGeometry) {
      this.lineStart = new THREE.Mesh(startGeometry, material);
      lineObject.add(this.lineStart);
    }

    // 3. Create end
    const endGeometry = this.getConnectorEndGeometry(this.endType);
    if (endGeometry) {
      this.lineEnd = new THREE.Mesh(endGeometry, material);
      lineObject.add(this.lineEnd);
    }
  }

  protected getConnectorEndGeometry(type: LineEndType): THREE.BufferGeometry | undefined {
    switch (type) {
      case LineEndType.circle:
        return new THREE.CircleGeometry(0.7, 16);
        break;
      case LineEndType.arrow:
        // eslint-disable-next-line no-case-declarations
        const shape = new THREE.Shape();
        shape.moveTo(0, -0.5);
        shape.lineTo(1, 2);
        shape.lineTo(0, 1.7);
        shape.lineTo(-1, 2);

        return new THREE.ShapeGeometry(shape);
        break;
      default:
        return undefined;
    }

  }


  override ngOnInit() {
    super.ngOnInit();
    this.addEdge();
  }


  protected addEdge() {
    if (this.dagreLayout && this.dagreLayout.getGraphModel()) {
      // console.log('DagreEdgeComponent.addEdge', this.name);

      // Register as layout children
      this.dagreLayout.getChildren().push(this);

      // Create Graph edge:
      if (this.from && this.to) {
        this.dagreLayout.getGraphModel().edges?.push({
          name: this.name,
          from: this.from,
          to: this.to
        });
      } else {
        console.warn('DagreEdgeComponent.addChild: edge source/target is undefined');
      }

      // Update Graph Layout
      this.dagreLayout.refreshLayout();
    }
  }

  override ngOnDestroy() {
    super.ngOnDestroy();
    this.removeEdge();
  }

  protected removeEdge() {
    if (this.dagreLayout && this.dagreLayout.getGraphModel()) {
      // console.log('DagreNodeComponent.removeNode', this.name);

      // Unsubscribe from graph update events
      this.graphUpdated?.unsubscribe();

      // Remove from layout
      this.dagreLayout.removeChildByName(this.name);

      // Remove from model
      this.dagreLayout.getGraphModel().edges = this.dagreLayout.getGraphModel().edges?.filter(i => i.name !== this.name);

      // Update Graph Layout
      this.dagreLayout.refreshLayout();
    }
  }

  protected syncGraph() {
    // console.log('DagreEdgeComponent.update');
    if (this.object) {
      this.syncGraphEdges(this.dagreLayout.getGraph());
    }
  }

  protected syncGraphEdges(g: dagre.graphlib.Graph) {
    // console.log('DagreEdgeComponent.syncGraphEdges');
    g.edges().forEach((e) => {
      const edge: dagre.GraphEdge = g.edge(e);
      // console.log('DagreEdgeComponent.syncGraphEdges: edge', edge);
      if (edge["name"] === this.name) {
        this.positions = [];
        // console.log('DagreEdgeComponent.syncGraphEdges: edge.points', edge.points);
        edge.points.forEach(p => {
          if (!Number.isNaN(p.x) && !Number.isNaN(p.y)) {
            // console.log('x=' + p.x + ', y=' + p.y);
            this.positions.push(p.x, p.y, 0.1);
          }
        });
        this.updateEnds();
        this.updateLineGeometry();
      }
    });
  }


  private updateEnds() {
    const p = this.positions;
    if (p?.length >= 9) {
      // Beginning / Start of the line
      this.updateEnd(this.lineStart,
        new THREE.Vector3(p[3], p[4], p[5]),
        new THREE.Vector3(p[0], p[1], p[2])
      );
      // Target / End of the line
      this.updateEnd(this.lineEnd,
        new THREE.Vector3(p[p.length - 6], p[p.length - 5], p[p.length - 4]),
        new THREE.Vector3(p[p.length - 3], p[p.length - 2], p[p.length - 1])
      );
    }

  }

  private updateEnd(lineSide: THREE.Mesh, prevPoint: THREE.Vector3, endPoint: THREE.Vector3) {
    if (lineSide) {
      const direction = prevPoint.clone().sub(endPoint);
      let angle = direction.angleTo(new THREE.Vector3(0, 1, 0));
      angle = prevPoint.x < endPoint.x ? angle : -angle;

      lineSide.rotation.set(0, 0, angle);
      lineSide.position.set(
        endPoint.x || 0,
        endPoint.y || 0,
        endPoint.z || 0
      );
    }
  }

  protected override getPositions(): number[] {
    if (this.positions) {
      return this.positions;
    } else {
      return [0, 0, 0, 0, 0, 0];
    }
  }

}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""