110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
import { Element } from './Element';
|
|
import { Edge } from './Edge';
|
|
import { Node } from './Node';
|
|
import { GraphStyles, NodeStyles } from './Styles';
|
|
import { Color } from './Color';
|
|
import { GraphLayouts } from './GraphLayouts';
|
|
|
|
interface NodeOptions {
|
|
name: string;
|
|
label: string;
|
|
style: NodeStyles;
|
|
color: Color;
|
|
}
|
|
|
|
export class Graph extends Element {
|
|
public children: Array<Graph> = [];
|
|
public nodes: Array<Node> = [];
|
|
public is_root = false;
|
|
public edges: Array<Edge> = [];
|
|
public style?: GraphStyles;
|
|
public color?: Color;
|
|
public directional = true;
|
|
public overlap?: boolean | string;
|
|
public splines?: boolean | string;
|
|
public layout?: GraphLayouts;
|
|
|
|
private get attributes (): Array<{name: string; value: string}> {
|
|
const attributes = [];
|
|
|
|
if (typeof this.color !== 'undefined')
|
|
attributes.push ({ name: 'color', value: this.color.toString () });
|
|
if (typeof this.style !== 'undefined')
|
|
attributes.push ({ name: 'style', value: this.style.toString () });
|
|
if (typeof this.overlap !== 'undefined')
|
|
attributes.push ({ name: 'overlap', value: this.overlap.toString () });
|
|
if (typeof this.splines !== 'undefined')
|
|
attributes.push ({ name: 'splines', value: this.splines.toString () });
|
|
if (typeof this.layout !== 'undefined')
|
|
attributes.push ({ name: 'layout', value: this.layout.toString () });
|
|
|
|
return attributes;
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
public toString (): string {
|
|
const header = this.parent
|
|
? `subgraph cluster_${this.full_name}`
|
|
: `${this.directional ? 'di' : ''}graph ${this.full_name}`;
|
|
|
|
let attrs = `\n${this.attributes.map ((v) => `${v.name} = ${v.value}`)
|
|
.join ('\n')}\n`;
|
|
let children = `\n${this.children.map ((c) => c.toString ())
|
|
.join ('\n')}\n`;
|
|
let nodes = `\n${this.nodes.map ((c) => c.toString ())
|
|
.join ('\n')}\n`;
|
|
let edges = `\n${this.edges.map ((c) => c.toString ())
|
|
.join ('\n')}\n`;
|
|
|
|
if (attrs === '\n\n')
|
|
attrs = '';
|
|
if (children === '\n\n')
|
|
children = '';
|
|
if (nodes === '\n\n')
|
|
nodes = '';
|
|
if (edges === '\n\n')
|
|
edges = '';
|
|
|
|
const indented = `${attrs}${children}${nodes}${edges}`
|
|
.replace (/\n$/u, '')
|
|
.replace (/^/gmu, ' ')
|
|
.split ('\n')
|
|
.map ((v) => v.trimRight ())
|
|
.join ('\n');
|
|
|
|
return `${header} {${indented}\n}`
|
|
.replace (/^\s+$/gmu, '');
|
|
}
|
|
|
|
public add_node (constructor: ((n: Node) => void) | string): string {
|
|
const node = new Node ('unnamed', this.full_name);
|
|
|
|
if (typeof constructor === 'string') {
|
|
node.name = constructor;
|
|
node.label = constructor;
|
|
}
|
|
else { constructor (node); }
|
|
|
|
this.nodes.push (node);
|
|
return node.full_name;
|
|
}
|
|
|
|
public add_graph (constructor: ((g: Graph) => void) | string): string {
|
|
const graph = new Graph ('unnamed', this.full_name);
|
|
|
|
graph.directional = this.directional;
|
|
|
|
if (typeof constructor === 'string')
|
|
graph.name = constructor;
|
|
else
|
|
constructor (graph);
|
|
|
|
this.children.push (graph);
|
|
return graph.full_name;
|
|
}
|
|
|
|
public add_edge (origin: string, target: string): void {
|
|
this.edges.push (new Edge (origin, target, this.directional));
|
|
}
|
|
}
|