How to layout nodes once in GraphStream?

2019-07-19 16:22发布

问题:

It is possible to activate layout process in GraphStream with Viewer#enableAutoLayout(). Unfortunately, this process will tamper each user interaction like node dragging.

Is is possible to do automatic layout once and then stop?

I have tried to turn autolayout for a second and wait, but this didn't work.

package tests.graphstream;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.SingleGraph;
import org.graphstream.ui.swingViewer.View;
import org.graphstream.ui.swingViewer.Viewer;

public class Tutorial1_01 {

    private static Graph graph = new SingleGraph("Tutorial 1");

    public static class MyFrame extends JFrame {

        private static final long serialVersionUID = 8394236698316485656L;

        //private Graph graph = new MultiGraph("embedded");
        private Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
        //private Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_SWING_THREAD);
        private View view = viewer.addDefaultView(false);
        private View defaultView  = viewer.getDefaultView();

        public MyFrame() {

             setLayout(new BorderLayout());

             //add( new JScrollPane(defaultView), BorderLayout.CENTER);

             add(defaultView, BorderLayout.CENTER);

             setDefaultCloseOperation(EXIT_ON_CLOSE);

        }

    }

    public static void main(String args[]) {

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {


                MyFrame frame = new MyFrame();


                frame.setSize(320, 240);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                graph.addNode("A");
                graph.addNode("B");
                graph.addNode("C");
                graph.addEdge("AB", "A", "B");
                graph.addEdge("BC", "B", "C");
                graph.addEdge("CA", "C", "A");

                graph.addAttribute("ui.quality");
                graph.addAttribute("ui.antialias");


                frame.viewer.enableAutoLayout();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                frame.viewer.disableAutoLayout();

                //frame.view.getCamera().resetView();
            }
        });





    }
}

回答1:

One (but surely not the best) solution is to compute the layout inside your run method.

First create an instance of the layout class and plug it to the graph before modifying the graph.

Then compute the layout until some stop condition. A fix amount of iterations is a safe choice in terms of computation but may not give you good results. Instead you can iterate up until the layout stabilizes by itself (which may never happen depending on your graph...)

public void run() {
    MyFrame frame = new MyFrame();

    frame.setSize(320, 240);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    // a layout algorithm instance plugged to the graph
    Layout layout = new SpringBox(false);
    graph.addSink(layout);
    layout.addAttributeSink(graph);

    graph.addNode("A");
    graph.addNode("B");
    graph.addNode("C");
    graph.addEdge("AB", "A", "B");
    graph.addEdge("BC", "B", "C");
    graph.addEdge("CA", "C", "A");

    graph.addAttribute("ui.quality");
    graph.addAttribute("ui.antialias");

    // iterate the compute() method a number of times
    while(layout.getStabilization() < 0.9){
        layout.compute();
    }   
}