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.event.ActionEvent;
18  import java.awt.event.ActionListener;
19  import java.awt.geom.AffineTransform;
20  import java.awt.geom.Point2D;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.swing.ImageIcon;
27  import javax.swing.JApplet;
28  import javax.swing.JButton;
29  import javax.swing.JFrame;
30  import javax.swing.JPanel;
31  
32  import org.apache.commons.collections15.Transformer;
33  import org.apache.commons.collections15.functors.ChainedTransformer;
34  
35  import edu.uci.ics.jung.algorithms.layout.Layout;
36  import edu.uci.ics.jung.algorithms.layout.StaticLayout;
37  import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
38  import edu.uci.ics.jung.graph.Graph;
39  import edu.uci.ics.jung.graph.util.EdgeType;
40  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
41  import edu.uci.ics.jung.visualization.Layer;
42  import edu.uci.ics.jung.visualization.VisualizationViewer;
43  import edu.uci.ics.jung.visualization.control.AbstractModalGraphMouse;
44  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
45  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
46  import edu.uci.ics.jung.visualization.control.ScalingControl;
47  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
48  import edu.uci.ics.jung.visualization.renderers.GradientVertexRenderer;
49  import edu.uci.ics.jung.visualization.renderers.Renderer;
50  import edu.uci.ics.jung.visualization.renderers.BasicVertexLabelRenderer.InsidePositioner;
51  
52  
53  /**
54   * Shows a graph overlaid on a world map image.
55   * Scaling of the graph also scales the image background.
56   * @author Tom Nelson
57   * 
58   */
59  @SuppressWarnings("serial")
60  public class WorldMapGraphDemo extends JApplet {
61  
62      /**
63       * the graph
64       */
65      Graph<String, Number> graph;
66  
67      /**
68       * the visual component and renderer for the graph
69       */
70      VisualizationViewer<String, Number> vv;
71      
72  	Map<String,String[]> map = new HashMap<String,String[]>();
73     	List<String> cityList;
74  
75  
76      
77      /**
78       * create an instance of a simple graph with controls to
79       * demo the zoom features.
80       * 
81       */
82      public WorldMapGraphDemo() {
83          setLayout(new BorderLayout());
84          
85  		map.put("TYO", new String[] {"35 40 N", "139 45 E"});
86     		map.put("PEK", new String[] {"39 55 N", "116 26 E"});
87     		map.put("MOW", new String[] {"55 45 N", "37 42 E"});
88     		map.put("JRS", new String[] {"31 47 N", "35 13 E"});
89     		map.put("CAI", new String[] {"30 03 N", "31 15 E"});
90     		map.put("CPT", new String[] {"33 55 S", "18 22 E"});
91     		map.put("PAR", new String[] {"48 52 N", "2 20 E"});
92     		map.put("LHR", new String[] {"51 30 N", "0 10 W"});
93     		map.put("HNL", new String[] {"21 18 N", "157 51 W"});
94     		map.put("NYC", new String[] {"40 77 N", "73 98 W"});
95     		map.put("SFO", new String[] {"37 62 N", "122 38 W"});
96     		map.put("AKL", new String[] {"36 55 S", "174 47 E"});
97     		map.put("BNE", new String[] {"27 28 S", "153 02 E"});
98     		map.put("HKG", new String[] {"22 15 N", "114 10 E"});
99     		map.put("KTM", new String[] {"27 42 N", "85 19 E"});
100    		map.put("IST", new String[] {"41 01 N", "28 58 E"});
101    		map.put("STO", new String[] {"59 20 N", "18 03 E"});
102    		map.put("RIO", new String[] {"22 54 S", "43 14 W"});
103    		map.put("LIM", new String[] {"12 03 S", "77 03 W"});
104    		map.put("YTO", new String[] {"43 39 N", "79 23 W"});
105 
106    		cityList = new ArrayList<String>(map.keySet());
107 
108         // create a simple graph for the demo
109         graph = new DirectedSparseMultigraph<String, Number>();
110         createVertices();
111         createEdges();
112         
113         ImageIcon mapIcon = null;
114         String imageLocation = "/images/political_world_map.jpg";
115         try {
116             mapIcon = 
117             	    new ImageIcon(getClass().getResource(imageLocation));
118         } catch(Exception ex) {
119             System.err.println("Can't load \""+imageLocation+"\"");
120         }
121         final ImageIcon icon = mapIcon;
122 
123         Dimension layoutSize = new Dimension(2000,1000);
124         
125         Layout<String,Number> layout = new StaticLayout<String,Number>(graph,
126         		new ChainedTransformer(new Transformer[]{
127         				new CityTransformer(map),
128         				new LatLonPixelTransformer(new Dimension(2000,1000))
129         		}));
130         	
131         layout.setSize(layoutSize);
132         vv =  new VisualizationViewer<String,Number>(layout,
133         		new Dimension(800,400));
134         
135         if(icon != null) {
136             vv.addPreRenderPaintable(new VisualizationViewer.Paintable(){
137                 public void paint(Graphics g) {
138                 	Graphics2D g2d = (Graphics2D)g;
139                 	AffineTransform oldXform = g2d.getTransform();
140                     AffineTransform lat = 
141                     	vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).getTransform();
142                     AffineTransform vat = 
143                     	vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).getTransform();
144                     AffineTransform at = new AffineTransform();
145                     at.concatenate(g2d.getTransform());
146                     at.concatenate(vat);
147                     at.concatenate(lat);
148                     g2d.setTransform(at);
149                     g.drawImage(icon.getImage(), 0, 0,
150                     		icon.getIconWidth(),icon.getIconHeight(),vv);
151                     g2d.setTransform(oldXform);
152                 }
153                 public boolean useTransform() { return false; }
154             });
155         }
156 
157         vv.getRenderer().setVertexRenderer(
158         		new GradientVertexRenderer<String,Number>(
159         				Color.white, Color.red, 
160         				Color.white, Color.blue,
161         				vv.getPickedVertexState(),
162         				false));
163         
164         // add my listeners for ToolTips
165         vv.setVertexToolTipTransformer(new ToStringLabeller());
166         vv.setEdgeToolTipTransformer(new Transformer<Number,String>() {
167 			public String transform(Number edge) {
168 				return "E"+graph.getEndpoints(edge).toString();
169 			}});
170         
171         vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
172         vv.getRenderer().getVertexLabelRenderer().setPositioner(new InsidePositioner());
173         vv.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.AUTO);
174         
175         final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
176         add(panel);
177         final AbstractModalGraphMouse graphMouse = new DefaultModalGraphMouse();
178         vv.setGraphMouse(graphMouse);
179         
180         vv.addKeyListener(graphMouse.getModeKeyListener());
181         vv.setToolTipText("<html><center>Type 'p' for Pick mode<p>Type 't' for Transform mode");
182         
183         final ScalingControl scaler = new CrossoverScalingControl();
184         
185 //        vv.scaleToLayout(scaler);
186 
187 
188         JButton plus = new JButton("+");
189         plus.addActionListener(new ActionListener() {
190             public void actionPerformed(ActionEvent e) {
191                 scaler.scale(vv, 1.1f, vv.getCenter());
192             }
193         });
194         JButton minus = new JButton("-");
195         minus.addActionListener(new ActionListener() {
196             public void actionPerformed(ActionEvent e) {
197                 scaler.scale(vv, 1/1.1f, vv.getCenter());
198             }
199         });
200 
201         JButton reset = new JButton("reset");
202         reset.addActionListener(new ActionListener() {
203 
204 			public void actionPerformed(ActionEvent e) {
205 				vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).setToIdentity();
206 				vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).setToIdentity();
207 			}});
208 
209         JPanel controls = new JPanel();
210         controls.add(plus);
211         controls.add(minus);
212         controls.add(reset);
213         add(controls, BorderLayout.SOUTH);
214     }
215     
216     /**
217      * create some vertices
218      * @param count how many to create
219      * @return the Vertices in an array
220      */
221     private void createVertices() {
222         for (String city : map.keySet()) {
223             graph.addVertex(city);
224         }
225     }
226 
227     /**
228      * create edges for this demo graph
229      * @param v an array of Vertices to connect
230      */
231     void createEdges() {
232      	
233     	for(int i=0; i<map.keySet().size()*1.3; i++) {
234     		graph.addEdge(new Double(Math.random()), randomCity(), randomCity(), EdgeType.DIRECTED);
235     	}
236     }
237     
238     private String randomCity() {
239     	int m = cityList.size();
240     	return cityList.get((int)(Math.random()*m));
241     }
242     
243     static class CityTransformer implements Transformer<String,String[]> {
244 
245     	Map<String,String[]> map;
246     	public CityTransformer(Map<String,String[]> map) {
247     		this.map = map;
248     	}
249 
250     	/**
251     	 * transform airport code to latlon string
252     	 */
253 		public String[] transform(String city) {
254 			return map.get(city);
255 		}
256     }
257     
258     static class LatLonPixelTransformer implements Transformer<String[],Point2D> {
259     	Dimension d;
260     	int startOffset;
261     	
262     	public LatLonPixelTransformer(Dimension d) {
263     		this.d = d;
264     	}
265     	/**
266     	 * transform a lat
267     	 */
268 		public Point2D transform(String[] latlon) {
269 			double latitude = 0;
270 			double longitude = 0;
271 			String[] lat = latlon[0].split(" ");
272 			String[] lon = latlon[1].split(" ");
273 			latitude = Integer.parseInt(lat[0]) + Integer.parseInt(lat[1])/60f;
274 			latitude *= d.height/180f;
275 			longitude = Integer.parseInt(lon[0]) + Integer.parseInt(lon[1])/60f;
276 			longitude *= d.width/360f;
277 			if(lat[2].equals("N")) {
278 				latitude = d.height / 2 - latitude;
279 				
280 			} else { // assume S
281 				latitude = d.height / 2 + latitude;
282 			}
283 			
284 			if(lon[2].equals("W")) {
285 				longitude = d.width / 2 - longitude;
286 				
287 			} else { // assume E
288 				longitude = d.width / 2 + longitude;
289 			}
290 			
291 			return new Point2D.Double(longitude,latitude);
292 		}
293     	
294     }
295 
296     /**
297      * a driver for this demo
298      */
299     public static void main(String[] args) {
300         // create a frome to hold the graph
301         final JFrame frame = new JFrame();
302         Container content = frame.getContentPane();
303         content.add(new WorldMapGraphDemo());
304         frame.pack();
305         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
306         frame.setVisible(true);
307     }
308 }