Hi is there a way to solve the following issue?
We’re using LayeredDigraphLayout and can have a node which can have up to two children that we tried to configure to look like this:
However, in some cases it doesn’t look as expected:
While generally we have this structure, it is possible for loops to exist in our logic (for instance the node on the right could point back to the node of the left or any other node before it), which is why we did not use TreeLayout.
We suspect that it looks like this because of the automatic layout of the nodes which is handled by the LayeredDigraphLayout. Is there a way we can control how the nodes are aligned in relation of each other? Or some other way to fix this?
Here is some example data that should help to reproduce all three cases:
nodeDataArray = [
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10001,
iconSrc: "",
iconColor: "#f2c2f7ff",
iconBackgroundColor: "#0c0d0dff",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: null,
key: 10002,
iconSrc: "",
iconColor: null,
iconBackgroundColor: "#1474c3",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10003,
iconSrc: "",
iconColor: null,
iconBackgroundColor: "#1474c3",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10004,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10005,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
key: 10006,
name: "Name",
iconSrc: "",
category: "main",
nodeType: "OTHERTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10007,
iconSrc: "",
iconColor: null,
iconBackgroundColor: "#1474c3",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: true
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10008,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10009,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10010,
iconSrc: "",
iconColor: null,
iconBackgroundColor: "#1474c3",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10011,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: true
},
{
name: "Name",
message: null,
key: 10012,
iconSrc: "",
iconColor: null,
iconBackgroundColor: "#1474c3",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10013,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: true
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10014,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: false
},
{
name: "Name",
message: "Lorem ipsum lorem ipsum",
key: 10015,
iconSrc: "",
iconColor: "#002137",
iconBackgroundColor: "#FFFFFF",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: true
},
{
name: null,
message: null,
key: 10016,
iconSrc: "",
iconColor: null,
iconBackgroundColor: "#1474c3",
category: "main",
nodeType: "MAINTYPE",
menuIconSrc: "",
isDecision: true
},
{
key: 10016,
name: "Name",
category: "main",
iconSrc: "",
iconColor: "#daa4e3ff",
iconBackgroundColor: "#985aa2ff",
nodeType: "OTHERTYPE",
menuIconSrc: "",
isDecision: true
}
];
linkDataArray = [
{
key: ":10004->10005",
from: 10004,
to: 10005,
fromSpot: Spot.Right,
toPort: "leftSide",
category: "normal"
},
{
key: "10005->10006",
from: 10005,
to: 10006,
fromSpot: Spot.Right,
toPort: "leftSide",
category: "normal"
},
{
key: "10006->10001",
from: 10006,
to: 10001,
fromSpot: Spot.Right,
toPort: "leftSide",
category: "normal"
},
{
key: "10006->10003",
from: 10006,
to: 10003,
fromSpot: Spot.Right,
toPort: "leftSide",
category: "normal"
},
{
key: "10006->10002",
from: 10006,
to: 10002,
fromSpot: Spot.Right,
toPort: "leftSide",
category: "normal"
},
{
key: "10007->10009",
from: 10007,
to: 10009,
fromSpot: Spot.Top,
toPort: "leftSide",
linkTypeText: "No",
iconSrc: "",
category: "branching"
},
{
key: "10007->10008",
from: 10007,
to: 10008,
toPort: "leftSide",
fromSpot: Spot.Bottom,
linkTypeText: "Yes",
iconSrc: "",
category: "branching",
},
{
key: "10011->10013",
from: 10011,
to: 10013,
fromSpot: Spot.Top,
toPort: "leftSide",
linkTypeText: "No",
iconSrc: "",
category: "branching"
},
{
key: "10011->10015",
from: 10011,
to: 10015,
toPort: "leftSide",
fromSpot: Spot.Bottom,
linkTypeText: "Yes",
iconSrc: "",
category: "branching",
},
{
key: "10013->10012",
from: 10013,
to: 10012,
fromSpot: Spot.Top,
toPort: "leftSide",
linkTypeText: "No",
iconSrc: "",
category: "branching"
},
{
key: "10013->10010",
from: 10013,
to: 10010,
toPort: "leftSide",
fromSpot: Spot.Bottom,
linkTypeText: "Yes",
iconSrc: "",
category: "branching",
},
{
key: "10015->10014",
from: 10015,
to: 10014,
fromSpot: Spot.Top,
toPort: "leftSide",
linkTypeText: "No",
iconSrc: "",
category: "branching"
},
{
key: "10016->10007",
from: 10016,
to: 10007,
fromSpot: Spot.Right,
toPort: "leftSide",
linkTypeText: "some text",
category: "withText"
},
{
key: "10016->10011",
from: 10016,
to: 10011,
fromSpot: Spot.Right,
toPort: "leftSide",
linkTypeText: "some text",
category: "withText"
},
{
key: "10016->10004",
from: 10016,
to: 10004,
fromSpot: Spot.Right,
toPort: "leftSide",
linkTypeText: "some text",
category: "withText"
}
];
The diagram configuration:
const diagram = $(Diagram, {
'undoManager.isEnabled': true,
layout: $(LayeredDigraphLayout, ({
layerSpacing: 300,
columnSpacing: 250,
direction: 0,
setsPortSpots: false, // do not set the port spots automatically, we do that in the node templates
})),
isReadOnly: true,
model: $(GraphLinksModel, {
linkKeyProperty: 'key',
linkFromPortIdProperty: 'fromPort',
linkToPortIdProperty: 'toPort',
}),
});
diagram.toolManager.mouseWheelBehavior = WheelMode.Zoom;
The node template:
const mainTemplate = $(
Node,
'Table',
$(
Panel,
'Auto',
{
column: 0,
portId: 'leftSide',
},
$(
Shape,
'RoundedRectangle',
{
isPanelMain: true,
strokeWidth: 1,
fill: '#ffffff',
stroke: '#E6E8EB',
margin: 0,
},
new Binding('width', 'isDecision', (isDecision) => isDecision ? 273 : 320),
),
$(
Panel,
'Horizontal',
{
background: 'transparent',
margin: 0,
},
$(
Panel,
'Table',
{
background: 'transparent',
stretch: Stretch.Vertical,
width: 10,
},
),
$(
Panel,
'Vertical',
{
background: 'transparent',
},
$(
Panel,
'Horizontal',
{
background: 'transparent',
height: 10,
stretch: Stretch.Fill,
},
),
$(Panel,
'Table',
$(Panel,
'Table',
{
row: 0,
margin: new Margin(0, 0, 10, 0)
},
new Binding('row', 'nodeType', (nodeType) => nodeType === 'MAINTYPE' ? 0 : 1),
$(Panel,
'Auto',
{
column: 0,
alignment: Spot.Top,
},
$(Shape, 'Circle', {
fill: 'white',
strokeWidth: 1,
width: 45,
height: 45,
alignment: new Spot(0.5, 0.5),
},
new Binding('fill', 'iconBackgroundColor')
),
$(Picture,
{
source: '',
width: 25,
height: 25,
},
new Binding('source', 'iconSrc'),
),
),
$(Panel,
'Auto',
{
background: 'transparent',
// width: 240,
column: 1,
margin: new Margin(0, 0, 0, 10),
},
new Binding('width', 'isDecision', (isDecision) => isDecision ? 193 : 240),
$(TextBlock,
{
row: 1,
overflow: TextOverflow.Ellipsis,
maxLines: 2,
font: 'bold 16px Roboto',
margin: new Margin(0, 0, 5, 0),
stretch: Stretch.Fill,
background: 'transparent',
textAlign: 'start',
},
new Binding('text', 'name'),
),
),
),
$(Panel,
'Auto',
{
row: 1,
},
$(TextBlock,
{
stretch: Stretch.Fill,
overflow: TextOverflow.Ellipsis,
maxLines: 2,
font: '14px Roboto',
background: 'transparent',
wrap: Wrap.Fit,
textAlign: 'start',
},
[
new Binding('text', 'message'),
new Binding('visible', 'nodeType', (nodeType) => nodeType === 'MAINTYPE'),
new Binding('width', 'isDecision', (isDecision) => isDecision ? 255 : 300),
]
),
),
),
$(
Panel,
'Horizontal',
{
background: 'transparent',
height: 10,
stretch: Stretch.Fill,
},
)
),
$(
Panel,
'Table',
{
background: 'transparent',
stretch: Stretch.Vertical,
width: 10,
},
),
)
),
$(
Shape,
'LineH',
{
column: 1,
width: 15,
},
new Binding('visible', 'isDecision')
),
$(
Shape,
'Diamond',
{
column: 2,
strokeWidth: 1,
fill: '#1474C3',
stroke: '#1474C3',
margin: 0,
width: 32,
height: 32,
strokeJoin: 'bevel',
strokeCap: 'round',
portId: '',
},
new Binding('visible', 'isDecision')
),
);
diagram.nodeTemplateMap.add('main', mainTemplate);
The link templates:
const branchingTemplate = $(Link,
{
routing: Routing.AvoidsNodes,
toEndSegmentLength: 50,
fromEndSegmentLength: 50,
curve: Curve.JumpOver,
toSpot: Spot.Left,
},
[
new Binding('fromSpot', 'fromSpot'),
new Binding('toPort', 'toPort'),
],
$(Shape),
$(Shape, { toArrow: 'Standard' }),
$(Panel, 'Auto').add(
$(Shape, 'RoundedRectangle',
{
stroke: 'transparent',
fill: '#E6E8EB',
},
new Binding('width', 'linkTypeText', (text) => text.length * 12 + 16),
),
$(Panel, 'Horizontal').add(
$(Picture,
{ source: '', width: 16, height: 16 },
new Binding('source', 'linkIconSrc'),
),
$(TextBlock, {
verticalAlignment: Spot.Center,
font: '12px Roboto',
}).bind('text','linkTypeText')
),
)
);
const withTextTemplate = $(Link,
{
routing: Routing.AvoidsNodes,
toEndSegmentLength: 40,
curve: Curve.JumpOver,
toSpot: Spot.Left,
},
[
new Binding('fromSpot', 'fromSpot'),
],
$(Shape),
$(Shape, { toArrow: 'Standard' }),
$(Panel, 'Auto',
{
segmentIndex: -2,
segmentFraction: 0.3,
}
).add(
$(Shape, 'RoundedRectangle',
{
stroke: 'transparent',
fill: '#E6E8EB',
},
),
$(Panel, 'Horizontal').add(
$(TextBlock, {
overflow: TextOverflow.Ellipsis,
wrap: Wrap.Fit,
maxLines: 1,
verticalAlignment: Spot.Center,
font: '12px Roboto',
width: 150,
}).bind('text','linkTypeText')
),
)
);
const normalLinkTemplate = $(Link,
{
routing: Routing.AvoidsNodes,
toEndSegmentLength: 40,
curve: Curve.JumpOver,
fromSpot: Spot.Right,
toSpot: Spot.Left,
},
[
new Binding('toSpot', 'toSpot'),
],
$(Shape),
$(Shape, { toArrow: 'Standard' }),
);
diagram.linkTemplateMap.add('branching', branchingTemplate);
diagram.linkTemplateMap.add('withText', withTextTemplate);
diagram.linkTemplateMap.add('normal', normalLinkTemplate);


