diff --git a/graphviz2drawio/mx/MxConst.py b/graphviz2drawio/mx/MxConst.py index a01ae3d..c16af8b 100644 --- a/graphviz2drawio/mx/MxConst.py +++ b/graphviz2drawio/mx/MxConst.py @@ -8,6 +8,7 @@ DEFAULT_TEXT_SIZE = 10 DEFAULT_FONT_FAMILY = "Helvetica" +DEFAULT_FONT_COLOR = "#000000" DEFAUT_STROKE = "#000000" DEFAUT_FILL = "#ffffff" diff --git a/graphviz2drawio/mx/MxGraph.py b/graphviz2drawio/mx/MxGraph.py index d771ca9..b2ca13f 100644 --- a/graphviz2drawio/mx/MxGraph.py +++ b/graphviz2drawio/mx/MxGraph.py @@ -2,7 +2,6 @@ from graphviz2drawio.models import DotAttr from graphviz2drawio.mx import MxConst -from graphviz2drawio.mx.Shape import Shape from graphviz2drawio.mx.Styles import Styles @@ -22,11 +21,10 @@ def __init__(self, nodes, edges): self.add_edge(edge) def add_edge(self, edge): - end_arrow = MxConst.NONE + end_arrow = MxConst.BLOCK end_fill = 1 dashed = 1 if edge.style == DotAttr.DASHED else 0 if edge.arrowtail is not None: - end_arrow = MxConst.BLOCK tail = edge.arrowtail if edge.arrowtail[0] == DotAttr.NO_FILL: end_fill = 0 @@ -68,7 +66,7 @@ def add_edge(self, edge): self.add_mx_geo(edge_element) def edge_reposition(self, edges): - # TODO: this needs to be smarter + # TODO: https://github.com/hbmartin/graphviz2drawio/issues/7 edge_to = {} for edge in edges: if edge.to not in edge_to: @@ -96,9 +94,12 @@ def add_node(self, node): else MxConst.DEFAUT_FILL ) stroke = node.stroke if node.stroke is not None else MxConst.DEFAUT_STROKE - style = Styles.NODE.format(fill=fill, stroke=stroke) - if node.shape == Shape.ELLIPSE: - style = Shape.ELLIPSE.value + ";" + style + + if node.shape is not None: + style = Styles.get_for_shape(node.shape).format(fill=fill, stroke=stroke) + else: + style = Styles.NODE.format(fill=fill, stroke=stroke) + node_element = ET.SubElement( self.root, MxConst.CELL, diff --git a/graphviz2drawio/mx/Node.py b/graphviz2drawio/mx/Node.py index f3bc5a7..9a9b6e6 100644 --- a/graphviz2drawio/mx/Node.py +++ b/graphviz2drawio/mx/Node.py @@ -2,14 +2,14 @@ class Node(GraphObj): - def __init__(self, sid, gid, rect, texts, fill, stroke, shape): + def __init__(self, sid, gid, rect, texts, fill, stroke): super(Node, self).__init__(sid, gid) self.rect = rect self.texts = texts self.fill = fill self.stroke = stroke self.label = None - self.shape = shape + self.shape = None def text_to_mx_value(self): value = "" diff --git a/graphviz2drawio/mx/NodeFactory.py b/graphviz2drawio/mx/NodeFactory.py index 908906c..11ed2f3 100644 --- a/graphviz2drawio/mx/NodeFactory.py +++ b/graphviz2drawio/mx/NodeFactory.py @@ -1,6 +1,5 @@ from graphviz2drawio.models import SVG from graphviz2drawio.models.Rect import Rect -from graphviz2drawio.mx.Shape import Shape from .Node import Node from .Text import Text @@ -11,7 +10,6 @@ def __init__(self, coords): def rect_from_svg_points(self, svg): points = svg.split(" ") - assert len(points) == 5 points = [self.coords.translate(*p.split(",")) for p in points] min_x, min_y = points[0] width = 0 @@ -57,14 +55,14 @@ def from_svg(self, g): rect = self.rect_from_svg_points( SVG.get_first(g, "polygon").attrib["points"] ) - shape = Shape.RECT else: rect = self.rect_from_ellipse_svg(SVG.get_first(g, "ellipse").attrib) - shape = Shape.ELLIPSE stroke = None - if "stroke" in g.attrib: - stroke = g.attrib["stroke"] + if SVG.has(g, "polygon"): + polygon = SVG.get_first(g, "polygon") + if "stroke" in polygon.attrib: + stroke = polygon.attrib["stroke"] fill = None if "fill" in g.attrib: fill = g.attrib["fill"] @@ -75,5 +73,4 @@ def from_svg(self, g): texts=texts, fill=fill, stroke=stroke, - shape=shape, ) diff --git a/graphviz2drawio/mx/Shape.py b/graphviz2drawio/mx/Shape.py index 08ac872..178c89f 100644 --- a/graphviz2drawio/mx/Shape.py +++ b/graphviz2drawio/mx/Shape.py @@ -1,6 +1,37 @@ -from enum import Enum - - -class Shape(Enum): - RECT = "rect" - ELLIPSE = "ellipse" +ELLIPSE = "ellipse" +OVAL = "oval" +BOX = "box" +RECT = "rect" +RECTANGLE = "rectangle" +HEXAGON = "hexagon" +POLYGON = "polygon" +CIRCLE = "circle" +EGG = "egg" +TRIANGLE = "triangle" +PLAIN = "plain" +DIAMOND = "diamond" +TRAPEZIUM = "trapezium" +PARALLELOGRAM = "parallelogram" +HOUSE = "house" +PENTAGON = "pentagon" +OCTAGON = "octagon" +DOUBLE_CIRCLE = "doublecircle" +DOUBLE_OCTAGON = "doubleoctagon" +INV_TRIANGLE = "invtriangle" +INV_TRAPEZIUM = "invtrapezium" +INV_HOUSE = "invhouse" +SQUARE = "square" +STAR = "star" +UNDERLINE = "underline" +CYLINDER = "cylinder" +NOTE = "note" +TAB = "tab" +FOLDER = "folder" +BOX_3D = "box3d" +COMPONENT = "component" +PROMOTER = "promoter" +RPROMOTER = "rpromoter" +LPROMOTER = "lpromoter" +CDS = "cds" +RARROW = "rarrow" +LARROW = "larrow" diff --git a/graphviz2drawio/mx/Styles.py b/graphviz2drawio/mx/Styles.py index 72982bd..fb28d86 100644 --- a/graphviz2drawio/mx/Styles.py +++ b/graphviz2drawio/mx/Styles.py @@ -1,4 +1,5 @@ from enum import Enum +from . import Shape class Styles(Enum): @@ -6,5 +7,106 @@ class Styles(Enum): 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};" TEXT = "margin:0px;text-align:{align};{margin};font-size:{size}px;font-family:{family};color:{color};" + ELLIPSE = "ellipse;" + NODE + CIRCLE = "ellipse;aspect=fixed;" + NODE + HEXAGON = "shape=hexagon;perimeter=hexagonPerimeter2;" + NODE + EGG = "shape=mxgraph.flowchart.display;direction=south;" + NODE + TRIANGLE = "triangle;direction=north;" + NODE + LINE = "line;strokeWidth=2;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=top;align=center;" + NODE + DIAMOND = "rhombus;" + NODE + TRAPEZOID = "shape=trapezoid;perimeter=trapezoidPerimeter;" + NODE + PARALLELOGRAM = "shape=parallelogram;perimeter=parallelogramPerimeter;" + NODE + HOUSE = "shape=offPageConnector;direction=west;" + NODE + PENTAGON = "shape=mxgraph.basic.pentagon;" + NODE + OCTAGON = "shape=mxgraph.basic.octagon2;align=center;verticalAlign=middle;dx=15;" + NODE + DOUBLE_CIRCLE = "ellipse;shape=doubleEllipse;aspect=fixed;" + NODE + 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 + INV_TRIANGLE = "triangle;direction=south;" + NODE + INV_TRAPEZOID = "shape=trapezoid;perimeter=trapezoidPerimeter;direction=west;" + NODE + INV_HOUSE = "shape=offPageConnector;direction=east;" + NODE + SQUARE = "aspect=fixed;" + NODE + STAR = "shape=mxgraph.basic.star;labelPosition=center;align=center;verticalLabelPosition=middle;verticalAlign=middle;" + NODE + UNDERLINE = "line;strokeWidth=2;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=top;align=center;" + CYLINDER = "shape=cylinder;boundedLbl=1;backgroundOutline=1;" + NODE + NOTE = "shape=note;backgroundOutline=1;" + NODE + TAB = "shape=folder;tabWidth=40;tabHeight=14;tabPosition=left;" + NODE + FOLDER = "shape=mxgraph.office.concepts.folder;outlineConnect=0;align=center;verticalLabelPosition=middle;verticalAlign=middle;labelPosition=center;shadow=0;dashed=0;" + NODE + CUBE = "shape=cube;boundedLbl=1;backgroundOutline=1;" + NODE + COMPONENT = "shape=component;align=center;spacingLeft=36;verticalAlign=bottom;" + NODE + RPROMOTER = "shape=mxgraph.arrows2.bendArrow;dy=15;dx=38;notch=0;arrowHead=55;rounded=0;shadow=0;dashed=0;align=center;verticalAlign=middle;" + NODE + LPROMOTER = "flipH=1;" + RPROMOTER + CDS = "shape=mxgraph.arrows2.arrow;dy=0;dx=10;notch=0;shadow=0;dashed=0;align=center;verticalAlign=middle;" + NODE + RARROW = "shape=mxgraph.arrows2.arrow;dy=0.6;dx=40;align=center;labelPosition=center;notch=0;strokeWidth=2;verticalLabelPosition=middle;verticalAlign=middle;" + NODE + LARROW = "flipH=1;" + RARROW + + @staticmethod + def get_for_shape(dot_shape): + if dot_shape == Shape.ELLIPSE or dot_shape == Shape.OVAL: + return Styles.ELLIPSE + elif dot_shape == Shape.BOX or dot_shape == Shape.RECT or dot_shape == Shape.RECTANGLE: + return Styles.NODE + elif dot_shape == Shape.HEXAGON or dot_shape == Shape.POLYGON: + return Styles.HEXAGON + elif dot_shape == Shape.CIRCLE: + return Styles.CIRCLE + elif dot_shape == Shape.EGG: + return Styles.EGG + elif dot_shape == Shape.TRIANGLE: + return Styles.TRIANGLE + elif dot_shape == Shape.PLAIN: + return Styles.LINE + elif dot_shape == Shape.DIAMOND: + return Styles.DIAMOND + elif dot_shape == Shape.TRAPEZIUM: + return Styles.TRAPEZOID + elif dot_shape == Shape.PARALLELOGRAM: + return Styles.PARALLELOGRAM + elif dot_shape == Shape.HOUSE: + return Styles.HOUSE + elif dot_shape == Shape.PENTAGON: + return Styles.PENTAGON + elif dot_shape == Shape.OCTAGON: + return Styles.OCTAGON + elif dot_shape == Shape.DOUBLE_CIRCLE: + return Styles.DOUBLE_CIRCLE + elif dot_shape == Shape.DOUBLE_OCTAGON: + return Styles.DOUBLE_OCTAGON + elif dot_shape == Shape.INV_TRIANGLE: + return Styles.INV_TRIANGLE + elif dot_shape == Shape.INV_TRAPEZIUM: + return Styles.INV_TRAPEZOID + elif dot_shape == Shape.INV_HOUSE: + return Styles.INV_HOUSE + elif dot_shape == Shape.SQUARE: + return Styles.SQUARE + elif dot_shape == Shape.STAR: + return Styles.STAR + elif dot_shape == Shape.UNDERLINE: + return Styles.UNDERLINE + elif dot_shape == Shape.CYLINDER: + return Styles.CYLINDER + elif dot_shape == Shape.NOTE: + return Styles.NODE + elif dot_shape == Shape.TAB: + return Styles.TAB + elif dot_shape == Shape.FOLDER: + return Styles.FOLDER + elif dot_shape == Shape.BOX_3D: + return Styles.CUBE + elif dot_shape == Shape.COMPONENT: + return Styles.COMPONENT + elif dot_shape == Shape.PROMOTER or dot_shape == Shape.RPROMOTER: + return Styles.RPROMOTER + elif dot_shape == Shape.LPROMOTER: + return Styles.LPROMOTER + elif dot_shape == Shape.CDS: + return Styles.CDS + elif dot_shape == Shape.RARROW: + return Styles.RARROW + elif dot_shape == Shape.LARROW: + return Styles.LARROW + else: + return Styles.NODE + def format(self, **values): return self.value.format(**values) diff --git a/graphviz2drawio/mx/Text.py b/graphviz2drawio/mx/Text.py index 04889a1..35e3dab 100644 --- a/graphviz2drawio/mx/Text.py +++ b/graphviz2drawio/mx/Text.py @@ -22,7 +22,7 @@ def get_mx_style(self): margin=margin, size=rescaled_size, family=self.family or MxConst.DEFAULT_FONT_FAMILY, - color=self.color, + color=self.color or MxConst.DEFAULT_FONT_COLOR, ) @staticmethod @@ -32,5 +32,5 @@ def from_svg(t): anchor=t.attrib["text-anchor"], family=t.attrib["font-family"], size=float(t.attrib["font-size"]), - color=t.attrib["fill"], + color=t.attrib["fill"] or None, ) diff --git a/graphviz2drawio/version.py b/graphviz2drawio/version.py index 81f0fde..b1a19e3 100644 --- a/graphviz2drawio/version.py +++ b/graphviz2drawio/version.py @@ -1 +1 @@ -__version__ = "0.0.4" +__version__ = "0.0.5"