1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-15 17:57:10 +00:00

Improve ELK support

This commit is contained in:
Arnaud Roques 2021-04-14 20:08:29 +02:00
parent dfdec8820f
commit 320ab186b4
2 changed files with 216 additions and 8 deletions

View File

@ -59,15 +59,19 @@ import org.eclipse.elk.graph.ElkNode;
import org.eclipse.elk.graph.util.ElkGraphUtil; import org.eclipse.elk.graph.util.ElkGraphUtil;
import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.UmlDiagram; import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.api.ImageDataSimple; import net.sourceforge.plantuml.api.ImageDataSimple;
import net.sourceforge.plantuml.core.ImageData; import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.cucadiagram.CucaDiagram; import net.sourceforge.plantuml.cucadiagram.CucaDiagram;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.cucadiagram.ILeaf; import net.sourceforge.plantuml.cucadiagram.ILeaf;
import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.graphic.AbstractTextBlock; import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.QuoteUtils; import net.sourceforge.plantuml.graphic.QuoteUtils;
import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlock;
@ -91,6 +95,7 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker {
private final DotStringFactory dotStringFactory; private final DotStringFactory dotStringFactory;
private final Map<ILeaf, ElkNode> nodes = new LinkedHashMap<ILeaf, ElkNode>(); private final Map<ILeaf, ElkNode> nodes = new LinkedHashMap<ILeaf, ElkNode>();
private final Map<Link, ElkEdge> edges = new LinkedHashMap<Link, ElkEdge>();
public CucaDiagramFileMakerElk(CucaDiagram diagram, StringBounder stringBounder) { public CucaDiagramFileMakerElk(CucaDiagram diagram, StringBounder stringBounder) {
this.diagram = diagram; this.diagram = diagram;
@ -99,6 +104,36 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker {
} }
// Unused right now
private TextBlock getLabel(Link link) {
final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1;
ISkinParam skinParam = diagram.getSkinParam();
final FontConfiguration labelFont = new FontConfiguration(skinParam, FontParam.ARROW, null);
final TextBlock label = link.getLabel().create(labelFont,
skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam);
if (TextBlockUtils.isEmpty(label, stringBounder)) {
return label;
}
return TextBlockUtils.withMargin(label, marginLabel, marginLabel);
}
// Unused right now
private TextBlock getQualifier(Link link, int n) {
final String tmp = n == 1 ? link.getQualifier1() : link.getQualifier2();
if (tmp == null) {
return null;
}
final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1;
ISkinParam skinParam = diagram.getSkinParam();
final FontConfiguration labelFont = new FontConfiguration(skinParam, FontParam.ARROW, null);
final TextBlock label = Display.getWithNewlines(tmp).create(labelFont,
skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam);
if (TextBlockUtils.isEmpty(label, stringBounder)) {
return label;
}
return TextBlockUtils.withMargin(label, marginLabel, marginLabel);
}
// The Drawing class does the real drawing // The Drawing class does the real drawing
class Drawing extends AbstractTextBlock implements TextBlockBackcolored { class Drawing extends AbstractTextBlock implements TextBlockBackcolored {
@ -125,6 +160,17 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker {
image.drawU(ug.apply(new UTranslate(corner))); image.drawU(ug.apply(new UTranslate(corner)));
} }
// Draw all edges
for (Entry<Link, ElkEdge> ent : edges.entrySet()) {
final Link link = ent.getKey();
if (link.isInvis()) {
continue;
}
final ElkEdge edge = ent.getValue();
new ElkPath(link, edge, diagram, getLabel(link), getQualifier(link, 1), getQualifier(link, 2))
.drawU(ug);
}
} }
public Dimension2D calculateDimension(StringBounder stringBounder) { public Dimension2D calculateDimension(StringBounder stringBounder) {
@ -146,7 +192,9 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker {
try { try {
final ElkNode root = ElkGraphUtil.createGraph(); final ElkNode root = ElkGraphUtil.createGraph();
final ElkPadding labelPadding = new ElkPadding(2.0);
// This padding setting have no impact ?
final ElkPadding labelPadding = new ElkPadding(100.0);
// Convert all "leaf" to ELK node // Convert all "leaf" to ELK node
for (ILeaf leaf : diagram.getLeafsvalues()) { for (ILeaf leaf : diagram.getLeafsvalues()) {
@ -162,7 +210,11 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker {
// There is no real "label" here // There is no real "label" here
// We just would like to force node dimension // We just would like to force node dimension
final ElkLabel label = ElkGraphUtil.createLabel(node); final ElkLabel label = ElkGraphUtil.createLabel(node);
label.setDimensions(dimension.getWidth(), dimension.getHeight()); label.setText("X");
// I don't know why we have to do this hack, but somebody has to fix it
final double VERY_STRANGE_OFFSET = 10;
label.setDimensions(dimension.getWidth() - VERY_STRANGE_OFFSET, dimension.getHeight());
// No idea of what we are doing here :-) // No idea of what we are doing here :-)
label.setProperty(CoreOptions.NODE_LABELS_PLACEMENT, EnumSet.of(NodeLabelPlacement.INSIDE, label.setProperty(CoreOptions.NODE_LABELS_PLACEMENT, EnumSet.of(NodeLabelPlacement.INSIDE,
@ -175,22 +227,31 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker {
nodes.put(leaf, node); nodes.put(leaf, node);
} }
// https://www.eclipse.org/forums/index.php/t/1095737/
for (final Link link : diagram.getLinks()) { for (final Link link : diagram.getLinks()) {
final ElkEdge edge = ElkGraphUtil.createEdge(root); final ElkEdge edge = ElkGraphUtil.createEdge(root);
System.err.println("edge=" + edge);
edge.getSources().add(nodes.get(link.getEntity1())); edge.getSources().add(nodes.get(link.getEntity1()));
edge.getTargets().add(nodes.get(link.getEntity2())); edge.getTargets().add(nodes.get(link.getEntity2()));
edges.put(link, edge);
} }
final RecursiveGraphLayoutEngine engine = new RecursiveGraphLayoutEngine(); final RecursiveGraphLayoutEngine engine = new RecursiveGraphLayoutEngine();
engine.layout(root, new NullElkProgressMonitor()); engine.layout(root, new NullElkProgressMonitor());
// Debug // Debug
for (final ElkNode node : nodes.values()) { // for (final ElkNode node : nodes.values()) {
final String name = node.getLabels().get(0).getText(); // final String name = node.getLabels().get(0).getText();
System.out.println("node " + name + " : " + node.getX() + ", " + node.getY() + " (" + node.getWidth() // System.out.println("node " + name + " : " + node.getX() + ", " + node.getY() + " (" + node.getWidth()
+ ", " + node.getHeight() + ")"); // + ", " + node.getHeight() + ")");
} // }
// for (final ElkEdge edge : edges.values()) {
// final EList<ElkEdgeSection> sections = edge.getSections();
// System.out.println("edge=" + edge.getSections());
// System.out.println("edge=" + edge.getProperty(LayeredOptions.JUNCTION_POINTS));
// for (ElkEdgeSection s : sections)
// System.out.println(s.getBendPoints());
// }
final MinMax minMax = TextBlockUtils.getMinMax(new Drawing(null), stringBounder, false); final MinMax minMax = TextBlockUtils.getMinMax(new Drawing(null), stringBounder, false);

View File

@ -0,0 +1,147 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.elk;
import org.eclipse.elk.graph.ElkBendPoint;
import org.eclipse.elk.graph.ElkEdge;
import org.eclipse.elk.graph.ElkEdgeSection;
import org.eclipse.emf.common.util.EList;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.UmlDiagramType;
import net.sourceforge.plantuml.cucadiagram.CucaDiagram;
import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.cucadiagram.LinkType;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UStroke;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
public class ElkPath implements UDrawable {
private final Link link;
private final ElkEdge edge;
private final CucaDiagram diagram;
private final TextBlock label;
private final TextBlock headLabel;
private final TextBlock tailLabel;
private final Rose rose = new Rose();
public ElkPath(Link link, ElkEdge edge, CucaDiagram diagram, TextBlock label, TextBlock tailLabel,
TextBlock headLabel) {
this.link = link;
this.edge = edge;
this.diagram = diagram;
this.label = label;
this.tailLabel = tailLabel;
this.headLabel = headLabel;
}
private ColorParam getArrowColorParam() {
if (diagram.getUmlDiagramType() == UmlDiagramType.CLASS) {
return ColorParam.arrow;
} else if (diagram.getUmlDiagramType() == UmlDiagramType.OBJECT) {
return ColorParam.arrow;
} else if (diagram.getUmlDiagramType() == UmlDiagramType.DESCRIPTION) {
return ColorParam.arrow;
} else if (diagram.getUmlDiagramType() == UmlDiagramType.ACTIVITY) {
return ColorParam.arrow;
} else if (diagram.getUmlDiagramType() == UmlDiagramType.STATE) {
return ColorParam.arrow;
}
throw new IllegalStateException();
}
public void drawU(UGraphic ug) {
if (link.isHidden()) {
return;
}
HColor color = rose.getHtmlColor(diagram.getSkinParam(), null, getArrowColorParam());
if (this.link.getColors() != null) {
final HColor newColor = this.link.getColors().getColor(ColorType.ARROW, ColorType.LINE);
if (newColor != null) {
color = newColor;
}
} else if (this.link.getSpecificColor() != null) {
color = this.link.getSpecificColor();
}
final LinkType linkType = link.getType();
UStroke stroke = linkType.getStroke3(diagram.getSkinParam().getThickness(LineParam.arrow, null));
if (link.getColors() != null && link.getColors().getSpecificLineStroke() != null) {
stroke = link.getColors().getSpecificLineStroke();
}
ug = ug.apply(stroke).apply(color);
final EList<ElkEdgeSection> sections = edge.getSections();
for (ElkEdgeSection section : sections) {
final EList<ElkBendPoint> points = section.getBendPoints();
double x1 = section.getStartX();
double y1 = section.getStartY();
for (ElkBendPoint pt : points) {
drawLine(ug, x1, y1, pt.getX(), pt.getY());
x1 = pt.getX();
y1 = pt.getY();
}
drawLine(ug, x1, y1, section.getEndX(), section.getEndY());
}
}
private void drawLine(UGraphic ug, final double x1, final double y1, final double x2, final double y2) {
final ULine line = new ULine(x2 - x1, y2 - y1);
ug.apply(new UTranslate(x1, y1)).draw(line);
}
}