View Javadoc

1   /*
2    * Copyright (c) 2003, the JUNG Project and the Regents of the University of
3    * California All rights reserved.
4    * 
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or http://jung.sourceforge.net/license.txt for a description.
7    * 
8    */
9   package edu.uci.ics.jung.samples;
10  
11  import java.awt.BorderLayout;
12  import java.awt.Color;
13  import java.awt.Container;
14  import java.awt.Dimension;
15  import java.awt.Graphics;
16  import java.awt.Graphics2D;
17  import java.awt.GridLayout;
18  import java.awt.Shape;
19  import java.awt.event.ActionEvent;
20  import java.awt.event.ActionListener;
21  import java.awt.event.ItemEvent;
22  import java.awt.event.ItemListener;
23  import java.awt.geom.AffineTransform;
24  import java.awt.geom.Ellipse2D;
25  import java.awt.geom.Point2D;
26  
27  import javax.swing.BorderFactory;
28  import javax.swing.JApplet;
29  import javax.swing.JButton;
30  import javax.swing.JComboBox;
31  import javax.swing.JFrame;
32  import javax.swing.JPanel;
33  import javax.swing.JRadioButton;
34  import javax.swing.JToggleButton;
35  
36  import org.apache.commons.collections15.Factory;
37  import org.apache.commons.collections15.functors.ConstantTransformer;
38  
39  import edu.uci.ics.jung.algorithms.layout.BalloonLayout;
40  import edu.uci.ics.jung.algorithms.layout.TreeLayout;
41  import edu.uci.ics.jung.graph.DirectedGraph;
42  import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
43  import edu.uci.ics.jung.graph.Forest;
44  import edu.uci.ics.jung.graph.DelegateForest;
45  import edu.uci.ics.jung.graph.DelegateTree;
46  import edu.uci.ics.jung.graph.Tree;
47  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
48  import edu.uci.ics.jung.visualization.Layer;
49  import edu.uci.ics.jung.visualization.VisualizationServer;
50  import edu.uci.ics.jung.visualization.VisualizationViewer;
51  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
52  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
53  import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
54  import edu.uci.ics.jung.visualization.control.ModalLensGraphMouse;
55  import edu.uci.ics.jung.visualization.control.ScalingControl;
56  import edu.uci.ics.jung.visualization.decorators.EdgeShape;
57  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
58  import edu.uci.ics.jung.visualization.layout.LayoutTransition;
59  import edu.uci.ics.jung.visualization.transform.LensSupport;
60  import edu.uci.ics.jung.visualization.transform.MutableTransformer;
61  import edu.uci.ics.jung.visualization.transform.MutableTransformerDecorator;
62  import edu.uci.ics.jung.visualization.transform.shape.HyperbolicShapeTransformer;
63  import edu.uci.ics.jung.visualization.transform.shape.ViewLensSupport;
64  import edu.uci.ics.jung.visualization.util.Animator;
65  
66  /**
67   * Demonstrates the visualization of a Tree using TreeLayout
68   * and BalloonLayout. An examiner lens performing a hyperbolic
69   * transformation of the view is also included.
70   * 
71   * @author Tom Nelson
72   * 
73   */
74  @SuppressWarnings("serial")
75  public class BalloonLayoutDemo extends JApplet {
76  
77      /**
78       * the graph
79       */
80  	Forest<String,Integer> graph;
81  
82  	Factory<DirectedGraph<String,Integer>> graphFactory = 
83  		new Factory<DirectedGraph<String,Integer>>() {
84  
85  		public DirectedGraph<String, Integer> create() {
86  			return new DirectedSparseMultigraph<String,Integer>();
87  		}
88  	};
89  
90  	Factory<Tree<String,Integer>> treeFactory =
91  		new Factory<Tree<String,Integer>> () {
92  
93  		public Tree<String, Integer> create() {
94  			return new DelegateTree<String,Integer>(graphFactory);
95  		}
96  	};
97  
98  	Factory<Integer> edgeFactory = new Factory<Integer>() {
99  		int i=0;
100 		public Integer create() {
101 			return i++;
102 		}};
103     
104     Factory<String> vertexFactory = new Factory<String>() {
105     	int i=0;
106 		public String create() {
107 			return "V"+i++;
108 		}};
109 
110     /**
111      * the visual component and renderer for the graph
112      */
113     VisualizationViewer<String,Integer> vv;
114     
115     VisualizationServer.Paintable rings;
116     
117     String root;
118     
119     TreeLayout<String,Integer> layout;
120     
121     BalloonLayout<String,Integer> radialLayout;
122     /**
123      * provides a Hyperbolic lens for the view
124      */
125     LensSupport hyperbolicViewSupport;
126     
127     public BalloonLayoutDemo() {
128         
129         // create a simple graph for the demo
130         graph = new DelegateForest<String,Integer>();
131 
132         createTree();
133         
134         layout = new TreeLayout<String,Integer>(graph);
135         radialLayout = new BalloonLayout<String,Integer>(graph);
136         radialLayout.setSize(new Dimension(900,900));
137         vv =  new VisualizationViewer<String,Integer>(layout, new Dimension(600,600));
138         vv.setBackground(Color.white);
139         vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
140         vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
141         // add a listener for ToolTips
142         vv.setVertexToolTipTransformer(new ToStringLabeller());
143         vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
144         rings = new Rings(radialLayout);
145         
146         Container content = getContentPane();
147         final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
148         content.add(panel);
149         
150         final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
151 
152         vv.setGraphMouse(graphMouse);
153         vv.addKeyListener(graphMouse.getModeKeyListener());
154         
155         hyperbolicViewSupport = 
156             new ViewLensSupport<String,Integer>(vv, new HyperbolicShapeTransformer(vv, 
157             		vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)), 
158                     new ModalLensGraphMouse());
159 
160 
161         graphMouse.addItemListener(hyperbolicViewSupport.getGraphMouse().getModeListener());
162 
163         JComboBox modeBox = graphMouse.getModeComboBox();
164         modeBox.addItemListener(graphMouse.getModeListener());
165         graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
166 
167         final ScalingControl scaler = new CrossoverScalingControl();
168         
169         vv.scaleToLayout(scaler);
170 
171         JButton plus = new JButton("+");
172         plus.addActionListener(new ActionListener() {
173             public void actionPerformed(ActionEvent e) {
174                 scaler.scale(vv, 1.1f, vv.getCenter());
175             }
176         });
177         JButton minus = new JButton("-");
178         minus.addActionListener(new ActionListener() {
179             public void actionPerformed(ActionEvent e) {
180                 scaler.scale(vv, 1/1.1f, vv.getCenter());
181             }
182         });
183         
184         JToggleButton radial = new JToggleButton("Balloon");
185         radial.addItemListener(new ItemListener() {
186 
187 			public void itemStateChanged(ItemEvent e) {
188 				if(e.getStateChange() == ItemEvent.SELECTED) {
189 
190 					LayoutTransition<String,Integer> lt =
191 						new LayoutTransition<String,Integer>(vv, layout, radialLayout);
192 					Animator animator = new Animator(lt);
193 					animator.start();
194 					vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).setToIdentity();
195 					vv.addPreRenderPaintable(rings);
196 				} else {
197 
198 					LayoutTransition<String,Integer> lt =
199 						new LayoutTransition<String,Integer>(vv, radialLayout, layout);
200 					Animator animator = new Animator(lt);
201 					animator.start();
202 					vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).setToIdentity();
203 					vv.removePreRenderPaintable(rings);
204 				}
205 				vv.repaint();
206 			}});
207         final JRadioButton hyperView = new JRadioButton("Hyperbolic View");
208         hyperView.addItemListener(new ItemListener(){
209             public void itemStateChanged(ItemEvent e) {
210                 hyperbolicViewSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
211             }
212         });
213 
214         JPanel scaleGrid = new JPanel(new GridLayout(1,0));
215         scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));
216 
217         JPanel controls = new JPanel();
218         scaleGrid.add(plus);
219         scaleGrid.add(minus);
220         controls.add(radial);
221         controls.add(scaleGrid);
222         controls.add(modeBox);
223         controls.add(hyperView);
224         content.add(controls, BorderLayout.SOUTH);
225     }
226     
227     class Rings implements VisualizationServer.Paintable {
228     	
229     	BalloonLayout<String,Integer> layout;
230     	
231     	public Rings(BalloonLayout<String,Integer> layout) {
232     		this.layout = layout;
233     	}
234     	
235 		public void paint(Graphics g) {
236 			g.setColor(Color.gray);
237 		
238 			Graphics2D g2d = (Graphics2D)g;
239 
240 			Ellipse2D ellipse = new Ellipse2D.Double();
241 			for(String v : layout.getGraph().getVertices()) {
242 				Double radius = layout.getRadii().get(v);
243 				if(radius == null) continue;
244 				Point2D p = layout.transform(v);
245 				ellipse.setFrame(-radius, -radius, 2*radius, 2*radius);
246 				AffineTransform at = AffineTransform.getTranslateInstance(p.getX(), p.getY());
247 				Shape shape = at.createTransformedShape(ellipse);
248 				
249 				MutableTransformer viewTransformer =
250 					vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW);
251 				
252 				if(viewTransformer instanceof MutableTransformerDecorator) {
253 					shape = vv.getRenderContext().getMultiLayerTransformer().transform(shape);
254 				} else {
255 					shape = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT,shape);
256 				}
257 
258 				g2d.draw(shape);
259 			}
260 		}
261 
262 		public boolean useTransform() {
263 			return true;
264 		}
265     }
266     
267     /**
268      * 
269      */
270     private void createTree() {
271     	
272        	graph.addVertex("A0");
273        	graph.addEdge(edgeFactory.create(), "A0", "B0");
274        	graph.addEdge(edgeFactory.create(), "A0", "B1");
275        	graph.addEdge(edgeFactory.create(), "A0", "B2");
276        	
277        	graph.addEdge(edgeFactory.create(), "B0", "C0");
278        	graph.addEdge(edgeFactory.create(), "B0", "C1");
279        	graph.addEdge(edgeFactory.create(), "B0", "C2");
280        	graph.addEdge(edgeFactory.create(), "B0", "C3");
281 
282        	graph.addEdge(edgeFactory.create(), "C2", "H0");
283        	graph.addEdge(edgeFactory.create(), "C2", "H1");
284 
285        	graph.addEdge(edgeFactory.create(), "B1", "D0");
286        	graph.addEdge(edgeFactory.create(), "B1", "D1");
287        	graph.addEdge(edgeFactory.create(), "B1", "D2");
288 
289        	graph.addEdge(edgeFactory.create(), "B2", "E0");
290        	graph.addEdge(edgeFactory.create(), "B2", "E1");
291        	graph.addEdge(edgeFactory.create(), "B2", "E2");
292 
293        	graph.addEdge(edgeFactory.create(), "D0", "F0");
294        	graph.addEdge(edgeFactory.create(), "D0", "F1");
295        	graph.addEdge(edgeFactory.create(), "D0", "F2");
296        	
297        	graph.addEdge(edgeFactory.create(), "D1", "G0");
298        	graph.addEdge(edgeFactory.create(), "D1", "G1");
299        	graph.addEdge(edgeFactory.create(), "D1", "G2");
300        	graph.addEdge(edgeFactory.create(), "D1", "G3");
301        	graph.addEdge(edgeFactory.create(), "D1", "G4");
302        	graph.addEdge(edgeFactory.create(), "D1", "G5");
303        	graph.addEdge(edgeFactory.create(), "D1", "G6");
304        	graph.addEdge(edgeFactory.create(), "D1", "G7");
305        	
306        	// uncomment this to make it a Forest:
307 //       	graph.addVertex("K0");
308 //       	graph.addEdge(edgeFactory.create(), "K0", "K1");
309 //       	graph.addEdge(edgeFactory.create(), "K0", "K2");
310 //       	graph.addEdge(edgeFactory.create(), "K0", "K3");
311 //       	
312 //       	graph.addVertex("J0");
313 //    	graph.addEdge(edgeFactory.create(), "J0", "J1");
314 //    	graph.addEdge(edgeFactory.create(), "J0", "J2");
315 //    	graph.addEdge(edgeFactory.create(), "J1", "J4");
316 //    	graph.addEdge(edgeFactory.create(), "J2", "J3");
317 ////    	graph.addEdge(edgeFactory.create(), "J2", "J5");
318 ////    	graph.addEdge(edgeFactory.create(), "J4", "J6");
319 ////    	graph.addEdge(edgeFactory.create(), "J4", "J7");
320 ////    	graph.addEdge(edgeFactory.create(), "J3", "J8");
321 ////    	graph.addEdge(edgeFactory.create(), "J6", "B9");
322 
323        	
324     }
325 
326     /**
327      * a driver for this demo
328      */
329     public static void main(String[] args) {
330         JFrame frame = new JFrame();
331         Container content = frame.getContentPane();
332         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
333 
334         content.add(new BalloonLayoutDemo());
335         frame.pack();
336         frame.setVisible(true);
337     }
338 }