klayjs
klayjs copied to clipboard
intCoordinates results in misaligned edges originating from and targeting the same port
Please consider the following example:
Options:
{
"algorithm": "de.cau.cs.kieler.klay.layered",
"spacing": 10,
"borderSpacing" : 10,
"labelSpacing" : 0,
"layoutHierarchy": true,
"intCoordinates": true,
"edgeRouting": "ORTHOGONAL"
}
KLay JSON:
{
"id": "root",
"labels": [
{
"text": "root"
}
],
"edges": [
{
"id": "a:0",
"source": "a",
"target": "a2",
"labels": [],
"sourcePort": "a_enter0",
"targetPort": "a2_enter0",
},
{
"id": "a1:0",
"source": "a1",
"target": "b",
"labels": [
{
"text": "t",
"width": 1.109375,
"height": 5
}
]
},
{
"id": "$generated_a_initial_0:0",
"source": "$generated_a_initial_0",
"target": "a1",
"labels": []
},
{
"id": "$generated_root_initial_0:0",
"source": "$generated_root_initial_0",
"target": "a",
"labels": []
},
{
"id": "a_exit0_a_enter0",
"source": "a",
"target": "a",
"sourcePort": "a_exit0",
"targetPort": "a_enter0",
"labels": [
{
"text": "t",
"width": 1.109375,
"height": 5
}
],
}
],
"width": 11.4375,
"height": 10,
"children": [
{
"id": "a",
"labels": [
{
"text": "a"
}
],
"edges": [],
"width": 6.765625,
"height": 10,
"children": [
{
"id": "a1",
"labels": [
{
"text": "a1"
}
],
"edges": [],
"width": 8.765625,
"height": 10,
"x": 0,
"y": 0
},
{
"id": "a2",
"labels": [
{
"text": "a2"
}
],
"edges": [],
"width": 8.765625,
"height": 10,
"ports": [
{
"id": "a2_enter0"
},
{
"id": "a2_exit0"
}
],
"x": 0,
"y": 0
},
{
"id": "$generated_a_initial_0",
"labels": [],
"edges": [],
"width": 4,
"height": 4,
"x": 0,
"y": 0
}
],
"ports": [
{
"id": "a_enter0"
},
{
"id": "a_exit0"
}
],
"x": 0,
"y": 0
},
{
"id": "b",
"labels": [
{
"text": "b"
}
],
"edges": [],
"width": 7,
"height": 10,
"x": 0,
"y": 0
},
{
"id": "$generated_root_initial_0",
"labels": [],
"edges": [],
"width": 4,
"height": 4,
"x": 0,
"y": 0
}
]
}
This yields the following layout:
{
"id": "root",
"labels": [
{
"text": "root"
}
],
"edges": [
{
"id": "a:0",
"source": "a",
"target": "a2",
"labels": [],
"sourcePort": "a_enter0",
"targetPort": "a2_enter0",
"sourcePoint": {
"x": 0,
"y": 38
},
"targetPoint": {
"x": 24,
"y": 38
},
"junctionPoints": []
},
{
"id": "a1:0",
"source": "a1",
"target": "b",
"labels": [
{
"text": "t",
"width": 1,
"height": 5,
"x": 59,
"y": 14
}
],
"sourcePoint": {
"x": 32,
"y": 20
},
"targetPoint": {
"x": 70,
"y": 20
},
"junctionPoints": []
},
{
"id": "$generated_a_initial_0:0",
"source": "$generated_a_initial_0",
"target": "a1",
"labels": [],
"sourcePoint": {
"x": 14,
"y": 20
},
"targetPoint": {
"x": 24,
"y": 20
},
"junctionPoints": []
},
{
"id": "$generated_root_initial_0:0",
"source": "$generated_root_initial_0",
"target": "a",
"labels": [],
"sourcePoint": {
"x": 14,
"y": 45
},
"targetPoint": {
"x": 27,
"y": 45
},
"junctionPoints": []
},
{
"id": "a_exit0_a_enter0",
"source": "a",
"target": "a",
"sourcePort": "a_exit0",
"targetPort": "a_enter0",
"labels": [
{
"text": "t",
"width": 1,
"height": 5,
"x": 10,
"y": 10
}
],
"sourcePoint": {
"x": 70,
"y": 26
},
"targetPoint": {
"x": 27,
"y": 55
},
"bendPoints": [
{
"x": 80,
"y": 26
},
{
"x": 80,
"y": 10
},
{
"x": 20,
"y": 10
},
{
"x": 20,
"y": 55
}
],
"junctionPoints": []
}
],
"width": 115,
"height": 82,
"children": [
{
"id": "a",
"labels": [
{
"text": "a"
}
],
"edges": [],
"width": 42,
"height": 55,
"children": [
{
"id": "a1",
"labels": [
{
"text": "a1"
}
],
"edges": [],
"width": 8.765625,
"height": 10,
"x": 24,
"y": 15
},
{
"id": "a2",
"labels": [
{
"text": "a2"
}
],
"edges": [],
"width": 8.765625,
"height": 10,
"ports": [
{
"id": "a2_enter0",
"x": 0,
"y": 3,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "WEST"
}
},
{
"id": "a2_exit0",
"x": 0,
"y": 6,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "WEST"
}
}
],
"x": 24,
"y": 35
},
{
"id": "$generated_a_initial_0",
"labels": [],
"edges": [],
"width": 4,
"height": 4,
"x": 10,
"y": 18
}
],
"ports": [
{
"id": "a_enter0",
"x": 0,
"y": 38,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "WEST"
}
},
{
"id": "a_exit0",
"x": 42,
"y": 10,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "EAST"
}
}
],
"x": 27,
"y": 16,
},
{
"id": "b",
"labels": [
{
"text": "b"
}
],
"edges": [],
"width": 7,
"height": 10,
"x": 98,
"y": 32
},
{
"id": "$generated_root_initial_0",
"labels": [],
"edges": [],
"width": 4,
"height": 4,
"x": 10,
"y": 43
}
],
}
Which when visualized as SVG yields:

