-
-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #339 from makimenko/dagra-layout
Dagre layout
- Loading branch information
Showing
22 changed files
with
687 additions
and
39 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './atft-data-center-actor.module'; | ||
export * from './layer'; | ||
export * from './server'; | ||
export * from './layout'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
projects/atft/src/lib/actor/data-center/layout/dagre-composition.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import {Component, EventEmitter, Input, Output} from '@angular/core'; | ||
import {provideParent} from '../../../util'; | ||
import {EmptyComponent} from '../../../object'; | ||
|
||
@Component({ | ||
selector: 'atft-dagre-composition', | ||
providers: [provideParent(DagreCompositionComponent)], | ||
template: ` | ||
<atft-plane-mesh atft-raycaster-group [width]="width" [height]="height" [materialColor]="color" (mouseEnter)="onSelected()" | ||
(mouseExit)="onDeselected()"> | ||
<atft-text-mesh [centered]="true" [text]="name" size="3" [translateY]="translateLabelY" | ||
materialColor="0xE0E0E0"> | ||
</atft-text-mesh> | ||
</atft-plane-mesh> | ||
` | ||
}) | ||
export class DagreCompositionComponent extends EmptyComponent { | ||
|
||
@Input() name: string; | ||
|
||
private _height: number; | ||
@Input() | ||
set height(hight: number) { | ||
this._height = hight; | ||
this.translateLabelY = this._height / 2 - 5; | ||
} | ||
|
||
get height(): number { | ||
return this._height; | ||
} | ||
|
||
@Input() width: number; | ||
|
||
|
||
|
||
@Output() render = new EventEmitter<void>(); | ||
@Output() selected = new EventEmitter<void>(); | ||
@Output() deselected = new EventEmitter<void>(); | ||
|
||
color = 0xA0A0A0; | ||
|
||
translateLabelY: number; | ||
|
||
public onSelected() { | ||
this.color = 0xA4A4A4; | ||
} | ||
|
||
public onDeselected() { | ||
this.color = 0xA0A0A0; | ||
} | ||
|
||
public onClick() { | ||
this.color = 0xA0A0A0; | ||
} | ||
|
||
} |
28 changes: 28 additions & 0 deletions
28
projects/atft/src/lib/actor/data-center/layout/dagre-edge.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import {Component} from '@angular/core'; | ||
import {MeshLineConnectorComponent} from '../../../object'; | ||
import {provideParent} from '../../../util'; | ||
import * as THREE from 'three'; | ||
|
||
@Component({ | ||
selector: 'atft-dagre-edge', | ||
providers: [provideParent(DagreEdgeComponent)], | ||
template: '<ng-content></ng-content>' | ||
}) | ||
export class DagreEdgeComponent extends MeshLineConnectorComponent { | ||
|
||
public positions: Array<number>; | ||
|
||
public animated = true; | ||
|
||
|
||
protected getLineGeometry(): THREE.BufferGeometry { | ||
if (!this.source || !this.target) { | ||
throw new Error('DagreCompositionComponent: source or target inputs are missing!'); | ||
} | ||
// console.log('DagreCompositionComponent.getLineGeometry', this.positions); | ||
const geometry = new THREE.BufferGeometry(); | ||
geometry.setAttribute('position', new THREE.Float32BufferAttribute(this.positions, 3)); | ||
return geometry; | ||
} | ||
|
||
} |
196 changes: 196 additions & 0 deletions
196
projects/atft/src/lib/actor/data-center/layout/dagre-layout.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
import {AfterViewInit, Component, Input, OnChanges, Optional, SimpleChanges, SkipSelf} from '@angular/core'; | ||
import {EmptyComponent} from '../../../object/helper'; | ||
import {provideParent} from '../../../util'; | ||
import {DagreUtils, GraphModel} from './dagre-utils'; | ||
import {RendererService} from '../../../renderer'; | ||
import {AbstractObject3D} from '../../../object'; | ||
import {DagreEdgeComponent} from './dagre-edge.component'; | ||
import * as dagre from 'dagre'; | ||
import {DagreNodeComponent} from './dagre-node.component'; | ||
import {DagreCompositionComponent} from './dagre-composition.component'; | ||
|
||
|
||
@Component({ | ||
selector: 'atft-dagre-layout', | ||
providers: [provideParent(DagreLayoutComponent)], | ||
template: ` | ||
` | ||
}) | ||
export class DagreLayoutComponent extends EmptyComponent implements AfterViewInit, OnChanges { | ||
|
||
@Input() align = 'DR'; | ||
@Input() rankdir = 'TB'; | ||
@Input() nodesep = 15; | ||
@Input() edgesep = 1; | ||
@Input() ranksep = 15; | ||
@Input() marginx = 0; | ||
@Input() marginy = 0; | ||
@Input() ranker = 'network-simplex'; | ||
|
||
|
||
protected graphModel: GraphModel; | ||
|
||
constructor( | ||
protected rendererService: RendererService, | ||
@SkipSelf() @Optional() protected parent: AbstractObject3D<any> | ||
) { | ||
super(rendererService, parent); | ||
|
||
// Initialize empty model: | ||
this.graphModel = { | ||
layout: {}, | ||
nodes: [], | ||
edges: [], | ||
composition: [] | ||
}; | ||
} | ||
|
||
public addChild(object: AbstractObject3D<any>): void { | ||
super.addChild(object); | ||
this.processDagreChild(object); | ||
} | ||
|
||
protected processDagreChild(object: AbstractObject3D<any>) { | ||
if (object instanceof DagreEdgeComponent) { | ||
this.addEdge(object); | ||
} else { | ||
this.addNode(object); | ||
} | ||
} | ||
|
||
protected addEdge(edge: DagreEdgeComponent) { | ||
// console.log('DagreLayoutComponent.addEdge', edge); | ||
const edgeObject: DagreEdgeComponent = edge; | ||
if (edgeObject.source && edgeObject.source.getObject() && edgeObject.target && edgeObject.target.getObject()) { | ||
this.graphModel.edges.push({ | ||
uuid: edgeObject.getObject().uuid, | ||
from: edgeObject.source.getObject().uuid, | ||
to: edgeObject.target.getObject().uuid | ||
}); | ||
} else { | ||
console.warn('DagreLayoutComponent.addChild: edge source/target is undefined'); | ||
} | ||
} | ||
|
||
|
||
protected addNode(object: AbstractObject3D<any>) { | ||
// console.log('DagreLayoutComponent.addNode', object); | ||
this.graphModel.nodes.push({ | ||
id: object.getObject().uuid, | ||
label: object.getObject().uuid, | ||
}); | ||
|
||
if (object instanceof DagreNodeComponent) { | ||
const node: DagreNodeComponent = object; | ||
if (node.composition) { | ||
// console.log('DagreLayoutComponent.addNode to composition', node.composition); | ||
this.graphModel.composition.push({ | ||
parent: node.composition.getObject().uuid, | ||
child: node.getObject().uuid | ||
}); | ||
} | ||
} | ||
|
||
} | ||
|
||
ngAfterViewInit() { | ||
super.ngAfterViewInit(); | ||
this.layout(); | ||
} | ||
|
||
public layout() { | ||
// console.log('DagreLayoutComponent.layout'); | ||
this.graphModel.layout = { | ||
align: this.align, | ||
rankdir: this.rankdir, | ||
nodesep: this.nodesep, | ||
edgesep: this.edgesep, | ||
ranksep: this.ranksep, | ||
marginx: this.marginx, | ||
marginy: this.marginy, | ||
ranker: this.ranker | ||
}; | ||
const g = DagreUtils.modelToGraph(this.graphModel); | ||
// console.log('DagreLayoutComponent.layout: g', g); | ||
this.syncGraphNodes(g); | ||
this.syncGraphEdges(g); | ||
this.rendererService.render(); | ||
} | ||
|
||
protected syncGraphNodes(g: dagre.graphlib.Graph) { | ||
// console.log('DagreLayoutComponent.syncGraphNodes'); | ||
g.nodes().forEach((uuid) => { | ||
// console.log('Node ' + uuid + ': ' + JSON.stringify(g.node(uuid))); | ||
const object: AbstractObject3D<any> = this.findByUuid(uuid); | ||
|
||
if (object) { | ||
const node = g.node(uuid); | ||
// console.log('DagreLayoutComponent.layout: Update position', node); | ||
|
||
object.translateX = node.x; | ||
object.translateY = node.y; | ||
object.applyTranslation(); | ||
|
||
if (object instanceof DagreCompositionComponent) { | ||
// console.log('DagreLayoutComponent.layout: Update composition', node); | ||
const composition: DagreCompositionComponent = object; | ||
composition.width = node.width; | ||
composition.height = node.height; | ||
|
||
} | ||
|
||
} else { | ||
console.warn('DagreLayoutComponent.layout: Object not found by uuid', uuid); | ||
} | ||
}); | ||
} | ||
|
||
protected syncGraphEdges(g: dagre.graphlib.Graph) { | ||
// console.log('DagreLayoutComponent.syncGraphEdges'); | ||
g.edges().forEach((e) => { | ||
const edge: dagre.GraphEdge = g.edge(e); | ||
// console.log('DagreLayoutComponent.syncGraphEdges: edge', edge); | ||
const object: AbstractObject3D<any> = this.findByUuid(edge.uuid); | ||
if (object && object instanceof DagreEdgeComponent) { | ||
const edgeComponent: DagreEdgeComponent = object; | ||
edgeComponent.positions = []; | ||
// console.log('DagreLayoutComponent.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); | ||
edgeComponent.positions.push(p.x, p.y, 0); | ||
} | ||
}); | ||
edgeComponent.updateLineGeometry(); | ||
} else { | ||
console.warn('DagreLayoutComponent.layout: Object not found by uuid', e.name); | ||
} | ||
}); | ||
} | ||
|
||
|
||
public ngOnChanges(changes: SimpleChanges) { | ||
// console.log('AbstractObject3D.ngOnChanges', this.uuid); | ||
if (!this.object) { | ||
return; | ||
} | ||
super.ngOnChanges(changes); | ||
|
||
let modified = false; | ||
|
||
if (['align', 'rankdir', 'ranksep', 'nodesep', 'edgesep', 'marginx', 'marginy', 'ranker'].some(propName => propName in changes)) { | ||
this.layout(); | ||
modified = true; | ||
} | ||
|
||
if (modified) { | ||
this.changed.emit(); | ||
// this.rendererService.render(); | ||
} | ||
|
||
} | ||
|
||
|
||
} |
Oops, something went wrong.