use graphviz_rust::dot_generator::*;
use graphviz_rust::dot_structures::*;
use graphviz_rust::printer::{DotPrinter, PrinterContext};
use std::cmp::max;
use crate::export::{graph_colors::key_colors, graph_data::GraphData};
pub fn export_dot_with_headers(graph_data: &GraphData) -> String {
let mut statements = Vec::new();
for document in graph_data.documents.values() {
let font_size = max(12, 16 + document.depth * 8);
let colors = key_colors(&document.key);
let node = node!(
document.id.to_string();
attr!("label", "ed(&document.title)),
attr!("fillcolor", "ed(colors.node_background)),
attr!("fontsize", font_size),
attr!("fontname", "Verdana"),
attr!("color", "ed("#b3b3b3")),
attr!("penwidth", "1.5"),
attr!("shape", "note"),
attr!("style", "filled")
);
statements.push(Stmt::Node(node));
}
for section in graph_data.sections.values() {
let node = node!(
section.id.to_string();
attr!("label", "ed(§ion.title)),
attr!("fontsize", 14),
attr!("fontname", "Verdana"),
attr!("color", "ed("#b3b3b3")),
attr!("penwidth", "1.5"),
attr!("shape", "plain")
);
statements.push(Stmt::Node(node));
}
for (i, subgraph_doc) in graph_data.documents.values().enumerate() {
let colors = key_colors(&subgraph_doc.key);
let section_nodes: Vec<Stmt> = graph_data
.sections
.values()
.filter(|s| s.key == subgraph_doc.key)
.map(|s| Stmt::Node(node!(s.id.to_string())))
.collect();
if !section_nodes.is_empty() {
let subgraph_name = format!("cluster_{}", i);
let subgraph = subgraph!(
subgraph_name;
attr!("labeljust", "ed("l")),
attr!("style", "filled"),
attr!("color", "ed(colors.subgraph_fill)),
attr!("fillcolor", "ed(colors.subgraph_fill)),
attr!("fontcolor", "ed(colors.subgraph_text)),
attr!("penwidth", "40")
);
let mut subgraph_with_nodes = subgraph;
for node_stmt in section_nodes {
subgraph_with_nodes.add_stmt(node_stmt);
}
statements.push(Stmt::Subgraph(subgraph_with_nodes));
}
}
for (from_id, to_id) in &graph_data.section_to_document {
if graph_data.sections.contains_key(to_id) || graph_data.documents.contains_key(to_id) {
let edge = edge!(
node_id!(from_id.to_string()) => node_id!(to_id.to_string());
attr!("arrowsize", "1.5"),
attr!("arrowhead", "ed("empty")),
attr!("style", "ed("dashed")),
attr!("color", "ed("#38546c66")),
attr!("penwidth", "1.2")
);
statements.push(Stmt::Edge(edge));
}
}
for (from_id, to_id) in &graph_data.section_to_section {
if graph_data.sections.contains_key(to_id) || graph_data.documents.contains_key(to_id) {
let edge = edge!(
node_id!(from_id.to_string()) => node_id!(to_id.to_string());
attr!("color", "ed("#38546c66")),
attr!("arrowhead", "normal"),
attr!("penwidth", "1.2")
);
statements.push(Stmt::Edge(edge));
}
}
for (from_id, to_id) in &graph_data.document_to_document {
if graph_data.documents.contains_key(to_id) {
let edge = edge!(
node_id!(from_id.to_string()) => node_id!(to_id.to_string());
attr!("color", "ed("#38546c66")),
attr!("arrowhead", "normal"),
attr!("penwidth", "1.2")
);
statements.push(Stmt::Edge(edge));
}
}
let g = graph!(
di id!("G");
attr!("rankdir", "LR"),
attr!("fontname", "Verdana"),
attr!("fontsize", "13"),
attr!("nodesep", "0.7"),
attr!("splines", "polyline"),
attr!("pad", "ed("0.5,0.2")),
attr!("ranksep", "1.2"),
attr!("overlap", "false")
);
let mut final_graph = g;
for stmt in statements {
final_graph.add_stmt(stmt);
}
let output = final_graph.print(&mut PrinterContext::default());
format!("{}\n", output)
}
fn quoted(s: &str) -> String {
format!("\"{}\"", s.replace('"', "\\\""))
}