diff --git a/dag/v2/ui.go b/dag/v2/ui.go index 1f1374a..bd32cc5 100644 --- a/dag/v2/ui.go +++ b/dag/v2/ui.go @@ -143,39 +143,60 @@ func (tm *DAG) ExportDOT() string { var sb strings.Builder sb.WriteString(fmt.Sprintf(`digraph "%s" {`, tm.name)) sb.WriteString("\n") - sb.WriteString(fmt.Sprintf(` label="%s";`, tm.name)) + sb.WriteString(` label="Enhanced DAG Representation";`) sb.WriteString("\n") - sb.WriteString(` labelloc="t";`) + sb.WriteString(` labelloc="t"; fontsize=22; fontname="Helvetica";`) sb.WriteString("\n") - sb.WriteString(` fontsize=20;`) + sb.WriteString(` node [shape=box, fontname="Helvetica", fillcolor="#B3CDE0", fontcolor="#2C3E50", fontsize=10, margin="0.25,0.15", style="rounded,filled"];`) sb.WriteString("\n") - sb.WriteString(` node [shape=box, style="rounded,filled", fillcolor="lightgray", fontname="Arial", margin="0.2,0.1"];`) + sb.WriteString(` edge [fontname="Helvetica", fontsize=12, arrowsize=0.8];`) sb.WriteString("\n") - sb.WriteString(` edge [fontname="Arial", fontsize=12, arrowsize=0.8];`) - sb.WriteString("\n") - sb.WriteString(` size="10,10";`) - sb.WriteString("\n") - sb.WriteString(` ratio="fill";`) + sb.WriteString(` rankdir=TB;`) sb.WriteString("\n") sortedNodes := tm.TopologicalSort() for _, nodeKey := range sortedNodes { node, _ := tm.nodes.Get(nodeKey) - nodeColor := "lightblue" - sb.WriteString(fmt.Sprintf(` "%s" [label=" %s", fillcolor="%s", id="node_%s"];`, node.ID, node.Label, nodeColor, node.ID)) + nodeColor := "lightgray" + nodeShape := "box" + labelSuffix := "" + + // Apply styles based on NodeType + switch node.NodeType { + case Function: + nodeColor = "#D4EDDA" + labelSuffix = " [Function]" + case Page: + nodeColor = "#F08080" + labelSuffix = " [Page]" + } + sb.WriteString(fmt.Sprintf( + ` "%s" [label="%s%s", fontcolor="#2C3E50", fillcolor="%s", shape="%s", style="rounded,filled", id="node_%s"];`, + node.ID, node.Label, labelSuffix, nodeColor, nodeShape, node.ID)) sb.WriteString("\n") } + + // Define edges with unique styling by EdgeType for _, nodeKey := range sortedNodes { node, _ := tm.nodes.Get(nodeKey) for _, edge := range node.Edges { - var edgeStyle string + edgeStyle := "solid" + edgeColor := "black" + labelSuffix := "" + + // Apply styles based on EdgeType switch edge.Type { case Iterator: edgeStyle = "dashed" - default: + edgeColor = "blue" + labelSuffix = " [Iter]" + case Simple: edgeStyle = "solid" + edgeColor = "black" + labelSuffix = "" } - edgeColor := "black" - sb.WriteString(fmt.Sprintf(` "%s" -> "%s" [label=" %s", color="%s", style=%s, fontsize=10, arrowsize=0.6];`, node.ID, edge.To.ID, edge.Label, edgeColor, edgeStyle)) + sb.WriteString(fmt.Sprintf( + ` "%s" -> "%s" [label="%s%s", color="%s", style="%s"];`, + node.ID, edge.To.ID, edge.Label, labelSuffix, edgeColor, edgeStyle)) sb.WriteString("\n") } } @@ -187,6 +208,8 @@ func (tm *DAG) ExportDOT() string { } } } + + // Optional: Group related nodes into subgraphs (e.g., loops) for _, nodeKey := range sortedNodes { node, _ := tm.nodes.Get(nodeKey) if node.processor != nil { @@ -194,35 +217,28 @@ func (tm *DAG) ExportDOT() string { if subDAG != nil { sb.WriteString(fmt.Sprintf(` subgraph "cluster_%s" {`, subDAG.name)) sb.WriteString("\n") - sb.WriteString(fmt.Sprintf(` label=" %s";`, subDAG.name)) + sb.WriteString(fmt.Sprintf(` label="Subgraph: %s";`, subDAG.name)) sb.WriteString("\n") - sb.WriteString(` style=dashed;`) - sb.WriteString("\n") - sb.WriteString(` bgcolor="lightgray";`) - sb.WriteString("\n") - sb.WriteString(` node [shape=rectangle, style="filled", fillcolor="lightblue", fontname="Arial", margin="0.2,0.1"];`) + sb.WriteString(` style=filled; color=gray90;`) sb.WriteString("\n") subDAG.nodes.ForEach(func(subNodeKey string, subNode *Node) bool { - sb.WriteString(fmt.Sprintf(` "%s" [label=" %s"];`, subNodeKey, subNode.Label)) + sb.WriteString(fmt.Sprintf(` "%s" [label="%s"];`, subNode.ID, subNode.Label)) sb.WriteString("\n") return true }) subDAG.nodes.ForEach(func(subNodeKey string, subNode *Node) bool { for _, edge := range subNode.Edges { - sb.WriteString(fmt.Sprintf(` "%s" -> "%s" [label=" %s", color="black", style=solid, arrowsize=0.6];`, subNodeKey, edge.To.ID, edge.Label)) + sb.WriteString(fmt.Sprintf(` "%s" -> "%s" [label="%s"];`, subNodeKey, edge.To.ID, edge.Label)) sb.WriteString("\n") } return true }) - sb.WriteString(` }`) - sb.WriteString("\n") - sb.WriteString(fmt.Sprintf(` "%s" -> "%s" [label=" %s", color="black", style=solid, arrowsize=0.6];`, node.ID, subDAG.startNode, subDAG.name)) - sb.WriteString("\n") + sb.WriteString(" }\n") } } } - sb.WriteString(`}`) - sb.WriteString("\n") + + sb.WriteString("}\n") return sb.String() }