Viz.js (Graphviz)
Viz.js trae el poder de Graphviz a Moraya, permitiéndote renderizar descripciones de grafos en lenguaje DOT directamente en bloques de código Markdown. Graphviz es la herramienta estándar de la industria para visualizar información estructural como diagramas de grafos y redes abstractas, desde diagramas de flujo simples hasta árboles de dependencias complejos y máquinas de estado.
Lenguajes de Bloque de Código
Usa dot o graphviz como etiqueta de lenguaje:
```dot
digraph { Start -> Process -> End }
```
```graphviz
graph { Server -- Client -- Database }
```
Ambos producen el mismo resultado: dot y graphviz son intercambiables.
Sintaxis Básica
Grafos Dirigidos (digraph)
Un grafo dirigido usa flechas (->) para conectar nodos. Este ejemplo muestra una tubería de compilación simple:
```dot
digraph pipeline {
rankdir=LR
Code -> Build -> Test -> Deploy
}
```
Grafos No Dirigidos (graph)
Un grafo no dirigido usa líneas (--) para conectar nodos. Este ejemplo muestra una red punto a punto:
```dot
graph network {
layout=neato
overlap=false
Alice -- Bob
Alice -- Carol
Bob -- Dave
Carol -- Dave
Dave -- Eve
}
```
Atributos
Los atributos personalizan la apariencia de grafos, nodos y aristas:
```dot
digraph styled {
rankdir=LR
node [shape=box, style=filled, fillcolor="#E3F2FD"]
edge [color="#1565C0"]
Input [shape=parallelogram, fillcolor="#C8E6C9"]
Output [shape=parallelogram, fillcolor="#FFCDD2"]
Input -> Process -> Decision
Decision -> Output [label="yes"]
Decision -> Process [label="retry", style=dashed]
}
```
Motores de Diseño
Especifica el motor de diseño con el atributo de grafo layout:
| Motor | Ideal Para |
|---|---|
dot (predeterminado) | Grafos jerárquicos y en capas (DAGs) |
neato | Grafos no dirigidos usando modelo de resorte |
fdp | Grafos no dirigidos usando posicionamiento dirigido por fuerza |
circo | Diseños circulares |
twopi | Diseños radiales (raíz en el centro) |
Uso: graph [layout=neato]
Formas de Nodo
Formas de nodo comunes disponibles en Graphviz:
| Forma | Descripción |
|---|---|
ellipse | Forma ovalada predeterminada |
box | Rectángulo |
circle | Círculo perfecto |
diamond | Rombo / decisión |
record | Registro con campos separados por | |
plaintext | Solo texto, sin borde |
doublecircle | Círculo con doble contorno |
triangle | Triángulo |
hexagon | Hexágono |
parallelogram | Paralelogramo |
cylinder | Cilindro (base de datos) |
folder | Forma de carpeta |
component | Componente UML |
note | Nota adhesiva |
Estilos de Arista
| Estilo | Descripción |
|---|---|
solid | Línea sólida predeterminada |
dashed | Línea discontinua |
dotted | Línea punteada |
bold | Línea sólida más gruesa |
invis | Invisible (para espaciado del diseño) |
Ejemplos
Grafo Dirigido Simple
Un grafo de dependencias básico mostrando la relación entre pasos de compilación.
```dot
digraph build_pipeline {
rankdir=LR
node [shape=box, style=filled, fillcolor="#f0f0f0"]
Source -> Compile
Compile -> Link
Link -> Test
Test -> Deploy
}
```
Diagrama de Flujo con Formas y Colores
Un diagrama de flujo de decisiones usando diferentes formas de nodo para distinguir acciones de decisiones.
```dot
digraph flowchart {
node [fontname="Helvetica"]
start [shape=ellipse, style=filled, fillcolor="#4CAF50", fontcolor=white, label="Start"]
input [shape=parallelogram, style=filled, fillcolor="#E3F2FD", label="Read Input"]
check [shape=diamond, style=filled, fillcolor="#FFF9C4", label="Valid?"]
process [shape=box, style=filled, fillcolor="#E3F2FD", label="Process Data"]
error [shape=box, style=filled, fillcolor="#FFCDD2", label="Show Error"]
output [shape=parallelogram, style=filled, fillcolor="#E3F2FD", label="Write Output"]
end [shape=ellipse, style=filled, fillcolor="#F44336", fontcolor=white, label="End"]
start -> input
input -> check
check -> process [label="Yes"]
check -> error [label="No"]
error -> input
process -> output
output -> end
}
```
Jerarquía de Clases (Árbol de Herencia)
Una jerarquía de clases orientada a objetos mostrando relaciones de herencia.
```dot
digraph class_hierarchy {
rankdir=BT
node [shape=record, style=filled, fillcolor="#FFFDE7"]
Animal [label="{Animal|+ name: String\l+ age: Int\l|+ speak(): String\l+ move(): void\l}"]
Dog [label="{Dog|+ breed: String\l|+ fetch(): void\l}"]
Cat [label="{Cat|+ indoor: Bool\l|+ purr(): void\l}"]
Bird [label="{Bird|+ wingspan: Float\l|+ fly(): void\l}"]
GoldenRetriever [label="{GoldenRetriever|+ trained: Bool\l}"]
Parrot [label="{Parrot|+ vocabulary: Int\l|+ mimic(): void\l}"]
Dog -> Animal [arrowhead=empty]
Cat -> Animal [arrowhead=empty]
Bird -> Animal [arrowhead=empty]
GoldenRetriever -> Dog [arrowhead=empty]
Parrot -> Bird [arrowhead=empty]
}
```
Máquina de Estados
Una máquina de estados finita para el ciclo de vida simplificado de una conexión TCP.
```dot
digraph tcp_states {
rankdir=LR
node [shape=circle, style=filled, fillcolor="#E8EAF6"]
CLOSED [shape=doublecircle, fillcolor="#FFCDD2"]
LISTEN [fillcolor="#C8E6C9"]
SYN_SENT
SYN_RCVD
ESTABLISHED [shape=doublecircle, fillcolor="#C8E6C9"]
FIN_WAIT_1
FIN_WAIT_2
CLOSE_WAIT
TIME_WAIT
CLOSED -> LISTEN [label="passive open"]
CLOSED -> SYN_SENT [label="active open\n/ send SYN"]
LISTEN -> SYN_RCVD [label="recv SYN\n/ send SYN+ACK"]
SYN_SENT -> ESTABLISHED [label="recv SYN+ACK\n/ send ACK"]
SYN_RCVD -> ESTABLISHED [label="recv ACK"]
ESTABLISHED -> FIN_WAIT_1 [label="close\n/ send FIN"]
ESTABLISHED -> CLOSE_WAIT [label="recv FIN\n/ send ACK"]
FIN_WAIT_1 -> FIN_WAIT_2 [label="recv ACK"]
FIN_WAIT_2 -> TIME_WAIT [label="recv FIN\n/ send ACK"]
CLOSE_WAIT -> CLOSED [label="close\n/ send FIN"]
TIME_WAIT -> CLOSED [label="timeout"]
}
```
Topología de Red
Una topología de red de centro de datos con switches, routers y servidores.
```dot
graph network {
graph [layout=neato, overlap=false]
node [fontname="Helvetica", fontsize=10]
// Core router
router [shape=diamond, style=filled, fillcolor="#FF9800", fontcolor=white, label="Core\nRouter"]
// Distribution switches
sw1 [shape=box, style=filled, fillcolor="#42A5F5", fontcolor=white, label="Switch 1"]
sw2 [shape=box, style=filled, fillcolor="#42A5F5", fontcolor=white, label="Switch 2"]
// Servers
web1 [shape=box3d, style=filled, fillcolor="#E8F5E9", label="Web 1"]
web2 [shape=box3d, style=filled, fillcolor="#E8F5E9", label="Web 2"]
db1 [shape=cylinder, style=filled, fillcolor="#FFF3E0", label="DB Primary"]
db2 [shape=cylinder, style=filled, fillcolor="#FFF3E0", label="DB Replica"]
cache [shape=box3d, style=filled, fillcolor="#F3E5F5", label="Redis"]
// Connections
router -- sw1 [penwidth=2]
router -- sw2 [penwidth=2]
sw1 -- web1
sw1 -- web2
sw1 -- cache
sw2 -- db1
sw2 -- db2
db1 -- db2 [style=dashed, label="replication"]
}
```
Nodos Basados en Registros (Struct)
Uso de formas de registro para visualizar estructuras de datos y la disposición de sus campos.
```dot
digraph structs {
node [shape=record, fontname="Courier", fontsize=10]
linked_list [label="<head> head | {data: 10 | <next> next}"]
node1 [label="{data: 20 | <next> next}"]
node2 [label="{data: 30 | <next> next}"]
null [shape=plaintext, label="NULL"]
linked_list:next -> node1
node1:next -> node2
node2:next -> null
// Binary tree
root [label="<left> | 50 | <right>"]
l1 [label="<left> | 30 | <right>"]
r1 [label="<left> | 70 | <right>"]
l2 [label="<left> | 20 | <right>"]
l3 [label="<left> | 40 | <right>"]
root:left -> l1
root:right -> r1
l1:left -> l2
l1:right -> l3
}
```
Subgrafos y Clústeres
Los clústeres agrupan nodos relacionados con un límite visible.
```dot
digraph architecture {
compound=true
node [shape=box, style="filled,rounded", fontname="Helvetica"]
subgraph cluster_frontend {
label="Frontend"
style=filled
fillcolor="#E3F2FD"
color="#1565C0"
react [label="React App", fillcolor="#BBDEFB"]
nginx [label="Nginx", fillcolor="#BBDEFB"]
}
subgraph cluster_backend {
label="Backend"
style=filled
fillcolor="#E8F5E9"
color="#2E7D32"
api [label="API Server", fillcolor="#C8E6C9"]
auth [label="Auth Service", fillcolor="#C8E6C9"]
worker [label="Background Worker", fillcolor="#C8E6C9"]
}
subgraph cluster_data {
label="Data Layer"
style=filled
fillcolor="#FFF3E0"
color="#E65100"
postgres [label="PostgreSQL", shape=cylinder, fillcolor="#FFE0B2"]
redis [label="Redis", shape=cylinder, fillcolor="#FFE0B2"]
s3 [label="S3 Storage", shape=folder, fillcolor="#FFE0B2"]
}
react -> nginx
nginx -> api
api -> auth
api -> postgres
api -> redis
auth -> postgres
worker -> redis
worker -> s3
}
```
Grafo de Commits de Git
Un historial simplificado de ramas y fusiones de Git.
```dot
digraph git {
rankdir=LR
node [shape=circle, style=filled, width=0.3, fixedsize=true, fontsize=8]
edge [arrowsize=0.6]
// Main branch
m1 [fillcolor="#4CAF50", label="m1"]
m2 [fillcolor="#4CAF50", label="m2"]
m3 [fillcolor="#4CAF50", label="m3"]
m4 [fillcolor="#4CAF50", label="m4"]
m5 [fillcolor="#4CAF50", label="m5"]
m1 -> m2 -> m3 -> m4 -> m5
// Feature branch
f1 [fillcolor="#2196F3", label="f1"]
f2 [fillcolor="#2196F3", label="f2"]
f3 [fillcolor="#2196F3", label="f3"]
m2 -> f1 -> f2 -> f3
f3 -> m4 [style=dashed, label="merge"]
// Hotfix branch
h1 [fillcolor="#F44336", label="h1"]
m3 -> h1
h1 -> m5 [style=dashed, label="merge"]
// Branch labels
main [shape=box, style="filled,rounded", fillcolor="#C8E6C9", label="main"]
feature [shape=box, style="filled,rounded", fillcolor="#BBDEFB", label="feature/login"]
hotfix [shape=box, style="filled,rounded", fillcolor="#FFCDD2", label="hotfix/bug-fix"]
m5 -> main [style=invis]
f3 -> feature [style=invis]
h1 -> hotfix [style=invis]
{ rank=same; m1 }
{ rank=same; m2; f1 }
{ rank=same; m3; f2; h1 }
{ rank=same; m4; f3 }
{ rank=same; m5; main; feature; hotfix }
}
```
Consejos
- Usa
rankdir=LRpara diseños de izquierda a derecha en lugar del predeterminado de arriba a abajo. - Usa
\len lugar de\nen etiquetas de registro para saltos de línea alineados a la izquierda. - Configura
overlap=falsecon diseñosneatoofdppara evitar que los nodos se superpongan. - Usa
compound=truepara permitir aristas entre clústeres. - Usa etiquetas tipo HTML (
<TABLE>) para contenido de nodo complejo cuando las formas de registro no son suficientemente flexibles.