如何在JUNG图中强制执行自定义布局?

时间:2012-11-16 01:13:59

标签: java swing jung

我有以下三组整数:

set0 = {1} //this will always be a singleton set.
set1 = {2, 3, 4, 5}
set2 = {6, 7}

我的图形具有从set1到set2或set2到set3的边,从而形成一个清晰的树状顶点层次结构。

 Set0 -- Set1  -- Set2

要显示此树状图表,我创建了DelegateForestTreeLayout

package Test;

import java.util.HashSet;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JPanel;

import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import edu.uci.ics.jung.graph.DelegateForest;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

class Main{
    public static void main(String[] args){

    Set<Integer> set0 = new HashSet<Integer>();
    Set<Integer> set1 = new HashSet<Integer>();
    Set<Integer> set2 = new HashSet<Integer>();

    set0.add(1);

    set1.add(2);
    set1.add(3);
    set1.add(4);
    set1.add(5);

    set2.add(6);
    set2.add(7);

    JFrame frame = new JFrame();
    frame.add(createGraphPanel(set0, set1, set2));
    frame.pack();
    frame.setVisible(true);


    }

    private static JPanel createGraphPanel( Set<Integer> setZero, Set<Integer> firstSet, Set<Integer> secondSet) {
            // create a graph
            Graph<Integer, String> graph = new DelegateForest<Integer, String>();

                Integer vertex1 = setZero.iterator().next();
            for (Integer i : firstSet) {
                graph.addEdge(vertex1+"-"+i, vertex1, i);
            }

            Layout<Integer, String> layout = new TreeLayout<Integer, String>((Forest<Integer, String>) graph);
            VisualizationViewer<Integer, String> vv = new  VisualizationViewer<Integer,String>(layout);

            vv.getRenderContext().setVertexLabelTransformer(
                    new ToStringLabeller<Integer>());

            return vv;
        }
    }

但是,我得到的图表(目前只包含set1和set2)看起来像这样 enter image description here

我想对此图做一些事情:

  1. 我希望它们从左到右流动,而不是从上到下流动的节点。 (像将它旋转90度一样)
  2. 目前,布局算法确保没有重叠,以线性方式扩展set2的节点。如果set2很大,它将超出面板的范围。我不介意重叠,并希望这些节点作为一个允许部分重叠的集群出现在一起。
  3. 我如何达到这两项要求?

2 个答案:

答案 0 :(得分:2)

回答问题(1):有一个演示(L2RTreeLayoutDemo)可以做到这一点。

回答问题(2):改变布局中的x和/或y间距;这可以在构造函数中设置。

答案 1 :(得分:0)

我扩展了TreeLayout类并交换了所有x / y变量。这应该水平显示树。但是,您必须添加自己的代码以防止将顶点放在一行中(可能使用边界框并在经过它后从顶部开始)。

public class HorizontalOverlappingTreeLayout<V, E> extends TreeLayout<V, E> {

    public static void main(String[] args) {
        Set<Integer> set0 = new HashSet<Integer>();
        Set<Integer> set1 = new HashSet<Integer>();
        Set<Integer> set2 = new HashSet<Integer>();
        set0.add(1);
        set1.add(2);
        set1.add(3);
        set1.add(4);
        set1.add(5);
        set2.add(6);
        set2.add(7);

        JPanel panel = new JPanel();
        Graph<Integer, String> graph = new DelegateForest<Integer, String>();
        Integer vertex1 = set0.iterator().next();
        for (Integer i : set1) {
            graph.addEdge(vertex1 + "-" + i, vertex1, i);
        }

        Layout<Integer, String> layout = new HorizontalOverlappingTreeLayout<Integer, String>(
                (Forest<Integer, String>) graph);
        VisualizationViewer<Integer, String> vv = new VisualizationViewer<Integer, String>(layout);
        vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Integer>());
        panel.add(vv);

        JFrame frame = new JFrame();
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public HorizontalOverlappingTreeLayout(Forest<V, E> g) {
        super(g);
    }

    @Override
    protected void buildTree() {
        this.m_currentPoint = new Point(0, 20);
        Collection<V> roots = TreeUtils.getRoots(graph);
        if (roots.size() > 0 && graph != null) {
            calculateDimensionY(roots);
            for (V v : roots) {
                calculateDimensionY(v);
                m_currentPoint.y += this.basePositions.get(v) / 2 + this.distY;
                buildTree(v, this.m_currentPoint.y);
            }
        }
        // TODO: removed code here
    }

    @Override
    protected void buildTree(V v, int y) {
        if (!alreadyDone.contains(v)) {
            alreadyDone.add(v);

            // go one level further down
            this.m_currentPoint.x += this.distX;
            this.m_currentPoint.y = y;

            this.setCurrentPositionFor(v);

            int sizeYofCurrent = basePositions.get(v);

            int lastY = y - sizeYofCurrent / 2;

            int sizeYofChild;
            int startYofChild;

            for (V element : graph.getSuccessors(v)) {
                sizeYofChild = this.basePositions.get(element);
                startYofChild = lastY + sizeYofChild / 2;
                buildTree(element, startYofChild);
                lastY = lastY + sizeYofChild + distY;
            }
            this.m_currentPoint.x -= this.distX;
        }
    }

    private int calculateDimensionY(V v) {
        int size = 0;
        int childrenNum = graph.getSuccessors(v).size();

        if (childrenNum != 0) {
            for (V element : graph.getSuccessors(v)) {
                size += calculateDimensionY(element) + distY;
            }
        }
        size = Math.max(0, size - distY);
        basePositions.put(v, size);

        return size;
    }

    private int calculateDimensionY(Collection<V> roots) {
        int size = 0;
        for (V v : roots) {
            int childrenNum = graph.getSuccessors(v).size();

            if (childrenNum != 0) {
                for (V element : graph.getSuccessors(v)) {
                    size += calculateDimensionY(element) + distY;
                }
            }
            size = Math.max(0, size - distY);
            basePositions.put(v, size);
        }

        return size;
    }

}