Skip to content

Commit 13490c6

Browse files
committed
add support for graphviz builtin shapes
1 parent f507870 commit 13490c6

8 files changed

Lines changed: 157 additions & 25 deletions

File tree

graphviz2drawio/mx/MxConst.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
DEFAULT_TEXT_SIZE = 10
1010
DEFAULT_FONT_FAMILY = "Helvetica"
11+
DEFAULT_FONT_COLOR = "#000000"
1112

1213
DEFAUT_STROKE = "#000000"
1314
DEFAUT_FILL = "#ffffff"

graphviz2drawio/mx/MxGraph.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from graphviz2drawio.models import DotAttr
44
from graphviz2drawio.mx import MxConst
5-
from graphviz2drawio.mx.Shape import Shape
65
from graphviz2drawio.mx.Styles import Styles
76

87

@@ -22,11 +21,10 @@ def __init__(self, nodes, edges):
2221
self.add_edge(edge)
2322

2423
def add_edge(self, edge):
25-
end_arrow = MxConst.NONE
24+
end_arrow = MxConst.BLOCK
2625
end_fill = 1
2726
dashed = 1 if edge.style == DotAttr.DASHED else 0
2827
if edge.arrowtail is not None:
29-
end_arrow = MxConst.BLOCK
3028
tail = edge.arrowtail
3129
if edge.arrowtail[0] == DotAttr.NO_FILL:
3230
end_fill = 0
@@ -68,7 +66,7 @@ def add_edge(self, edge):
6866
self.add_mx_geo(edge_element)
6967

7068
def edge_reposition(self, edges):
71-
# TODO: this needs to be smarter
69+
# TODO: https://github.com/hbmartin/graphviz2drawio/issues/7
7270
edge_to = {}
7371
for edge in edges:
7472
if edge.to not in edge_to:
@@ -96,9 +94,12 @@ def add_node(self, node):
9694
else MxConst.DEFAUT_FILL
9795
)
9896
stroke = node.stroke if node.stroke is not None else MxConst.DEFAUT_STROKE
99-
style = Styles.NODE.format(fill=fill, stroke=stroke)
100-
if node.shape == Shape.ELLIPSE:
101-
style = Shape.ELLIPSE.value + ";" + style
97+
98+
if node.shape is not None:
99+
style = Styles.get_for_shape(node.shape).format(fill=fill, stroke=stroke)
100+
else:
101+
style = Styles.NODE.format(fill=fill, stroke=stroke)
102+
102103
node_element = ET.SubElement(
103104
self.root,
104105
MxConst.CELL,

graphviz2drawio/mx/Node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33

44
class Node(GraphObj):
5-
def __init__(self, sid, gid, rect, texts, fill, stroke, shape):
5+
def __init__(self, sid, gid, rect, texts, fill, stroke):
66
super(Node, self).__init__(sid, gid)
77
self.rect = rect
88
self.texts = texts
99
self.fill = fill
1010
self.stroke = stroke
1111
self.label = None
12-
self.shape = shape
12+
self.shape = None
1313

1414
def text_to_mx_value(self):
1515
value = ""

graphviz2drawio/mx/NodeFactory.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from graphviz2drawio.models import SVG
22
from graphviz2drawio.models.Rect import Rect
3-
from graphviz2drawio.mx.Shape import Shape
43
from .Node import Node
54
from .Text import Text
65

@@ -11,7 +10,6 @@ def __init__(self, coords):
1110

1211
def rect_from_svg_points(self, svg):
1312
points = svg.split(" ")
14-
assert len(points) == 5
1513
points = [self.coords.translate(*p.split(",")) for p in points]
1614
min_x, min_y = points[0]
1715
width = 0
@@ -57,14 +55,14 @@ def from_svg(self, g):
5755
rect = self.rect_from_svg_points(
5856
SVG.get_first(g, "polygon").attrib["points"]
5957
)
60-
shape = Shape.RECT
6158
else:
6259
rect = self.rect_from_ellipse_svg(SVG.get_first(g, "ellipse").attrib)
63-
shape = Shape.ELLIPSE
6460

6561
stroke = None
66-
if "stroke" in g.attrib:
67-
stroke = g.attrib["stroke"]
62+
if SVG.has(g, "polygon"):
63+
polygon = SVG.get_first(g, "polygon")
64+
if "stroke" in polygon.attrib:
65+
stroke = polygon.attrib["stroke"]
6866
fill = None
6967
if "fill" in g.attrib:
7068
fill = g.attrib["fill"]
@@ -75,5 +73,4 @@ def from_svg(self, g):
7573
texts=texts,
7674
fill=fill,
7775
stroke=stroke,
78-
shape=shape,
7976
)

