nodes section - modelint/flatland-model-diagram-editor GitHub Wiki
Immediately below the header is the nodes section. A node is the graphical representation of a model element that can be represented with some style of rectangle. Nodes are connected to one another via connectors.
A state machine diagram, for example, will define a node for each state and a connector for each transition. Similarly, a class diagram defines a node for each class and a connector for each relationship. Each node has a name and a grid placement specification. The node name must match a corresponding model element name. So if you are drawing a class diagram, each node name will be a class name. If you are drawing a state machine diagram, each node name will be a state name. The placement specification indicates where you would like that node to be drawn using the Flatland grid.
nodes
<node_name>(/<lines>)? [<width_expansion>] [<compartment_height_expansion>]... <row_span>,<col_span> [>right | >left]? [>top | >bottom ]? <tag>
...
The node keyword appears on a un-indented line by itself. All subsequent node specifications must be indented by exactly four spaces. Five shalt thou not count, neither count thou three, excepting that thou then proceed to four. Six is right out. (Flatland is written in python, so there had to be a Monty Python quote in here somewhere).
<node_name>
refers to a name of a corresponding element in the model file. <row_span>,<col_span>
with no space around the comma, is the grid coordinate(s) where the node will be placed. A range is specified so that a node can span more than one row or column. In the simple case, the range is a single row or column number. They syntax for a span is:
<from_number>(-<to_number>)?
In other words, a from_number
followed by an optional -to_number
if you want to specify a range greater than one grid unit. The value of the to_number
must be greater than the from_number
. Here are some span examples:
2,3 // row 2, col 3
2-4,3 // rows 2, 3 and 4, col 3
1,5-6 // ro1 1, cols 5 and 6
3-4,2-3 // rows 3 and 4, cols 2 and 3
By default, each node is aligned vertically and horizontally centered within its row and column spans. And if a node is the largest within its row and column spans, it will be shrink wrapped by the span grid boundaries and no alignment options will take effect, even if specified. But when one node is smaller than the other nodes in its row span, let’s say, you may want to push that node to the top or bottom of the row span: similarly for columns.
In this section we’ll leave out the connector section and just focus on the nodes. If you specify the following in your layout file:
nodes
Aircraft 1,1 // Both nodes in same column
Pilot 3,1
The nodes will be placed on the diagram grid as shown:
In the example above the Pilot
node is placed in row 3, column 1 while the Aircraft
is in the same column, two rows down. If you want to connect the two nodes, you’ll need to leave at least one row of empty space in between.
Now let’s say that your class model has a generalization relationship where you want a superclass centered above two subclasses. In that case you’ll use a tree connector and you could place the superclass in its own column as shown below:
nodes
Aircraft 3,2
Helicopter 1,1
Fixed Wing 1,3
This works, but that dedicated column in the middle takes up a lot of horizontal space. The column width is computed automatically, so you can’t control that directly. You can, however, tighten things up by moving the Fixed Wing
subclass into column 2, adjacent to Helicopter
, and have the Aircraft
class straddle columns 1 and 2 using a column span as shown:
nodes
Aircraft 3,1-2
Helicopter 1,1
Fixed Wing 1,3
Notice that we changed the Aircraft
column specification from a single column to a span. It gives us this output:
The fundamental rule of the Flatland grid is that no two nodes may occupy the same span. When a node claims a span, it greedily prevents any other node from intruding into that span. So no other node can intrude into columns 1 and 2 in row 3. This rule ensures that no two nodes can ever overlap. You will get an error and no diagram if you try.
To tighten up the vertical space, it might be nice to move the root node down closer to its leaf nodes. We can’t just move the Aircraft
node down into row 2 because there would then be no room for the branch and trunk decoration (the generalization arrow). A better option is to have the root node span rows 2 and 3. The new node section of our script then looks like this:
nodes
Aircraft 2-3,1-2 // Span two rows and two columns
Helicopter 1,1
Fixed Wing 1,2
Which renders as:
The Aircraft
node now occupies four grid cells. With spanning, you need to be careful to not accidentally assign the same grid cell to two nodes. If you do, you will get an error and no diagram.
The Aircraft
node is centered within its four grid cell span, which, in the above example, is probably what you want. But there are cases where you might want the node to be aligned to the top or bottom vertically, left or right horizontally, or some combination of vertical and horizontal alignment. This is possible by adding an alignment specification as shown:
nodes
Aircraft 2-3,1-2 >right
Helicopter 1,1
Fixed Wing 1,2
Here we have pushed the root node over to the right, but kept it centered horizontally.
Or we can push the node to the top left corner of its span.
nodes
Aircraft 2-3,1-2 >left >top
Helicopter 1,1
Fixed Wing 1,2
A class with a long name can result in an excessively wide node as shown below:
nodes
Drone 3,2
Remote controlled fixed wing drone 1,1
Remote controlled rotary wing drone 1,2
We can wrap the the long title names into multiple lines to trade off node width vs. height using the /
symbol followed by the number of lines you want.
nodes Drone 3,2 Remote controlled fixed wing drone/2 1,1 Remote controlled rotary wing drone/3 1,3
The first subclass is wrapped on two lines while the other is wrapped on three.
Sometimes a node will envelope short lines of text and therefore be a bit narrow. This can be a problem if you want to attach more than one connector to the top or bottom of the node. A class named 'Dog' with only one attribute 'ID' is a perfect example. To widen it up, you can provide an expansion percentage. This will increase the width of the node rectangle by adding that percentage.
nodes
Dog 75% 2,4
In the above example, the node will be be wider by 75% of its original width.
Syntax:
'[C' number ']' percent '%'
Normally all compartment heights in a node are wrapped to fit text and a small margin above and below. If you want a taller node you need to apply an expansion factor to one or more compartments. Compartments are numbered top to bottom starting with 1. So the name compartment of a class or state will be 1. The activity compartment of a UML state will be 2, the attributes compartment of a UML class is 2 and the methods compartment of a UML class will be 3.
Here is an example where the name compartment of a state is normal height, but the activity compartment is stretched 6x normal leaving lots of blank space between the last line of activity text and the bottom of the expanded compartment.
Pre cross fail [C2]600% 17-21,8 // The activity compartment is 6x as tall!
If you wanted to expand the name compartment by 50% also, and while you're at it, make the whole node 25% wider, you could add another compartment height expansion as well as a node width expansion like this:
Pre cross fail 25% [C1]50% [C2]600% 17-21,8 // More width and both compartments taller
Syntax:
space '<' tag_name '>'
You may want a node to be colored according to some usage. For example, a state on a state machine diagram might appear in the 'bubble gum' (pink-ish red) color to indicate that it is an error state or 'sky' (sky blue) to represent a recovery state. On a class diagram you might decide to highlight all specification classes with some color.
To do this, you add a tag to your node indicating your particular usage. This usage will then be mapped by Flatland to an associated color. (You do not specify a color in your tag, just a usage). Currently defiend usages are just for state machines and they are <ideal> (everything going well state), <recovery> (not so well, but still marching on) and <error>. More tags to come and soon they will be user definable.
nodes
Target lane unavailable 19,6 <error>
And that’s all there is to node placement specifications!