Skip to content

Commit

Permalink
Completed implementation for connectors.
Browse files Browse the repository at this point in the history
  • Loading branch information
autobuild committed Oct 6, 2024
1 parent fa93c88 commit 7db2830
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 177 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,24 @@ Icons are from the [icons repo](https://github.com/IBM-Cloud/architecture-icons)
<details><summary>Features</summary>

1. Diagrams generated by ibmdiagrams follow the [IBM Diagram Standard](https://www.ibm.com/design/language/infographics/technical-diagrams/design) using IBM Color Palette and IBM Plex Fonts.
2. Shapes:
2. Sidebars:
- ibmcloud is becoming hardened and less likely to change.
- ibmshapes (only available internally for non-cloud) is not hardened and likely to change.
3. Shapes:
- Group (container=1) represents a deployedOn relationship (e.g. virtual server is deployedOn a subnet).
- Zone (container=0) represents a deployedTo relationship (e.g. virtual server is deployedTo a security group).
- Node (square shape) represent standalone components or devices.
- Actor (round shape) represent roles, functions or attributes played by human users, devices and other entities that interact with any of the above.
3. Selecting within non-containers:
4. Selecting within non-containers:
- ibmdiagrams generates correct Z order autommatically.
- If needed, use alt-click or option-click to select shapes within non-containers, or define Z order by moving shapes backward.
4. Labels:
5. Labels:
- ibmdiagrams enables the use of two labels on all shapes with a label that is SemiBold font and a sublabel (under label) that is regular font using html: \<b style='font-weight:600'>label\</b>\<br>sublabel
- Users can also add \<br> tags in labels and sublabels for additional lines.
- Group properties are generated according to how many lines are intended to ensure proper label placement, e.g. Labels with one, two, or three lines will be centered vertically in the 48 height of the group label, and greater than three lines will start at the top of the 48 height and continue downward.
5. Fill colors:
6. Fill colors:
- ibmdiagrams generates shapes with fill colors that are either white or a light color from same color family as the corresponding primary color (e.g. Cyan 50 is primary and fill is Cyan 10 or white).
6. Connectors (in progress):
7. Connectors (in progress):
- Line styles can be solid, dashed2, dotted, double, and tunnel are supported according to existing styles in drawio - the dashed1 line style is deferred initially.
- Line ends can be arrow (filled or open), circle (filled or open), and diamond (filled or open) - the T-shape end is deferred initially.
</details>
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "ibmdiagrams"
version = "1.0.26"
version = "1.0.27"
description = "Generate architecture diagrams following IBM Diagram Standard"
readme = "README.md"
requires-python = ">=3.11.0"
Expand Down
15 changes: 9 additions & 6 deletions src/ibmdiagrams.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: ibmdiagrams
Version: 1.0.26
Version: 1.0.27
Summary: Generate architecture diagrams following IBM Diagram Standard
Author-email: Jay Warfield <[email protected]>
Maintainer-email: Jay Warfield <[email protected]>
Expand Down Expand Up @@ -255,21 +255,24 @@ Icons are from the [icons repo](https://github.com/IBM-Cloud/architecture-icons)
<details><summary>Features</summary>

1. Diagrams generated by ibmdiagrams follow the [IBM Diagram Standard](https://www.ibm.com/design/language/infographics/technical-diagrams/design) using IBM Color Palette and IBM Plex Fonts.
2. Shapes:
2. Sidebars:
- ibmcloud is becoming hardened and less likely to change.
- ibmshapes (only available internally for non-cloud) is not hardened and likely to change.
3. Shapes:
- Group (container=1) represents a deployedOn relationship (e.g. virtual server is deployedOn a subnet).
- Zone (container=0) represents a deployedTo relationship (e.g. virtual server is deployedTo a security group).
- Node (square shape) represent standalone components or devices.
- Actor (round shape) represent roles, functions or attributes played by human users, devices and other entities that interact with any of the above.
3. Selecting within non-containers:
4. Selecting within non-containers:
- ibmdiagrams generates correct Z order autommatically.
- If needed, use alt-click or option-click to select shapes within non-containers, or define Z order by moving shapes backward.
4. Labels:
5. Labels:
- ibmdiagrams enables the use of two labels on all shapes with a label that is SemiBold font and a sublabel (under label) that is regular font using html: \<b style='font-weight:600'>label\</b>\<br>sublabel
- Users can also add \<br> tags in labels and sublabels for additional lines.
- Group properties are generated according to how many lines are intended to ensure proper label placement, e.g. Labels with one, two, or three lines will be centered vertically in the 48 height of the group label, and greater than three lines will start at the top of the 48 height and continue downward.
5. Fill colors:
6. Fill colors:
- ibmdiagrams generates shapes with fill colors that are either white or a light color from same color family as the corresponding primary color (e.g. Cyan 50 is primary and fill is Cyan 10 or white).
6. Connectors (in progress):
7. Connectors (in progress):
- Line styles can be solid, dashed2, dotted, double, and tunnel are supported according to existing styles in drawio - the dashed1 line style is deferred initially.
- Line ends can be arrow (filled or open), circle (filled or open), and diamond (filled or open) - the T-shape end is deferred initially.
</details>
Expand Down
93 changes: 14 additions & 79 deletions src/ibmdiagrams/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# @file __init__.py
#i @file __init__.py
#
# Copyright contributors to the ibmdiagrams project
#
Expand Down Expand Up @@ -301,91 +301,60 @@ def __init__(self,
def __sub__(self, shape = None):
# item - item or item - connector
if isinstance(shape, Group) or isinstance(shape, Item):
#connector = Connector(sourceid=self.shapeid, targetid=shape.shapeid, startarrow="", endarrow="", operator="sub", fontname=self.fontname, fontsize=12)
connector = Connector(sourceid=self.shapeid, targetid=shape.shapeid, startarrow="", endarrow="", operator="sub")
else: # isinstance(shape, Connector)
shape.sourceid = self.shapeid
#shape.startarrow = ""
#shape.endarrow = ""
shape.operator = "sub"
return shape

def __lshift__(self, shape = None):
# shape << shape or shape << connector
if isinstance(shape, Group) or isinstance(shape, Item):
#connector = Connector(sourceid=shape.shapeid, targetid=self.shapeid, operator="lshift", fontname=self.fontname, fontsize=12)
#connector = Connector(sourceid=shape.shapeid, targetid=self.shapeid, startarrow="", endarrow="arrow", operator="lshift", fontname=self.fontname, fontsize=12)
connector = Connector(sourceid=shape.shapeid, targetid=self.shapeid, startarrow="", endarrow="arrow", operator="lshift")

else: # isinstance(shape, Connector)
shape.sourceid = self.shapeid
#shape.startarrow = ""
#shape.endarrow = "arrow"
shape.operator = "lshift"

connectorid = shape.getConnectorID()
_data.setConnectorSourceID(connectorid, shape.shapeid)
_data.setConnectorTargetID(connectorid, self.shapeid)
_data.setConnectorEndArrow(connectorid, "block")
#NEW _data.setConnectorEndArrow(connectorid, "block")
_data.setConnectorOperator(connectorid, "lshift")

#print("__init__::item.lshift")
#_data.printConnector(connectorid)

return shape

def __rshift__(self, shape = None):
# shape >> shape or shape >> connector
if isinstance(shape, Group) or isinstance(shape, Item):
#connector = Connector(sourceid=self.shapeid, targetid=shape.shapeid, color = "", operator="rshift", fontname=self.fontname, fontsize=12)
#connector = Connector(sourceid=self.shapeid, targetid=shape.shapeid, startarrow="", endarrow="arrow", operator="rshift", fontname=self.fontname, fontsize=12)

connector = Connector(sourceid=self.shapeid, targetid=shape.shapeid, startarrow="", endarrow="arrow", operator="rshift")

#print("__init__::item.rshift shape=Group/Item:")
#_data.printConnector(connectorid)
else: # isinstance(shape, Connector)
shape.targetid = self.shapeid
#shape.startarrow = ""
#shape.endarrow = "arrow"
#shape.startarrow = "arrow"
#shape.endarrow = ""
shape.operator = "rshift"

connectorid = shape.getConnectorID()
_data.setConnectorSourceID(connectorid, shape.shapeid)
_data.setConnectorTargetID(connectorid, self.shapeid)
#_data.setConnectorEndArrow(connectorid, "")
_data.setConnectorStartArrow(connectorid, "block")
#_data.setConnectorStartArrow(connectorid, "block")
_data.setConnectorOperator(connectorid, "rshift")

#print("__init__::item.rshift shape=Connector:")
#_data.printConnector(connectorid)

#if self.targetid != None:
# _data.setConnectorSourceID(self.shapeid, self.targetid)
# _data.setConnectorTargetID(self.shapeid, self.sourceid)
# _data.setConnectorStartArrow(self.shapeid, self.startarrow)
# _data.setConnectorEndArrow(self.shapeid, self.endarrow)
# _data.setConnectorStartFill(self.shapeid, self.startfill)
# _data.setConnectorEndFill(self.shapeid, self.endfill)
# _data.setConnectorOperator(self.shapeid, shape.operator)

return shape

class EndTypes(Enum):
NONE = "NONE" # arrow=none
ARROW = "ARROW" # arrow=block
OPENARROW = "OPENARROW" # arrow=open
CIRCLE = "CIRCLE" # arrow=oval
OPENCIRCLE = "OPENSIRCLE" # arrow=oval with fill=0
OPENCIRCLE = "OPENCIRCLE" # arrow=oval with fill=0
DIAMOND = "DIAMOND" # arrow=diamond
OPENDIAMOND = "OPENDIAMOND" # arrow=diamond with fill=0

class EndMapping(Enum):
NONE = "" # arrow=none
ARROW = "block" # arrow=block
OPENARROW = "open" # arrow=block with fill=0
OPENARROW = "block" # arrow=block with fill=0
CIRCLE = "oval" # arrow=oval
OPENCIRCLE = "oval" # arrow=oval with fill=0
DIAMOND = "diamond" # arrow=diamond
Expand All @@ -398,27 +367,25 @@ class Connector:
#sourceid = None
#targetid = None
parent = None
color = ""
linetype = "solid"
linewidth = 1
linecolor = ""
startarrow = ""
endarrow = ""
startfill = True
endfill = True
#operator = ""
#style = ""
item = None
connector = None
properties = {}

def __init__(self,
label = "",
#forward = False, # Not currently used.
#reverse = False, # Not currently used.
color = "", # Not currently used.
style = "", # Not currently used.
startarrow = "",
endarrow = "",
#startfill = True,
#endfill = True,
linetype = "solid",
linewidth = 1,
linecolor = "#000000",
fontname = "IBM Plex Sans",
fontsize = 14,
operator = "", # Internal use only.
Expand All @@ -427,10 +394,7 @@ def __init__(self,
self.common = Common()
self.shapeid = randomid()

self.color = color

#self.startarrow = startarrow
#self.endarrow = endarrow
self.linecolor = linecolor

if startarrow != "":
if not startarrow.upper() in [parm.value for parm in EndTypes]:
Expand Down Expand Up @@ -470,14 +434,11 @@ def __init__(self,
else:
self.endarrow = ""

self.properties = _data.getConnectorProperties(label=label, sourceid=sourceid, targetid=targetid, color=color, style=style, startarrow=self.startarrow, endarrow=self.endarrow, startfill=self.startfill, endfill=self.endfill, fontname=fontname, fontsize=fontsize)
self.properties = _data.getConnectorProperties(label=label, sourceid=sourceid, targetid=targetid, startarrow=self.startarrow, endarrow=self.endarrow, startfill=self.startfill, endfill=self.endfill, linetype=linetype, linewidth=linewidth, linecolor=linecolor, fontname=fontname, fontsize=fontsize)

_data.addConnector(self.shapeid, self.properties)
_data.updateSequence(self.shapeid)

#print("__init__::connector.init printConnector:")
#_data.printConnector(self.shapeid)

return

def getConnectorID(self):
Expand Down Expand Up @@ -516,9 +477,7 @@ def __lshift__(self, shape = None):
# connector << shape
if isinstance(shape, Group) or isinstance(shape, Item):
_data.setConnectorSourceID(self.shapeid, shape.shapeid)
#_data.setConnectorTargetID(self.shapeid, self.sourceid)
_data.setConnectorOperator(self.shapeid, self.operator)
#arrow = "double" if self.operator == "rshift" else "single"
if self.operator == "rshift":
# Double arrow.
_data.setConnectorStartArrow(self.shapeid, self.startarrow)
Expand All @@ -528,16 +487,9 @@ def __lshift__(self, shape = None):
_data.setConnectorOperator(self.shapeid, "lshift")
else:
# Single arrow.
#_data.setConnectorStartArrow(self.shapeid, self.startarrow)
#_data.setConnectorEndArrow(self.shapeid, self.endarrow)
#_data.setConnectorEndArrow(self.shapeid, "block")
_data.setConnectorStartArrow(self.shapeid, "block")
#_data.setConnectorStartFill(self.shapeid, self.startfill)
_data.setConnectorEndArrow(self.shapeid, "block")
_data.setConnectorEndFill(self.shapeid, self.endfill)
_data.setConnectorOperator(self.shapeid, "lshift")

#print("__init__::connector.lshift:")
#_data.printConnector(self.shapeid)
else:
print("Connector.__lshift__: connector << shape not supported")
sys_exit()
Expand All @@ -546,23 +498,11 @@ def __lshift__(self, shape = None):
def __rshift__(self, shape = None):
# connector >> shape
if isinstance(shape, Group) or isinstance(shape, Item):
#_data.setConnectorSourceID(self.shapeid, self.shapeid)
_data.setConnectorSourceID(self.shapeid, shape.shapeid)
#_data.setConnectorTargetID(self.shapeid, shape.shapeid)
#_data.setConnectorOperator(self.shapeid, self.operator)
#_data.setConnectorTargetID(self.shapeid, shape.shapeid)
_data.setConnectorOperator(self.shapeid, "rshift")
#arrow = "double" if self.operator == "lshift" else "single"
if self.operator == "lshift":
# Double arrow.
#_data.setConnectorStartArrow(self.shapeid, self.startarrow)
_data.setConnectorStartArrow(self.shapeid, "block")
#_data.setConnectorEndArrow(self.shapeid, self.endarrow)
#_data.setConnectorStartFill(self.shapeid, self.startfill)
#_data.setConnectorEndFill(self.shapeid, self.endfill)

#print("__init__::connector.rshift shape=Group/Item lshift:")
#_data.printConnector(self.shapeid)

else:
# Single arrow.
Expand All @@ -572,13 +512,8 @@ def __rshift__(self, shape = None):
_data.setConnectorTargetID(self.shapeid, sourceid)
_data.setConnectorStartArrow(self.shapeid, "")
_data.setConnectorEndArrow(self.shapeid, "block")
#_data.setConnectorStartFill(self.shapeid, self.startfill)
_data.setConnectorEndFill(self.shapeid, self.endfill)

#print("__init__::connector.rshift shape=Group/Item notLSHIFT:")
#_data.printConnector(self.shapeid)


else:
print("Connector.__rshift__: connector >> shape not supported")
sys_exit()
Expand Down
35 changes: 19 additions & 16 deletions src/ibmdiagrams/ibmbase/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ def buildSheets(self, properties, diagrams):
outputfile = outputfile if outputfile != "" else diagramname + ".drawio"
outputfolder = self.common.getOutputFolder()

print("build:")
print(self.common.isInputPython())
if (self.common.isInputPython()):
self.common.printStartDiagram(diagramname + ".py", provider)
else:
Expand Down Expand Up @@ -286,6 +284,11 @@ def buildConnectorShape(self, connectorid, properties):
startfill = properties["startfill"]
endfill = properties["endfill"]
label = properties["label"]
linetype = properties["linetype"]
linewidth = properties["linewidth"]
linecolor = properties["linecolor"]
fontname = properties["fontname"]
fontsize = properties["fontsize"]

'''
if arrow == "none":
Expand All @@ -297,12 +300,12 @@ def buildConnectorShape(self, connectorid, properties):
'''

if startarrow == "" and endarrow == "":
connectornode = self.shapes.buildSolidLink(connectorid, label, sourceid, targetid, startarrow, endarrow, startfill, endfill, None)
connectornode = self.shapes.buildSolidLink(connectorid, label, sourceid, targetid, startarrow, endarrow, startfill, endfill, linetype, linewidth, linecolor, fontname, fontsize, None)
elif startarrow != "" and endarrow != "":
connectornode = self.shapes.buildDoubleArrow(connectorid, label, sourceid, targetid, startarrow, endarrow, startfill, endfill, None)
connectornode = self.shapes.buildDoubleArrow(connectorid, label, sourceid, targetid, startarrow, endarrow, startfill, endfill, linetype, linewidth, linecolor, fontname, fontsize, None)
#elif startarrow != "" or endarrow != "":
else:
connectornode = self.shapes.buildSingleArrow(connectorid, label, sourceid, targetid, startarrow, endarrow, startfill, endfill, None)
connectornode = self.shapes.buildSingleArrow(connectorid, label, sourceid, targetid, startarrow, endarrow, startfill, endfill, linetype, linewidth, linecolor, fontname, fontsize, None)

links.append(connectornode)

Expand Down Expand Up @@ -670,21 +673,21 @@ def checkItems(self, items):

def checkConnectors(self, connectors):
for connectorid, properties in connectors.items():
color = properties["color"]
if color != "":
hexcolor = self.checkLineColor(color)
self.common.printInvalidLineColor(color)
linecolor = properties["linecolor"]
if linecolor == "":
hexcolor = self.checkLineColor(linecolor)
self.common.printInvalidLineColor(linecolor)
return None
else:
color = self.checkLineColor("black")
#else:
# color = self.checkLineColor("black")

style = properties["style"]
if style == "":
style = CONNECTOR_STYLE_DEFAULT
elif not style.upper() in [parm.value for parm in ConnectorStyles]:
linetype = properties["linetype"]
if linetype == "":
linetype = CONNECTOR_STYLE_DEFAULT
elif not linetype.upper() in [parm.value for parm in ConnectorStyles]:
self.common.printInvalidConnectorStyle(style)
return None
connectors[connectorid]["style"] = style
connectors[connectorid]["linetype"] = linetype

'''
startarrow = properties["startarrow"]
Expand Down
Loading

0 comments on commit 7db2830

Please sign in to comment.