graphviz2drawio/mx/Shape.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,37 @@
1-
from enum import Enum
2-
3-
4-
class Shape(Enum):
5-
RECT = "rect"
6-
ELLIPSE = "ellipse"
1+
ELLIPSE = "ellipse"
2+
OVAL = "oval"
3+
BOX = "box"
4+
RECT = "rect"
5+
RECTANGLE = "rectangle"
6+
HEXAGON = "hexagon"
7+
POLYGON = "polygon"
8+
CIRCLE = "circle"
9+
EGG = "egg"
10+
TRIANGLE = "triangle"
11+
PLAIN = "plain"
12+
DIAMOND = "diamond"
13+
TRAPEZIUM = "trapezium"
14+
PARALLELOGRAM = "parallelogram"
15+
HOUSE = "house"
16+
PENTAGON = "pentagon"
17+
OCTAGON = "octagon"
18+
DOUBLE_CIRCLE = "doublecircle"
19+
DOUBLE_OCTAGON = "doubleoctagon"
20+
INV_TRIANGLE = "invtriangle"
21+
INV_TRAPEZIUM = "invtrapezium"
22+
INV_HOUSE = "invhouse"
23+
SQUARE = "square"
24+
STAR = "star"
25+
UNDERLINE = "underline"
26+
CYLINDER = "cylinder"
27+
NOTE = "note"
28+
TAB = "tab"
29+
FOLDER = "folder"
30+
BOX_3D = "box3d"
31+
COMPONENT = "component"
32+
PROMOTER = "promoter"
33+
RPROMOTER = "rpromoter"
34+
LPROMOTER = "lpromoter"
35+
CDS = "cds"
36+
RARROW = "rarrow"
37+
LARROW = "larrow"

graphviz2drawio/mx/Styles.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,112 @@
11
from enum import Enum
2+
from . import Shape
23

34

45
class Styles(Enum):
56
NODE = "verticalAlign=top;align=left;overflow=fill;html=1;rounded=0;shadow=0;comic=0;labelBackgroundColor=none;strokeColor={stroke};strokeWidth=1;fillColor={fill};"
67
EDGE = "edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX={exit_x:.3g};exitY={exit_y:.3g};entryX={entry_x:.3g};entryY={entry_y:.3g};jettySize=auto;orthogonalLoop=1;endArrow={end_arrow};dashed={dashed};endFill={end_fill};"
78
TEXT = "margin:0px;text-align:{align};{margin};font-size:{size}px;font-family:{family};color:{color};"
89