You can see that the y attributes of the edge targeting port a_enter0
and the edge originating from port a_enter0
are misaligned.
Specifically, in screen coordinates, the y coordinate of target point of edge a:0 is 54 (16 + 38, which is coordinates of node a, plus target point of edge a:0). The y coordinate of target point of edge a_exit0_a_enter0 is 55. Therefore there is an off-by-one error on the coordinates of the port.
I was only able to reproduce this behavior when the layout yielded edges which were crossing, so I think that this might be related.
Please let me know what you think. Thank you.
Could be a bug. It shouldn't been related to the crossing but there are several places where this can go wrong.
Can you check the coordinates you mention when you set intCoordinates
to false
? I would be interested if the original positions are already integral.
Thanks by the way for the nice presentation of the issue 👍 .
Setting intCoordinates to false resolves this issue.
Can you also tell me the floating point values of the two coordinates? I'm wondering why they result in two different integers.
Here are the floating point coordinates:
{
"id": "root",
"labels": [
{
"text": "root"
}
],
"edges": [
{
"id": "a:0",
"source": "a",
"target": "a2",
"labels": [],
"sourcePort": "a_enter0",
"targetPort": "a2_enter0",
"$hyperlink": "a_exit0_a_enter0",
"sourcePoint": {
"x": 0,
"y": 38.41666666666667
},
"targetPoint": {
"x": 24,
"y": 38.41666666666667
},
"junctionPoints": []
},
{
"id": "a1:0",
"source": "a1",
"target": "b",
"labels": [
{
"text": "t",
"width": 1.109375,
"height": 4.5,
"x": 59.26562476158142,
"y": 15
}
],
"sourcePoint": {
"x": 32.765625,
"y": 20.5
},
"targetPoint": {
"x": 70.37499976158142,
"y": 20.499999999999996
},
"junctionPoints": []
},
{
"id": "$generated_a_initial_0:0",
"source": "$generated_a_initial_0",
"target": "a1",
"labels": [],
"sourcePoint": {
"x": 14,
"y": 20.5
},
"targetPoint": {
"x": 24,
"y": 20.5
},
"junctionPoints": []
},
{
"id": "$generated_root_initial_0:0",
"source": "$generated_root_initial_0",
"target": "a",
"labels": [],
"sourcePoint": {
"x": 14,
"y": 45.41666654745738
},
"targetPoint": {
"x": 27.99999976158142,
"y": 45.41666654745738
},
"junctionPoints": []
},
{
"id": "a_exit0_a_enter0",
"source": "a",
"target": "a",
"sourcePort": "a_exit0",
"targetPort": "a_enter0",
"labels": [
{
"text": "t",
"width": 1.109375,
"height": 4.5,
"x": 10,
"y": 10
}
],
"sourcePoint": {
"x": 70.76562476158142,
"y": 26.99999988079071
},
"targetPoint": {
"x": 27.99999976158142,
"y": 55.41666654745738
},
"bendPoints": [
{
"x": 80.26562464237213,
"y": 26.99999988079071
},
{
"x": 80.26562464237213,
"y": 10
},
{
"x": 20.99999988079071,
"y": 10
},
{
"x": 20.99999988079071,
"y": 55.41666654745738
}
],
"junctionPoints": []
}
],
"width": 115.37499952316284,
"height": 81.74999988079071,
"children": [
{
"id": "a",
"labels": [
{
"text": "a"
}
],
"edges": [],
"width": 42.765625,
"height": 54.75,
"children": [
{
"id": "a1",
"labels": [
{
"text": "a1"
}
],
"edges": [],
"width": 8.765625,
"height": 9.5,
"x": 24,
"y": 15.75
},
{
"id": "a2",
"labels": [
{
"text": "a2"
}
],
"edges": [],
"width": 8.765625,
"height": 9.5,
"ports": [
{
"id": "a2_enter0",
"x": 0,
"y": 3.1666666666666674,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "WEST"
}
},
{
"id": "a2_exit0",
"x": 0,
"y": 6.333333333333334,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "WEST"
}
}
],
"x": 24,
"y": 35.25
},
{
"id": "$generated_a_initial_0",
"labels": [],
"edges": [],
"width": 4,
"height": 4,
"x": 10,
"y": 18.5
}
],
"ports": [
{
"id": "a_enter0",
"x": 0,
"y": 38.41666666666667,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "WEST"
}
},
{
"id": "a_exit0",
"x": 42.765625,
"y": 10,
"width": 0,
"height": 0,
"properties": {
"de.cau.cs.kieler.portSide": "EAST"
}
}
],
"x": 27.99999976158142,
"y": 16.99999988079071,
"$H": 25
},
{
"id": "b",
"labels": [
{
"text": "b"
}
],
"edges": [],
"width": 7,
"height": 9.5,
"x": 98.37499952316284,
"y": 32.74999988079071
},
{
"id": "$generated_root_initial_0",
"labels": [],
"edges": [],
"width": 4,
"height": 4,
"x": 10,
"y": 43.41666654745738
}
]
}
Rendering:

Thank you for your help with this.
Ah I see, it's a bad idea to round the coordinates to integers if they represent relative positions that have to be added later on. We should fix this in the next version of the library.