Skip to content

Commit 183cbfd

Browse files
GraphvizAutomaticLayout.apply(Workspace) now only applies automatic layout to views that have Graphviz configured.
1 parent a3af931 commit 183cbfd

File tree

4 files changed

+104
-96
lines changed

4 files changed

+104
-96
lines changed

structurizr-autolayout/src/main/java/com/structurizr/autolayout/graphviz/DOTExporter.java

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ class DOTExporter extends AbstractDiagramExporter {
2020
private static final int CLUSTER_INTERNAL_MARGIN = 25;
2121

2222
private Locale locale = Locale.US;
23-
private RankDirection rankDirection;
24-
private double rankSeparation;
25-
private double nodeSeparation;
23+
private final RankDirection rankDirection;
24+
private final double rankSeparation;
25+
private final double nodeSeparation;
2626

2727
private int groupId = 1;
2828

2929
DOTExporter(RankDirection rankDirection, double rankSeparation, double nodeSeparation) {
30-
this.rankDirection = rankDirection;
31-
this.rankSeparation = rankSeparation;
32-
this.nodeSeparation = nodeSeparation;
30+
this.rankDirection = rankDirection != null ? rankDirection : RankDirection.TopBottom;
31+
this.rankSeparation = rankSeparation / Constants.STRUCTURIZR_DPI;
32+
this.nodeSeparation = nodeSeparation / Constants.STRUCTURIZR_DPI;
3333
}
3434

3535
void setLocale(Locale locale) {
@@ -38,33 +38,6 @@ void setLocale(Locale locale) {
3838

3939
@Override
4040
protected void writeHeader(ModelView view, IndentingWriter writer) {
41-
if (view.getAutomaticLayout() != null) {
42-
if (view.getAutomaticLayout().getRankDirection() == null) {
43-
rankDirection = RankDirection.TopBottom;
44-
} else {
45-
switch (view.getAutomaticLayout().getRankDirection()) {
46-
case TopBottom:
47-
rankDirection = RankDirection.TopBottom;
48-
break;
49-
case BottomTop:
50-
rankDirection = RankDirection.BottomTop;
51-
break;
52-
case LeftRight:
53-
rankDirection = RankDirection.LeftRight;
54-
break;
55-
case RightLeft:
56-
rankDirection = RankDirection.RightLeft;
57-
break;
58-
}
59-
}
60-
61-
rankSeparation = view.getAutomaticLayout().getRankSeparation();
62-
nodeSeparation = view.getAutomaticLayout().getNodeSeparation();
63-
}
64-
65-
rankSeparation = rankSeparation / Constants.STRUCTURIZR_DPI;
66-
nodeSeparation = nodeSeparation / Constants.STRUCTURIZR_DPI;
67-
6841
writer.writeLine("digraph {");
6942
writer.indent();
7043
writer.writeLine("compound=true");

structurizr-autolayout/src/main/java/com/structurizr/autolayout/graphviz/GraphvizAutomaticLayout.java

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public class GraphvizAutomaticLayout {
3030
private final File path;
3131

3232
private RankDirection rankDirection = RankDirection.TopBottom;
33-
private double rankSeparation = 1.0;
34-
private double nodeSeparation = 1.0;
33+
private double rankSeparation = 300;
34+
private double nodeSeparation = 300;
3535

3636
private int margin = 400;
3737
private boolean changePaperSize = true;
@@ -75,8 +75,21 @@ public void setLocale(Locale locale) {
7575
this.locale = locale;
7676
}
7777

78-
private DOTExporter createDOTExporter() {
79-
DOTExporter exporter = new DOTExporter(rankDirection, rankSeparation, nodeSeparation);
78+
private DOTExporter createDOTExporter(AutomaticLayout automaticLayout) {
79+
DOTExporter exporter;
80+
81+
if (automaticLayout == null) {
82+
// use the configured defaults
83+
exporter = new DOTExporter(rankDirection, rankSeparation, nodeSeparation);
84+
} else {
85+
// use the values from the automatic layout configuration associated with the view
86+
exporter = new DOTExporter(
87+
RankDirection.valueOf(automaticLayout.getRankDirection().name()),
88+
automaticLayout.getRankSeparation(),
89+
automaticLayout.getNodeSeparation()
90+
);
91+
}
92+
8093
exporter.setLocale(locale);
8194

8295
return exporter;
@@ -130,87 +143,101 @@ private void runGraphviz(View view) throws Exception {
130143

131144
public void apply(CustomView view) throws Exception {
132145
log.debug("Running Graphviz for view with key " + view.getKey());
133-
Diagram diagram = createDOTExporter().export(view);
146+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
134147
writeFile(diagram);
135148
runGraphviz(view);
136149
createSVGReader().parseAndApplyLayout(view);
137150
}
138151

139152
public void apply(SystemLandscapeView view) throws Exception {
140153
log.debug("Running Graphviz for view with key " + view.getKey());
141-
Diagram diagram = createDOTExporter().export(view);
154+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
142155
writeFile(diagram);
143156
runGraphviz(view);
144157
createSVGReader().parseAndApplyLayout(view);
145158
}
146159

147160
public void apply(SystemContextView view) throws Exception {
148161
log.debug("Running Graphviz for view with key " + view.getKey());
149-
Diagram diagram = createDOTExporter().export(view);
162+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
150163
writeFile(diagram);
151164
runGraphviz(view);
152165
createSVGReader().parseAndApplyLayout(view);
153166
}
154167

155168
public void apply(ContainerView view) throws Exception {
156169
log.debug("Running Graphviz for view with key " + view.getKey());
157-
Diagram diagram = createDOTExporter().export(view);
170+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
158171
writeFile(diagram);
159172
runGraphviz(view);
160173
createSVGReader().parseAndApplyLayout(view);
161174
}
162175

163176
public void apply(ComponentView view) throws Exception {
164177
log.debug("Running Graphviz for view with key " + view.getKey());
165-
Diagram diagram = createDOTExporter().export(view);
178+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
166179
writeFile(diagram);
167180
runGraphviz(view);
168181
createSVGReader().parseAndApplyLayout(view);
169182
}
170183

171184
public void apply(DynamicView view) throws Exception {
172185
log.debug("Running Graphviz for view with key " + view.getKey());
173-
Diagram diagram = createDOTExporter().export(view);
186+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
174187
writeFile(diagram);
175188
runGraphviz(view);
176189
createSVGReader().parseAndApplyLayout(view);
177190
}
178191

179192
public void apply(DeploymentView view) throws Exception {
180193
log.debug("Running Graphviz for view with key " + view.getKey());
181-
Diagram diagram = createDOTExporter().export(view);
194+
Diagram diagram = createDOTExporter(view.getAutomaticLayout()).export(view);
182195
writeFile(diagram);
183196
runGraphviz(view);
184197
createSVGReader().parseAndApplyLayout(view);
185198
}
186199

187200
public void apply(Workspace workspace) throws Exception {
188201
for (CustomView view : workspace.getViews().getCustomViews()) {
189-
apply(view);
202+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
203+
apply(view);
204+
}
190205
}
191206

192207
for (SystemLandscapeView view : workspace.getViews().getSystemLandscapeViews()) {
193-
apply(view);
208+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
209+
apply(view);
210+
}
194211
}
195212

196213
for (SystemContextView view : workspace.getViews().getSystemContextViews()) {
197-
apply(view);
214+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
215+
apply(view);
216+
}
198217
}
199218

200219
for (ContainerView view : workspace.getViews().getContainerViews()) {
201-
apply(view);
220+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
221+
apply(view);
222+
}
202223
}
203224

204225
for (ComponentView view : workspace.getViews().getComponentViews()) {
205-
apply(view);
226+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
227+
apply(view);
228+
}
206229
}
207230

208231
for (DynamicView view : workspace.getViews().getDynamicViews()) {
209-
apply(view);
232+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
233+
apply(view);
234+
}
210235
}
211236

212237
for (DeploymentView view : workspace.getViews().getDeploymentViews()) {
213-
apply(view);
238+
if (view.getAutomaticLayout() != null && view.getAutomaticLayout().getImplementation() == AutomaticLayout.Implementation.Graphviz) {
239+
apply(view);
240+
}
214241
}
215242
}
216243

structurizr-autolayout/src/test/java/com/structurizr/autolayout/graphviz/DOTExporterTests.java

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -483,49 +483,50 @@ public void test_writeContainerViewWithGroupedElements_WithAndWithoutAGroupSepar
483483
@Test
484484
public void test_AmazonWebServicesExample() throws Exception {
485485
Workspace workspace = WorkspaceUtils.loadWorkspaceFromJson(new File("src/test/resources/structurizr-54915-workspace.json"));
486-
DOTExporter exporter = new DOTExporter(RankDirection.TopBottom, 300, 300);
486+
DOTExporter exporter = new DOTExporter(RankDirection.LeftRight, 300, 300);
487487
Diagram diagram = exporter.export(workspace.getViews().getDeploymentViews().iterator().next());
488488

489489
String content = diagram.getDefinition();
490490

491-
String expectedResult = "digraph {\n" +
492-
" compound=true\n" +
493-
" graph [splines=polyline,rankdir=LR,ranksep=1.0,nodesep=1.0,fontsize=5]\n" +
494-
" node [shape=box,fontsize=5]\n" +
495-
" edge []\n" +
496-
"\n" +
497-
" subgraph cluster_5 {\n" +
498-
" margin=25\n" +
499-
" subgraph cluster_6 {\n" +
500-
" margin=25\n" +
501-
" subgraph cluster_12 {\n" +
502-
" margin=25\n" +
503-
" subgraph cluster_13 {\n" +
504-
" margin=25\n" +
505-
" 14 [width=1.500000,height=1.000000,fixedsize=true,id=14,label=\"14: Database\"]\n" +
506-
" }\n" +
507-
"\n" +
508-
" }\n" +
509-
"\n" +
510-
" 7 [width=1.500000,height=1.000000,fixedsize=true,id=7,label=\"7: Route 53\"]\n" +
511-
" 8 [width=1.500000,height=1.000000,fixedsize=true,id=8,label=\"8: Elastic Load Balancer\"]\n" +
512-
" subgraph cluster_9 {\n" +
513-
" margin=25\n" +
514-
" subgraph cluster_10 {\n" +
515-
" margin=25\n" +
516-
" 11 [width=1.500000,height=1.000000,fixedsize=true,id=11,label=\"11: Web Application\"]\n" +
517-
" }\n" +
518-
"\n" +
519-
" }\n" +
520-
"\n" +
521-
" }\n" +
522-
"\n" +
523-
" }\n" +
524-
"\n" +
525-
" 11 -> 14 [id=15]\n" +
526-
" 7 -> 8 [id=16]\n" +
527-
" 8 -> 11 [id=17]\n" +
528-
"}";
491+
String expectedResult = """
492+
digraph {
493+
compound=true
494+
graph [splines=polyline,rankdir=LR,ranksep=1.0,nodesep=1.0,fontsize=5]
495+
node [shape=box,fontsize=5]
496+
edge []
497+
498+
subgraph cluster_5 {
499+
margin=25
500+
subgraph cluster_6 {
501+
margin=25
502+
subgraph cluster_12 {
503+
margin=25
504+
subgraph cluster_13 {
505+
margin=25
506+
14 [width=1.500000,height=1.000000,fixedsize=true,id=14,label="14: Database"]
507+
}
508+
509+
}
510+
511+
7 [width=1.500000,height=1.000000,fixedsize=true,id=7,label="7: Route 53"]
512+
8 [width=1.500000,height=1.000000,fixedsize=true,id=8,label="8: Elastic Load Balancer"]
513+
subgraph cluster_9 {
514+
margin=25
515+
subgraph cluster_10 {
516+
margin=25
517+
11 [width=1.500000,height=1.000000,fixedsize=true,id=11,label="11: Web Application"]
518+
}
519+
520+
}
521+
522+
}
523+
524+
}
525+
526+
11 -> 14 [id=15]
527+
7 -> 8 [id=16]
528+
8 -> 11 [id=17]
529+
}""";
529530

530531
assertEquals(expectedResult, content);
531532
}

structurizr-autolayout/src/test/java/com/structurizr/autolayout/graphviz/GraphvizAutomaticLayoutTests.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.structurizr.model.Person;
66
import com.structurizr.model.SoftwareSystem;
77
import com.structurizr.model.Tags;
8+
import com.structurizr.view.AutomaticLayout;
89
import com.structurizr.view.Shape;
910
import com.structurizr.view.SystemContextView;
1011
import org.junit.jupiter.api.Test;
@@ -17,7 +18,10 @@
1718
public class GraphvizAutomaticLayoutTests {
1819

1920
@Test
20-
public void test() throws Exception {
21+
public void apply_Workspace() throws Exception {
22+
File tempDir = Files.createTempDirectory("graphviz").toFile();
23+
GraphvizAutomaticLayout graphviz = new GraphvizAutomaticLayout(tempDir);
24+
2125
Workspace workspace = new Workspace("Name", "");
2226
Person user = workspace.getModel().addPerson("User");
2327
SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System");
@@ -33,12 +37,15 @@ public void test() throws Exception {
3337
assertEquals(0, view.getElementView(softwareSystem).getX());
3438
assertEquals(0, view.getElementView(softwareSystem).getY());
3539

36-
File tempDir = Files.createTempDirectory("graphviz").toFile();
37-
GraphvizAutomaticLayout graphviz = new GraphvizAutomaticLayout(tempDir);
38-
graphviz.setRankSeparation(300);
39-
graphviz.setNodeSeparation(300);
40-
graphviz.setMargin(400);
40+
graphviz.apply(workspace);
41+
42+
// no change - the view doesn't have automatic layout configured
43+
assertEquals(0, view.getElementView(user).getX());
44+
assertEquals(0, view.getElementView(user).getY());
45+
assertEquals(0, view.getElementView(softwareSystem).getX());
46+
assertEquals(0, view.getElementView(softwareSystem).getY());
4147

48+
view.enableAutomaticLayout(AutomaticLayout.RankDirection.TopBottom);
4249
graphviz.apply(workspace);
4350

4451
assertEquals(233, view.getElementView(user).getX());

0 commit comments

Comments
 (0)