10+
ELLIPSE = "ellipse;" + NODE
11+
CIRCLE = "ellipse;aspect=fixed;" + NODE
12+
HEXAGON = "shape=hexagon;perimeter=hexagonPerimeter2;" + NODE
13+
EGG = "shape=mxgraph.flowchart.display;direction=south;" + NODE
14+
TRIANGLE = "triangle;direction=north;" + NODE
15+
LINE = "line;strokeWidth=2;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=top;align=center;" + NODE
16+
DIAMOND = "rhombus;" + NODE
17+
TRAPEZOID = "shape=trapezoid;perimeter=trapezoidPerimeter;" + NODE
18+
PARALLELOGRAM = "shape=parallelogram;perimeter=parallelogramPerimeter;" + NODE
19+
HOUSE = "shape=offPageConnector;direction=west;" + NODE
20+
PENTAGON = "shape=mxgraph.basic.pentagon;" + NODE
21+
OCTAGON = "shape=mxgraph.basic.octagon2;align=center;verticalAlign=middle;dx=15;" + NODE
22+
DOUBLE_CIRCLE = "ellipse;shape=doubleEllipse;aspect=fixed;" + NODE
23+
DOUBLE_OCTAGON = "shape=image;html=1;verticalAlign=middle;verticalLabelPosition=middle;imageAspect=0;aspect=fixed;image=https://cdn4.iconfinder.com/data/icons/feather/24/octagon-128.png;labelPosition=center;align=center;" + NODE
24+
INV_TRIANGLE = "triangle;direction=south;" + NODE
25+
INV_TRAPEZOID = "shape=trapezoid;perimeter=trapezoidPerimeter;direction=west;" + NODE
26+
INV_HOUSE = "shape=offPageConnector;direction=east;" + NODE
27+
SQUARE = "aspect=fixed;" + NODE
28+
STAR = "shape=mxgraph.basic.star;labelPosition=center;align=center;verticalLabelPosition=middle;verticalAlign=middle;" + NODE
29+
UNDERLINE = "line;strokeWidth=2;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=top;align=center;"
30+
CYLINDER = "shape=cylinder;boundedLbl=1;backgroundOutline=1;" + NODE
31+
NOTE = "shape=note;backgroundOutline=1;" + NODE
32+
TAB = "shape=folder;tabWidth=40;tabHeight=14;tabPosition=left;" + NODE
33+
FOLDER = "shape=mxgraph.office.concepts.folder;outlineConnect=0;align=center;verticalLabelPosition=middle;verticalAlign=middle;labelPosition=center;shadow=0;dashed=0;" + NODE
34+
CUBE = "shape=cube;boundedLbl=1;backgroundOutline=1;" + NODE
35+
COMPONENT = "shape=component;align=center;spacingLeft=36;verticalAlign=bottom;" + NODE
36+
RPROMOTER = "shape=mxgraph.arrows2.bendArrow;dy=15;dx=38;notch=0;arrowHead=55;rounded=0;shadow=0;dashed=0;align=center;verticalAlign=middle;" + NODE
37+
LPROMOTER = "flipH=1;" + RPROMOTER
38+
CDS = "shape=mxgraph.arrows2.arrow;dy=0;dx=10;notch=0;shadow=0;dashed=0;align=center;verticalAlign=middle;" + NODE
39+
RARROW = "shape=mxgraph.arrows2.arrow;dy=0.6;dx=40;align=center;labelPosition=center;notch=0;strokeWidth=2;verticalLabelPosition=middle;verticalAlign=middle;" + NODE
40+
LARROW = "flipH=1;" + RARROW
41+
42+
@staticmethod
43+
def get_for_shape(dot_shape):
44+
if dot_shape == Shape.ELLIPSE or dot_shape == Shape.OVAL:
45+
return Styles.ELLIPSE
46+
elif dot_shape == Shape.BOX or dot_shape == Shape.RECT or dot_shape == Shape.RECTANGLE:
47+
return Styles.NODE
48+
elif dot_shape == Shape.HEXAGON or dot_shape == Shape.POLYGON:
49+
return Styles.HEXAGON
50+
elif dot_shape == Shape.CIRCLE:
51+
return Styles.CIRCLE
52+
elif dot_shape == Shape.EGG:
53+
return Styles.EGG
54+
elif dot_shape == Shape.TRIANGLE:
55+
return Styles.TRIANGLE
56+
elif dot_shape == Shape.PLAIN:
57+
return Styles.LINE
58+
elif dot_shape == Shape.DIAMOND:
59+
return Styles.DIAMOND
60+
elif dot_shape == Shape.TRAPEZIUM:
61+
return Styles.TRAPEZOID
62+
elif dot_shape == Shape.PARALLELOGRAM:
63+
return Styles.PARALLELOGRAM
64+
elif dot_shape == Shape.HOUSE:
65+
return Styles.HOUSE
66+
elif dot_shape == Shape.PENTAGON:
67+
return Styles.PENTAGON
68+
elif dot_shape == Shape.OCTAGON:
69+
return Styles.OCTAGON
70+
elif dot_shape == Shape.DOUBLE_CIRCLE:
71+
return Styles.DOUBLE_CIRCLE
72+
elif dot_shape == Shape.DOUBLE_OCTAGON:
73+
return Styles.DOUBLE_OCTAGON
74+
elif dot_shape == Shape.INV_TRIANGLE:
75+
return Styles.INV_TRIANGLE
76+
elif dot_shape == Shape.INV_TRAPEZIUM:
77+
return Styles.INV_TRAPEZOID
78+
elif dot_shape == Shape.INV_HOUSE:
79+
return Styles.INV_HOUSE
80+
elif dot_shape == Shape.SQUARE:
81+
return Styles.SQUARE
82+
elif dot_shape == Shape.STAR:
83+
return Styles.STAR
84+
elif dot_shape == Shape.UNDERLINE:
85+
return Styles.UNDERLINE
86+
elif dot_shape == Shape.CYLINDER:
87+
return Styles.CYLINDER
88+
elif dot_shape == Shape.NOTE:
89+
return Styles.NODE
90+
elif dot_shape == Shape.TAB:
91+
return Styles.TAB
92+
elif dot_shape == Shape.FOLDER:
93+
return Styles.FOLDER
94+
elif dot_shape == Shape.BOX_3D:
95+
return Styles.CUBE
96+
elif dot_shape == Shape.COMPONENT:
97+
return Styles.COMPONENT
98+
elif dot_shape == Shape.PROMOTER or dot_shape == Shape.RPROMOTER:
99+
return Styles.RPROMOTER
100+
elif dot_shape == Shape.LPROMOTER:
101+
return Styles.LPROMOTER
102+
elif dot_shape == Shape.CDS:
103+
return Styles.CDS
104+
elif dot_shape == Shape.RARROW:
105+
return Styles.RARROW
106+
elif dot_shape == Shape.LARROW:
107+
return Styles.LARROW
108+
else:
109+
return Styles.NODE
110+
9111
def format(self, **values):
10112
return self.value.format(**values)

graphviz2drawio/mx/Text.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def get_mx_style(self):
2222
margin=margin,
2323
size=rescaled_size,
2424
family=self.family or MxConst.DEFAULT_FONT_FAMILY,
25-
color=self.color,
25+
color=self.color or MxConst.DEFAULT_FONT_COLOR,
2626
)
2727

2828
@staticmethod
@@ -32,5 +32,5 @@ def from_svg(t):
3232
anchor=t.attrib["text-anchor"],
3333
family=t.attrib["font-family"],
3434
size=float(t.attrib["font-size"]),
35-
color=t.attrib["fill"],
35+
color=t.attrib["fill"] or None,
3636
)

graphviz2drawio/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.0.4"
1+
__version__ = "0.0.5"

0 commit comments

Comments
 (0)