`
walnut
  • 浏览: 105158 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

jGraph 有向图自动布局解决方案

    博客分类:
  • java
阅读更多
背景:
jGraph具有相当高的交互性和自动化,是一套为图定做的组件。其主要用途是在一些需要表示图结构的应用中,比如流程图、UML、交通线路、网络等等。jGraph主要包括以下一些产品:
        JGraph - The Java Open Source Graph Drawing Component    ( Open Source )
        JGraph Layout Pro - The Java Graph Layout Solution
       JGraphpad Pro Diagram Editor Framework
    我们选择jGraph来画有向图, jGraph Layout Pro是一个对图进行布局的软件,可以提供自动布局的功能,但是目前要收费的,为了解决这个问题,我们引入了draw2d的一个算法。

大体思路:
在构建有向图的时候,同时构建两幅图:一幅是jGraph图,另一幅是draw2d的gefGraph(两幅图节点和边的数据都是一样的并且通过HashMap关联起来),利用draw2d提供的算法计算自动布局后得到的X,Y坐标然后指定jGrahp图的节点同样的坐标,实际上只画jGraph的图。

遇到问题:
1、 当有向图产生回路的时候,自动布局算法可能会报错。
2、 当这个图形不是一个整体而是好几个部分的时候,自动布局算法会报错。

解决方案:
问题1,当有指向自身边的时候只是在jGraph图中添加这一条边,在gefGraph中不加这条边,这样这条边还是可以画出来,有一种特殊情况如果某个节点只有一条指向自己的边而和其他任何节点没有联系的话在gefGraph图中就不存在该节点,当然也就不能给出该节点自动布局的坐标,这个时候我们可以手工给出这些节点的坐标,为了不和自动算出来的坐标重合而难看,我们可以让出上端的一定高度,专门留给这些特殊节点,自动布局的节点的Y坐标向下顺延。
问题2,可以选取另一种布局算法,新的布局算法是原有布局算法的子类,对于非连通的有向图,它会自动添加一些虚拟边使其连通然后计算自动布局坐标,然后再去除虚拟边。对于连通图,使用原有布局算法效果要好于使用后者,但是前者不能计算非连通的有向图,所以我们的原则是:首先尝试使用第一种布局算法,如果报错我们捕获这个异常然后调用第二种布局算法。

代码示例(全部源代码附件中有下载):
需要的jar包(全部jar包附件中有下载):
jgraph.jar  draw2d.jar  schemaeditor.jar(这个包里面有针对问题2的新的布局算法)

package test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JApplet;
import javax.swing.JScrollPane;
import javax.swing.UIManager;

import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.graph.DirectedGraph;
import org.eclipse.draw2d.graph.DirectedGraphLayout;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.Node;
import org.jgraph.JGraph;
import org.jgraph.graph.ConnectionSet;
import org.jgraph.graph.DefaultEdge;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.DefaultGraphModel;
import org.jgraph.graph.GraphConstants;
import org.jgraph.graph.GraphModel;

import test.bean.NodeBean;
import test.bean.EdgeBean;
import test.bean.UnionEdge;

import com.realpersist.gef.layout.NodeJoiningDirectedGraphLayout;

/**
 * @author walnut
 * @version 创建时间:2007-7-18
 */
public class TestGraph extends JApplet {


	public Map gefNodeMap = null;

	public Map graphNodeMap = null;

	public List edgeList = null;

	DirectedGraph directedGraph = null;

	JGraph graph = null;
	
	public TestGraph() {

	}

	public void init() {

		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		}
		graphInit();
		
		paintGraph();

	}

	private void paintGraph() {
		try {
			
			// 测试数据
			NodeBean a1=new NodeBean("a1");
			NodeBean a11=new NodeBean("a11");
			NodeBean a12=new NodeBean("a12");
			NodeBean a13=new NodeBean("a13");
			NodeBean a121=new NodeBean("a121");
			NodeBean a122=new NodeBean("a122");
			NodeBean a123=new NodeBean("a123");
			NodeBean a1231=new NodeBean("a1231");
			NodeBean a1232=new NodeBean("a1232");
			NodeBean a1233=new NodeBean("a1233");
			NodeBean a1234=new NodeBean("a1234");
			
			NodeBean b1=new NodeBean("b1");
			NodeBean b2=new NodeBean("b2");
			NodeBean c=new NodeBean("c");
			
			EdgeBean as1=new EdgeBean(a1,a11,new Long(20));
			EdgeBean as2=new EdgeBean(a1,a12,new Long(20));
			EdgeBean as3=new EdgeBean(a1,a13,new Long(20));
			EdgeBean as4=new EdgeBean(a12,a121,new Long(20));
			EdgeBean as5=new EdgeBean(a12,a122,new Long(20));
			EdgeBean as6=new EdgeBean(a12,a123,new Long(20));
			EdgeBean as7=new EdgeBean(a123,a1231,new Long(20));
			EdgeBean as8=new EdgeBean(a123,a1232,new Long(20));
			EdgeBean as9=new EdgeBean(a123,a1233,new Long(20));
			EdgeBean as10=new EdgeBean(a123,a1234,new Long(20));
			EdgeBean as11=new EdgeBean(a1232,a11,new Long(20));
			EdgeBean as12=new EdgeBean(a1233,a122,new Long(20));
			EdgeBean as13=new EdgeBean(a123,a1,new Long(20));
			// 这一条边和其他边没有连通
			EdgeBean as14=new EdgeBean(b1,b2,new Long(20));
			// 这一条边和其他边没有连通且指向自身
			EdgeBean as15=new EdgeBean(c,c,new Long(20));
			
			List edgeBeanList =new ArrayList();
			
			edgeBeanList.add(as1);
			edgeBeanList.add(as2);
			edgeBeanList.add(as3);
			edgeBeanList.add(as4);
			edgeBeanList.add(as5);
			edgeBeanList.add(as6);
			edgeBeanList.add(as7);
			edgeBeanList.add(as8);
			edgeBeanList.add(as9);
			edgeBeanList.add(as10);
			edgeBeanList.add(as11);
			edgeBeanList.add(as12);
			edgeBeanList.add(as13);
			edgeBeanList.add(as14);
			edgeBeanList.add(as15);
			
			// 解析数据,构造图
			gefNodeMap = new HashMap();
			graphNodeMap = new HashMap();
			edgeList = new ArrayList();
			directedGraph = new DirectedGraph();
			GraphModel model = new DefaultGraphModel();
			graph.setModel(model);
			Map attributes = new Hashtable();
			// Set Arrow
			Map edgeAttrib = new Hashtable();
			GraphConstants.setLineEnd(edgeAttrib, GraphConstants.ARROW_CLASSIC);
			GraphConstants.setEndFill(edgeAttrib, true);
			graph.setJumpToDefaultPort(true);
			
			if (edgeBeanList == null || edgeBeanList.size() == 0) {
				graph.repaint();
				return;
			}
			Iterator edgeBeanIt = edgeBeanList.iterator();
			while (edgeBeanIt.hasNext()) {
				EdgeBean edgeBean = (EdgeBean) edgeBeanIt.next();
				NodeBean sourceAction = edgeBean.getsourceNodeBean();
				NodeBean targetAction = edgeBean.gettargetNodeBean();
				Long ageLong = edgeBean.getStatCount();
				String edgeString = "(" + ageLong +  ")";
				addEdge(sourceAction, targetAction, 20, edgeString);
			}
			
			// 自动布局 首先用DirectedGraphLayout如果出现异常(图不是整体连通的)则采用NodeJoiningDirectedGraphLayout
			// 后者可以对非连通图进行布局坐标计算,但效果不如前者好,所以首选前者,当前者不可以处理时采用后者
			try{
				new DirectedGraphLayout().visit(directedGraph);
			}catch(Exception e1){
				new NodeJoiningDirectedGraphLayout().visit(directedGraph);
			}
			
			int self_x=50;
			int self_y=50;
			int base_y=10;
			if(graphNodeMap!=null&&gefNodeMap!=null&&graphNodeMap.size()>gefNodeMap.size()){
				base_y=self_y+GraphProp.NODE_HEIGHT;
			}
			
			// 向图中添加节点node
			Collection nodeCollection = graphNodeMap.values();
			if (nodeCollection != null) {
				Iterator nodeIterator = nodeCollection.iterator();
				if (nodeIterator != null) {
					while (nodeIterator.hasNext()) {
						DefaultGraphCell node = (DefaultGraphCell) nodeIterator.next();
						NodeBean userObject = (NodeBean) node.getUserObject();
						if (userObject == null) {
							continue;
						}
						Node gefNode = (Node) gefNodeMap.get(userObject);
						if(gefNode==null){
							// 这是因为当一个节点有一个指向自身的边的时候,我们在gefGraph中并没有计算这条边(gefGraph不能计算包含指向自己边的布局),
							// 所以当在所要画的图中该节点只有一条指向自身的边的时候,我们在gefNodeMap中就找不到相应节点了
							// 这个时候,我们手工给出该节点的 X,Y 坐标
							gefNode=new Node();
							gefNode.x=self_x;
							gefNode.y=self_y-base_y;
							self_x+=(10+GraphProp.NODE_WIDTH);
						}
						Map nodeAttrib = new Hashtable();
						GraphConstants.setBorderColor(nodeAttrib, Color.black);
						Rectangle2D Bounds = new Rectangle2D.Double(gefNode.x,gefNode.y+base_y, GraphProp.NODE_WIDTH,GraphProp.NODE_HEIGHT);
						GraphConstants.setBounds(nodeAttrib, Bounds);
						attributes.put(node, nodeAttrib);
					}// while
				}
			}
			
			// 向图中添加边
			if (edgeList == null) {
				//logger.error("edge list is null");
				return;
			}
			for (int i = 0; i < edgeList.size(); i++) {
				UnionEdge unionEdge = (UnionEdge) edgeList.get(i);
				if (unionEdge == null) {
					//logger.error("union edge is null");
					continue;
				}
				ConnectionSet cs = new ConnectionSet(unionEdge.getEdge(),unionEdge.getSourceNode().getChildAt(0), unionEdge.getTargetNode().getChildAt(0));
				Object[] cells = new Object[] { unionEdge.getEdge(),unionEdge.getSourceNode(), unionEdge.getTargetNode() };
				attributes.put(unionEdge.getEdge(), edgeAttrib);
				model.insert(cells, attributes, cs, null, null);
			}
			
			graph.repaint();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void graphInit() {

		// Construct Model and Graph
		GraphModel model = new DefaultGraphModel();
		graph = new JGraph(model);
		graph.setSelectionEnabled(true);
		
		// 显示applet
		JScrollPane scroll=new JScrollPane(graph);
		this.getContentPane().add(scroll);
		
		this.setSize(new Dimension(800, 800));

	}


	/**
	 * @param source
	 * @param target
	 */
	private void addEdge(NodeBean source, NodeBean target, int weight,String edgeString) {

		if (source == null || target == null) {
			return;
		}
		if (gefNodeMap == null) {
			gefNodeMap = new HashMap();
		}
		if (graphNodeMap == null) {
			graphNodeMap = new HashMap();
		}
		if (edgeList == null) {
			edgeList = new ArrayList();
		}
		if (directedGraph == null) {
			directedGraph = new DirectedGraph();
		}

		// 建立GEF的 node edge将来用来计算graph node的layout
		addEdgeGef(source, target,weight,edgeString);
		
		// 建立真正要用的graph的 node edge
		DefaultGraphCell sourceNode = null;
		DefaultGraphCell targetNode = null;
		sourceNode = (DefaultGraphCell) graphNodeMap.get(source);
		if (sourceNode == null) {
			sourceNode = new DefaultGraphCell(source);
			sourceNode.addPort();
			graphNodeMap.put(source, sourceNode);
		}
		targetNode = (DefaultGraphCell) graphNodeMap.get(target);
		if (targetNode == null) {
			targetNode = new DefaultGraphCell(target);
			targetNode.addPort();
			graphNodeMap.put(target, targetNode);
		}
		DefaultEdge edge = new DefaultEdge(edgeString);
		UnionEdge unionEdge = new UnionEdge();
		unionEdge.setEdge(edge);
		unionEdge.setSourceNode(sourceNode);
		unionEdge.setTargetNode(targetNode);

		edgeList.add(unionEdge);

	}

	/**
	 * @param source
	 * @param target
	 * @param weight
	 * @param edgeString
	 */
	private void addEdgeGef(NodeBean source, NodeBean target, int weight, String edgeString) {

		if(source.equals(target)){
			return;
		}
		// 建立GEF的 node edge将来用来计算graph node的layout
		Node gefSourceNode = null;
		Node gefTargetNode = null;
		gefSourceNode = (Node) gefNodeMap.get(source);
		if (gefSourceNode == null) {
			gefSourceNode = new Node();
			gefSourceNode.width = GraphProp.NODE_WIDTH;
			gefSourceNode.height = GraphProp.NODE_WIDTH;
			//gefSourceNode.setPadding(new Insets(GraphProp.NODE_TOP_PAD,GraphProp.NODE_LEFT_PAD, GraphProp.NODE_BOTTOM_PAD,GraphProp.NODE_RIGHT_PAD));
			directedGraph.nodes.add(gefSourceNode);
			gefNodeMap.put(source, gefSourceNode);
		}
		
		gefTargetNode = (Node) gefNodeMap.get(target);
		if (gefTargetNode == null) {
			gefTargetNode = new Node();
			gefTargetNode.width = GraphProp.NODE_WIDTH;
			gefTargetNode.height = GraphProp.NODE_WIDTH;
			//gefTargetNode.setPadding(new Insets(GraphProp.NODE_TOP_PAD,GraphProp.NODE_LEFT_PAD, GraphProp.NODE_BOTTOM_PAD,GraphProp.NODE_RIGHT_PAD));
			directedGraph.nodes.add(gefTargetNode);
			gefNodeMap.put(target, gefTargetNode);
		}
		
		Edge gefEdge1=null;
		try{
			gefEdge1 = new Edge(gefSourceNode, gefTargetNode);
			gefEdge1.weight = weight;
			directedGraph.edges.add(gefEdge1);
		}catch(Exception e){
			e.printStackTrace();
		}
	}

}

  • jars.rar (731.6 KB)
  • 描述: 全部jar包
  • 下载次数: 2204
  • src.rar (4 KB)
  • 描述: 源代码
  • 下载次数: 1305
分享到:
评论
9 楼 xhaopuj 2008-08-08  
请问GraphProp这个是在那个包呀?
8 楼 remainn002 2008-08-05  
打扰一下,你现在有JGraphLayout.jar包吧?
现在急需里面的一个layout算法!
7 楼 xiaoxubuaa 2008-05-27  
这个程序怎么为顶点加图标呢?
6 楼 walnut 2008-01-28  
原来在bean包中的几个类名起的不够形象化,以至于不好理解,现在改了一下命名,希望对大家的理解有帮助。
5 楼 David0446 2008-01-26  
我用这种方法绘制出来的拓扑图怎么都是一字排开的呢?
4 楼 walnut 2007-09-29  
已经添加上缺少的东西了,现在从附件中下载源代码和所有需要的jar包后,即可运行。
3 楼 Zeus 2007-09-28  
please add the following java code or jar file, thanks:
import test.bean.ActionInfo;  
import test.bean.ActionStat;  
import com.baidu.un_uba.bean.UnionEdge;

2 楼 walnut 2007-09-04  
少什么啊 ,我再给加上,请指出
1 楼 shmayl 2007-08-30  
少东西

相关推荐

    有向图自动布局-JGraph--demo

    JGraph是一个Java库,专为创建和展示有向图而设计,它提供了丰富的功能,包括自动布局算法,使得图表的展示更加清晰、易读。 JGraph的核心特性之一是其自动布局功能。自动布局能够根据图的结构和大小,智能地调整...

    jgraphx自动布局解决方案

    以上就是使用jgraphx实现有向图自动布局的基本原理和常见问题的解决方案。通过巧妙地结合jgraph、draw2d以及自定义布局算法,开发者能够创建出高效、美观的图形界面,即使面临复杂的图结构也能游刃有余。

    Java图形组件 JGraph

    总的来说,Java图形组件JGraph是一个功能强大的工具,为Java开发者提供了一套全面的解决方案,用于创建直观且交互性强的图形界面。无论你是想构建数据可视化工具、流程设计器还是其他需要图形界面的应用,JGraph都能...

    jgraph源码+例子

    2. **图形布局**:JGraph提供了一套自动布局算法,可以帮助用户自动排列图形,使其看起来更加整洁。这些布局包括树形布局、圆形布局、网格布局等,可以适应不同的应用场景。 3. **交互性**:JGraph的图形是可以交互...

    JGraph

    通过JGraph,用户可以轻松地创建各种类型的图表,包括但不限于流程图、网络图、组织结构图等。该功能主要依赖于其强大的绘图引擎,能够支持复杂的图表结构和样式定制。 ##### 2.2 图表交互(Graph Interaction) ...

    JGraph中文资料

    - 图形布局是 JGraph 的一个重要特性,它可以帮助自动调整图形元素的位置,保持图表的清晰和有序。内置的布局算法包括树形布局、圆形布局等,也可以自定义布局策略。 2. **图表互动** - 用户可以通过鼠标操作与...

    jgraph官方手册

    - **图形布局**:jgraph内置了多种自动布局算法,可以根据不同的场景选择合适的布局策略来美化图形。 - **图形分析**:利用jgraph提供的API,开发者可以进行图形的深度分析,如路径查找、连通性分析等。 - **1.3 ...

    JGraph 手册+The JGraph Tutorial

    4. **图布局**:JGraph提供了一系列预设的布局算法,如SpringLayout、TreeLayout等,手册会阐述如何选择和自定义这些布局策略。 5. **事件处理**:详细讲解用户交互,如节点拖放、边缘连接和鼠标事件的监听与处理。...

    jgraph

    用户可以点击、拖动、缩放和旋转图形,这使得jgraph在创建流程图、网络拓扑图和状态机等需要用户参与的应用中特别有用。 5. **事件处理:** jgraph允许开发者绑定自定义事件处理器,以便在用户与图形交互时执行...

    JGRAPH开发jar

    总的来说,JGRAPH是一个强大而灵活的图形库,对于需要在Java应用中构建图形界面的开发者来说,它提供了一套完整的解决方案。无论是数据分析的可视化展示,还是流程图的绘制,JGRAPH都能够满足需求,并且提供了足够的...

    Jgraph 使用手册

    3. **图形布局**:JGraph内置了多种自动布局算法,如树形布局、圆形布局、网格布局等,可以自动调整图形的结构,使其更易于理解和分析。 4. **图形分析**:除了基本的图形展示和编辑功能,JGraph还提供了图形分析...

    JGraph document

    5. **API参考**:熟悉JGraph的API文档,这将有助于解决开发过程中的具体问题。 **五、JGraph文档资源** 压缩包中的"JGraph doc"文件可能是JGraph的官方文档,包括详细的API参考、示例代码和教程,是学习和使用...

    Jgraph中文讲义

    JGraph 有多个版本,其中 JGraphX(也称为 JGraph Swing)是面向 Swing 应用程序的版本,而 JGraphT 则专注于图理论和算法。JGraph 还有一个开源社区,提供了许多扩展和示例。 **2. JGraph 的图形应用** JGraph 的...

    jgraph的jar包 zip 源代码

    JGraph广泛应用于数据可视化、流程图、网络拓扑图、uml图等场合,尤其是在需要用户交互编辑图形的软件中。例如: - **项目管理工具**:用于展示项目任务间的依赖关系。 - **数据库设计工具**:展示数据库表之间的...

    Java图形组件 JGraph.7z

    - JGraph提供了多种内置布局管理器,如层次布局(Hierarchical Layout)、圆形布局(Circular Layout)和强制导向布局(Force-Directed Layout),帮助自动调整节点的位置,使得图形更易于理解和分析。 - 开发者也...

    jgraph官方文档

    - **3.3 图形布局**:自动布局是jgraph的一大特色,它能够根据图表的内容自动生成美观的布局。这种自动化布局不仅节省了开发者的大量时间,而且还能确保图表清晰易读。 - **3.4 图形分析**:jgraph内置了一些基本的...

    JGraph小列子加jar包

    例如,它可以用于设计数据库模式、绘制UML图,或者创建流程自动化系统中的图形化工作流。 6. **扩展和定制:** JGraph不仅提供了丰富的内置功能,还允许开发者通过扩展和自定义来满足特定需求。你可以编写自己的...

    图形化开源软件jgraph

    在后台或JApplet开发中,它提供了一套完整的解决方案,帮助开发者实现直观、动态的图形展示。这款工具以其灵活性、易用性和高效性受到了广泛的认可。 ### 1. jgraph的核心特性 - **丰富的图形库**: `jgraph`提供了...

    jgraph源代码

    **正文** 标题“jgraph源代码”所提及的“jgraph”,是一个开源的图形组件库,主要用于Java Swing应用...对于希望提升Java应用视觉表现力和交互性的开发者来说,理解和使用JGraph及其扩展库是一项非常有价值的技能。

Global site tag (gtag.js) - Google Analytics