diff --git a/example/lib/layer_graphview.dart b/example/lib/layer_graphview.dart index 9c9ce81..20d11c6 100644 --- a/example/lib/layer_graphview.dart +++ b/example/lib/layer_graphview.dart @@ -51,6 +51,28 @@ class _LayeredGraphViewPageState extends State { }, ), ), + Container( + width: 100, + child: Column( + children: [ + Text('Alignment'), + DropdownButton( + value: builder.coordinateAssignment, + items: CoordinateAssignment.values.map((coordinateAssignment) { + return DropdownMenuItem( + value: coordinateAssignment, + child: Text(coordinateAssignment.name), + ); + }).toList(), + onChanged: (value) { + setState(() { + builder.coordinateAssignment = value!; + }); + }, + ), + ], + ), + ), ElevatedButton( onPressed: () { final node12 = Node.Id(r.nextInt(100)); diff --git a/example/lib/layer_graphview_json.dart b/example/lib/layer_graphview_json.dart index 9e84f7c..e368933 100644 --- a/example/lib/layer_graphview_json.dart +++ b/example/lib/layer_graphview_json.dart @@ -9,107 +9,81 @@ class LayerGraphPageFromJson extends StatefulWidget { class _LayerGraphPageFromJsonState extends State { var json = { "edges": [ - {"from": "651372822", "to": "780273411"}, - {"from": "780273411", "to": "347969226"}, - {"from": "347969226", "to": "157648240"}, - {"from": "157648240", "to": "676569359"}, - {"from": "676569359", "to": "91606809"}, - {"from": "676569359", "to": "154477528"}, - {"from": "676569359", "to": "843017499"}, - {"from": "843017499", "to": "983981562"}, - {"from": "843017499", "to": "504040588"}, - {"from": "504040588", "to": "446062329"}, - {"from": "446062329", "to": "622974985"}, - {"from": "622974985", "to": "1044667060"}, - {"from": "622974985", "to": "556331086"}, - {"from": "556331086", "to": "995470137"}, - {"from": "995470137", "to": "1056219149"}, - {"from": "1056219149", "to": "239427950"}, - {"from": "995470137", "to": "239427950"}, - {"from": "995470137", "to": "175942639"}, - {"from": "175942639", "to": "239427950"}, - {"from": "995470137", "to": "914018177"}, - {"from": "914018177", "to": "239427950"}, - {"from": "556331086", "to": "776412718"}, - {"from": "776412718", "to": "311423239"}, - {"from": "311423239", "to": "71054174"}, - {"from": "71054174", "to": "436868910"}, - {"from": "436868910", "to": "86163114"}, - {"from": "86163114", "to": "876219077"}, - {"from": "436868910", "to": "385178969"}, - {"from": "385178969", "to": "18115125"}, - {"from": "71054174", "to": "869070735"}, - {"from": "776412718", "to": "71054174"}, - {"from": "776412718", "to": "978694637"}, - {"from": "978694637", "to": "71054174"}, - {"from": "776412718", "to": "481786088"}, - {"from": "481786088", "to": "71054174"}, - {"from": "622974985", "to": "657744632"}, - {"from": "657744632", "to": "995470137"}, - {"from": "657744632", "to": "776412718"}, - {"from": "622974985", "to": "398317434"}, - {"from": "843017499", "to": "441827615"}, - {"from": "843017499", "to": "345074369"}, - {"from": "345074369", "to": "983981562"}, - {"from": "345074369", "to": "504040588"}, - {"from": "345074369", "to": "441827615"}, - {"from": "843017499", "to": "1038969179"}, - {"from": "1038969179", "to": "983981562"}, - {"from": "1038969179", "to": "504040588"}, - {"from": "1038969179", "to": "441827615"}, - {"from": "1038969179", "to": "345074369"}, - {"from": "676569359", "to": "582216004"}, - {"from": "582216004", "to": "983981562"}, - {"from": "582216004", "to": "853366903"}, - {"from": "853366903", "to": "549040211"}, - {"from": "549040211", "to": "438987595"}, - {"from": "438987595", "to": "1044667060"}, - {"from": "438987595", "to": "927647245"}, - {"from": "927647245", "to": "995470137"}, - {"from": "927647245", "to": "286211157"}, - {"from": "286211157", "to": "466182692"}, - {"from": "466182692", "to": "724424756"}, - {"from": "724424756", "to": "739317534"}, - {"from": "739317534", "to": "315526883"}, - {"from": "724424756", "to": "869070735"}, - {"from": "286211157", "to": "724424756"}, - {"from": "286211157", "to": "175042175"}, - {"from": "175042175", "to": "724424756"}, - {"from": "286211157", "to": "567113513"}, - {"from": "567113513", "to": "724424756"}, - {"from": "438987595", "to": "625227999"}, - {"from": "625227999", "to": "995470137"}, - {"from": "625227999", "to": "286211157"}, - {"from": "438987595", "to": "398317434"}, - {"from": "582216004", "to": "441827615"}, - {"from": "582216004", "to": "306330186"}, - {"from": "306330186", "to": "983981562"}, - {"from": "306330186", "to": "853366903"}, - {"from": "306330186", "to": "441827615"}, - {"from": "582216004", "to": "476307185"}, - {"from": "476307185", "to": "983981562"}, - {"from": "476307185", "to": "853366903"}, - {"from": "476307185", "to": "441827615"}, - {"from": "157648240", "to": "1031140514"}, - {"from": "1031140514", "to": "983981562"}, - {"from": "1031140514", "to": "329379632"}, - {"from": "1031140514", "to": "441827615"}, - {"from": "1031140514", "to": "722519336"}, - {"from": "722519336", "to": "983981562"}, - {"from": "722519336", "to": "329379632"}, - {"from": "722519336", "to": "441827615"}, - {"from": "722519336", "to": "431136131"}, - {"from": "431136131", "to": "329379632"}, - {"from": "1031140514", "to": "431136131"}, - {"from": "347969226", "to": "91606809"}, - {"from": "347969226", "to": "154477528"}, - {"from": "347969226", "to": "843017499"}, - {"from": "347969226", "to": "582216004"}, - {"from": "780273411", "to": "383221931"} - ], + { + "from": "254022114", + "to": "435737192" + }, + { + "from": "102061118", + "to": "435737192" + }, + { + "from": "864374573", + "to": "676874082" + }, + { + "from": "564905731", + "to": "864374573" + }, + { + "from": "435737192", + "to": "864374573" + }, + { + "from": "435737192", + "to": "183014792" + }, + { + "from": "435737192", + "to": "222855694" + }, + { + "from": "864342115", + "to": "652678503" + }, + { + "from": "864342115", + "to": "469600377" + }, + { + "from": "676874082", + "to": "684761235" + }, + { + "from": "864374573", + "to": "864342115" + }, + { + "from": "564905731", + "to": "176177853" + }, + { + "from": "564905731", + "to": "983393593" + }, + { + "from": "564905731", + "to": "818531897" + }, + { + "from": "584192116", + "to": "102061118" + }, + { + "from": "598554018", + "to": "102061118" + }, + { + "from": "207392962", + "to": "584192116" + }, + { + "from": "161904647", + "to": "598554018" + } + ] }; - @override Widget build(BuildContext context) { return Scaffold( @@ -152,6 +126,28 @@ class _LayerGraphPageFromJsonState extends State { }, ), ), + Container( + width: 100, + child: Column( + children: [ + Text('Alignment'), + DropdownButton( + value: builder.coordinateAssignment, + items: CoordinateAssignment.values.map((coordinateAssignment) { + return DropdownMenuItem( + value: coordinateAssignment, + child: Text(coordinateAssignment.name), + ); + }).toList(), + onChanged: (value) { + setState(() { + builder.coordinateAssignment = value!; + }); + }, + ), + ], + ), + ), ], ), Expanded( diff --git a/lib/layered/SugiyamaAlgorithm.dart b/lib/layered/SugiyamaAlgorithm.dart index 434d858..8e2a649 100644 --- a/lib/layered/SugiyamaAlgorithm.dart +++ b/lib/layered/SugiyamaAlgorithm.dart @@ -442,75 +442,94 @@ class SugiyamaAlgorithm extends Algorithm { void balance(List> x, List> blockWidth) { final coordinates = {}; - var minWidth = double.infinity; - var smallestWidthLayout = 0; - final minArray = List.filled(4, 0.0); - final maxArray = List.filled(4, 0.0); - var minSmallestWidthLayout = double.infinity; - var maxSmallestWidthLayout = 0.0; + switch (configuration.coordinateAssignment) { + case CoordinateAssignment.Average: + var minWidth = double.infinity; - // Get the layout with the smallest width and set minimum and maximum value for each direction; - for (var i = 0; i < 4; i++) { - minArray[i] = double.infinity; - maxArray[i] = 0; - - graph.nodes.forEach((v) { - final bw = 0.5 * blockWidth[i][v]!; - var xp = x[i][v]! - bw; - if (xp < minArray[i]) { - minArray[i] = xp; - } - xp = x[i][v]! + bw; - if (xp > maxArray[i]) { - maxArray[i] = xp; - } - }); + var smallestWidthLayout = 0; + final minArray = List.filled(4, 0.0); + final maxArray = List.filled(4, 0.0); - final width = maxArray[i] - minArray[i]; - if (width < minWidth) { - minWidth = width; - smallestWidthLayout = i; + // Get the layout with the smallest width and set minimum and maximum value for each direction; + for (var i = 0; i < 4; i++) { + minArray[i] = double.infinity; + maxArray[i] = 0; - // Cache the values for the smallest width layout - minSmallestWidthLayout = minArray[i]; - maxSmallestWidthLayout = maxArray[i]; - } - } + graph.nodes.forEach((v) { + final bw = 0.5 * blockWidth[i][v]!; + var xp = x[i][v]! - bw; + if (xp < minArray[i]) { + minArray[i] = xp; + } + xp = x[i][v]! + bw; + if (xp > maxArray[i]) { + maxArray[i] = xp; + } + }); - // Align the layouts to the one with the smallest width - for (var layout = 0; layout < 4; layout++) { - if (layout != smallestWidthLayout) { - // Align the left to right layouts to the left border of the smallest layout - var diff = 0.0; - if (layout < 2) { - diff = minArray[layout] - minSmallestWidthLayout; - } else { - // Align the right to left layouts to the right border of the smallest layout - diff = maxArray[layout] - maxSmallestWidthLayout; + final width = maxArray[i] - minArray[i]; + if (width < minWidth) { + minWidth = width; + smallestWidthLayout = i; + } } - if (diff > 0) { - x[layout].keys.forEach((n) { - x[layout][n] = x[layout][n]! - diff; - }); - } else { - x[layout].keys.forEach((n) { - x[layout][n] = x[layout][n]! + diff; - }); + + // Align the layouts to the one with the smallest width + for (var layout = 0; layout < 4; layout++) { + if (layout != smallestWidthLayout) { + // Align the left to right layouts to the left border of the smallest layout + var diff = 0.0; + if (layout < 2) { + diff = minArray[layout] - minArray[smallestWidthLayout]; + } else { + // Align the right to left layouts to the right border of the smallest layout + diff = maxArray[layout] - maxArray[smallestWidthLayout]; + } + if (diff > 0) { + x[layout].keys.forEach((n) { + x[layout][n] = x[layout][n]! - diff; + }); + } else { + x[layout].keys.forEach((n) { + x[layout][n] = x[layout][n]! + diff; + }); + } + } } - } - } - // Get the average median of each coordinate - var values = List.filled(4, 0.0); - graph.nodes.forEach((n) { - for (var i = 0; i < 4; i++) { - values[i] = x[i][n]!; - } - values.sort(); - var average = (values[1] + values[2]) * 0.5; - coordinates[n] = average; - }); + // Get the average median of each coordinate + var values = List.filled(4, 0.0); + graph.nodes.forEach((n) { + for (var i = 0; i < 4; i++) { + values[i] = x[i][n]!; + } + values.sort(); + var average = (values[1] + values[2]) * 0.5; + coordinates[n] = average; + }); + break; + case CoordinateAssignment.DownRight: + graph.nodes.forEach((n) { + coordinates[n] = x[0][n] ?? 0.0; + }); + break; + case CoordinateAssignment.DownLeft: + graph.nodes.forEach((n) { + coordinates[n] = x[1][n] ?? 0.0; + }); + break; + case CoordinateAssignment.UpRight: + graph.nodes.forEach((n) { + coordinates[n] = x[2][n] ?? 0.0; + }); + break; + case CoordinateAssignment.UpLeft: + graph.nodes.forEach((n) { + coordinates[n] = x[3][n] ?? 0.0; + }); + break; + } // Get the minimum coordinate value var minValue = coordinates.values.reduce(min); diff --git a/lib/layered/SugiyamaConfiguration.dart b/lib/layered/SugiyamaConfiguration.dart index 1d035f5..0bcc442 100644 --- a/lib/layered/SugiyamaConfiguration.dart +++ b/lib/layered/SugiyamaConfiguration.dart @@ -16,6 +16,7 @@ class SugiyamaConfiguration { int orientation = DEFAULT_ORIENTATION; int iterations = DEFAULT_ITERATIONS; BendPointShape bendPointShape = SharpBendPointShape(); + CoordinateAssignment coordinateAssignment = CoordinateAssignment.Average; int getLevelSeparation() { return levelSeparation; @@ -30,6 +31,14 @@ class SugiyamaConfiguration { } } +enum CoordinateAssignment { + DownRight, // 0 + DownLeft, // 1 + UpRight, // 2 + UpLeft, // 3 + Average, // 4 +} + abstract class BendPointShape {} class SharpBendPointShape extends BendPointShape {}