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.GridLayout;
16  import java.awt.Shape;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.ActionListener;
19  import java.awt.event.ItemEvent;
20  import java.awt.event.ItemListener;
21  import java.awt.geom.Point2D;
22  import java.awt.geom.Rectangle2D;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import javax.media.jai.PerspectiveTransform;
27  import javax.swing.BorderFactory;
28  import javax.swing.ButtonGroup;
29  import javax.swing.JApplet;
30  import javax.swing.JButton;
31  import javax.swing.JFrame;
32  import javax.swing.JMenuBar;
33  import javax.swing.JPanel;
34  import javax.swing.JRadioButton;
35  import javax.swing.JSlider;
36  import javax.swing.event.ChangeEvent;
37  import javax.swing.event.ChangeListener;
38  
39  import org.apache.commons.collections15.Transformer;
40  import org.apache.commons.collections15.TransformerUtils;
41  
42  import edu.uci.ics.jung.algorithms.layout.FRLayout;
43  import edu.uci.ics.jung.algorithms.layout.Layout;
44  import edu.uci.ics.jung.algorithms.layout.StaticLayout;
45  import edu.uci.ics.jung.graph.Graph;
46  import edu.uci.ics.jung.graph.SparseMultigraph;
47  import edu.uci.ics.jung.graph.util.TestGraphs;
48  import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
49  import edu.uci.ics.jung.visualization.VisualizationModel;
50  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
51  import edu.uci.ics.jung.visualization.VisualizationViewer;
52  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
53  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
54  import edu.uci.ics.jung.visualization.control.ScalingControl;
55  import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
56  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
57  import edu.uci.ics.jung.visualization.jai.PerspectiveLayoutTransformSupport;
58  import edu.uci.ics.jung.visualization.jai.PerspectiveTransformSupport;
59  import edu.uci.ics.jung.visualization.jai.PerspectiveViewTransformSupport;
60  import edu.uci.ics.jung.visualization.picking.PickedState;
61  
62  
63  /**
64   * Demonstrates the use of <code>PerspectiveTransform</code>
65   * applied to either the model (graph layout) or the view
66   * (VisualizationViewer)
67   * 
68   * @author Tom Nelson
69   * 
70   */
71  public class PerspectiveTransformerDemo extends JApplet {
72  
73      /**
74  	 * 
75  	 */
76  	private static final long serialVersionUID = -702499007038889493L;
77  
78  	/**
79       * the graph
80       */
81      Graph<String,Number> graph;
82      
83      Layout<String,Number> graphLayout;
84      
85      /**
86       * a grid shaped graph
87       */
88      Graph<String,Number> grid;
89      
90      Layout<String,Number> gridLayout;
91  
92     /**
93       * the visual component and renderer for the graph
94       */
95      VisualizationViewer<String,Number> vv;
96  
97      /**
98       * provides a Perspective transform for the view
99       */
100     PerspectiveTransformSupport viewSupport;
101     
102     /**
103      * provides a Perspective transform for the model
104      */
105     PerspectiveTransformSupport layoutSupport;
106     
107     /**
108      * create an instance of a simple graph with controls to
109      * demo the zoom and perspective features.
110      * 
111      */
112     @SuppressWarnings("serial")
113 	public PerspectiveTransformerDemo() {
114         
115         // create a simple graph for the demo
116         graph = TestGraphs.getOneComponentGraph();
117 
118         graphLayout = new FRLayout<String,Number>(graph);
119         ((FRLayout<String,Number>)graphLayout).setMaxIterations(1000);
120 
121         Dimension preferredSize = new Dimension(600,600);
122         Map<String,Point2D> map =
123             new HashMap<String,Point2D>();
124         Transformer<String,Point2D> vlf = TransformerUtils.mapTransformer(map);
125         grid = this.generateVertexGrid(map, preferredSize, 25);
126         gridLayout = new StaticLayout<String,Number>(grid, vlf, preferredSize);
127         
128         final VisualizationModel<String,Number> visualizationModel = 
129             new DefaultVisualizationModel<String,Number>(graphLayout, preferredSize);
130         vv =  new VisualizationViewer<String,Number>(visualizationModel, preferredSize);
131         PickedState<Number> pes = vv.getPickedEdgeState();
132         vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(pes, Color.black, Color.red));
133         vv.getRenderContext().setVertexShapeTransformer(new Transformer<String,Shape>() {
134 
135             public Shape transform(String v) {
136                 return new Rectangle2D.Float(-10,-10,20,20);
137             }});
138         vv.setBackground(Color.white);
139 
140         // add a listener for ToolTips
141         vv.setVertexToolTipTransformer(new ToStringLabeller<String>());
142         
143         Container content = getContentPane();
144         GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv);
145         content.add(gzsp);
146         
147         /**
148          * the regular graph mouse for the normal view
149          */
150         final DefaultModalGraphMouse<Number, Number> graphMouse = 
151             new DefaultModalGraphMouse<Number, Number>();
152 
153         vv.setGraphMouse(graphMouse);
154         
155         viewSupport = new PerspectiveViewTransformSupport<String,Number>(vv);
156         layoutSupport = new PerspectiveLayoutTransformSupport<String,Number>(vv);
157         
158         final ScalingControl scaler = new CrossoverScalingControl();
159 
160         JButton plus = new JButton("+");
161         plus.addActionListener(new ActionListener() {
162             public void actionPerformed(ActionEvent e) {
163                 scaler.scale(vv, 1.1f, vv.getCenter());
164             }
165         });
166         JButton minus = new JButton("-");
167         minus.addActionListener(new ActionListener() {
168             public void actionPerformed(ActionEvent e) {
169                 scaler.scale(vv, 0.9f, vv.getCenter());
170             }
171         });
172         final JSlider horizontalSlider = new JSlider(-120,120,0){
173 
174 			/* (non-Javadoc)
175 			 * @see javax.swing.JComponent#getPreferredSize()
176 			 */
177 			@Override
178 			public Dimension getPreferredSize() {
179 				return new Dimension(80, super.getPreferredSize().height);
180 			}
181         };
182         
183         final JSlider verticalSlider = new JSlider(-120,120,0) {
184 
185 			/* (non-Javadoc)
186 			 * @see javax.swing.JComponent#getPreferredSize()
187 			 */
188 			@Override
189 			public Dimension getPreferredSize() {
190 				return new Dimension(super.getPreferredSize().width, 80);
191 			}
192         };
193         verticalSlider.setOrientation(JSlider.VERTICAL);
194         final ChangeListener changeListener = new ChangeListener() {
195 
196 			public void stateChanged(ChangeEvent e) {
197                 int vval = -verticalSlider.getValue();
198                 int hval = horizontalSlider.getValue();
199 
200                 Dimension d = vv.getSize();
201                  PerspectiveTransform pt = null;
202                     pt = PerspectiveTransform.getQuadToQuad(
203                             vval,          hval, 
204                             d.width-vval, -hval, 
205                             d.width+vval, d.height+hval, 
206                             -vval,         d.height-hval,
207                             
208                             0, 0, 
209                             d.width, 0, 
210                             d.width, d.height, 
211                             0, d.height);
212 
213                 viewSupport.getPerspectiveTransformer().setPerspectiveTransform(pt);
214                 layoutSupport.getPerspectiveTransformer().setPerspectiveTransform(pt);
215                 vv.repaint();
216 			}};
217 		horizontalSlider.addChangeListener(changeListener);
218 		verticalSlider.addChangeListener(changeListener);
219 
220         JPanel perspectivePanel = new JPanel(new BorderLayout());
221         JPanel perspectiveCenterPanel = new JPanel(new BorderLayout());
222         perspectivePanel.setBorder(BorderFactory.createTitledBorder("Perspective Controls"));
223         final JButton center = new JButton("Center");
224         center.addActionListener(new ActionListener() {
225 
226 			public void actionPerformed(ActionEvent e) {
227 				horizontalSlider.setValue(0);
228 				verticalSlider.setValue(0);
229 			}});
230         ButtonGroup radio = new ButtonGroup();
231         JRadioButton normal = new JRadioButton("None");
232         normal.addItemListener(new ItemListener() {
233             public void itemStateChanged(ItemEvent e) {
234             	boolean selected = e.getStateChange() == ItemEvent.SELECTED;
235                 if(selected) {
236                     if(viewSupport != null) {
237                         viewSupport.deactivate();
238                     }
239                     if(layoutSupport != null) {
240                         layoutSupport.deactivate();
241                     }
242                 }
243                 center.setEnabled(!selected);
244                 horizontalSlider.setEnabled(!selected);
245                 verticalSlider.setEnabled(!selected);
246             }
247         });
248 
249         final JRadioButton perspectiveView = new JRadioButton("In View");
250         perspectiveView.addItemListener(new ItemListener(){
251             public void itemStateChanged(ItemEvent e) {
252                 viewSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
253             }
254         });
255         final JRadioButton perspectiveModel = new JRadioButton("In Layout");
256         perspectiveModel.addItemListener(new ItemListener(){
257             public void itemStateChanged(ItemEvent e) {
258                 layoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
259             }
260         });
261 
262         radio.add(normal);
263         radio.add(perspectiveModel);
264         radio.add(perspectiveView);
265         normal.setSelected(true);
266         
267         ButtonGroup graphRadio = new ButtonGroup();
268         JRadioButton graphButton = new JRadioButton("Graph");
269         graphButton.setSelected(true);
270         graphButton.addItemListener(new ItemListener() {
271 
272             public void itemStateChanged(ItemEvent e) {
273                 if(e.getStateChange() == ItemEvent.SELECTED) {
274                     visualizationModel.setGraphLayout(graphLayout);
275                     vv.repaint();
276                 }
277             }});
278         JRadioButton gridButton = new JRadioButton("Grid");
279         gridButton.addItemListener(new ItemListener() {
280 
281             public void itemStateChanged(ItemEvent e) {
282                 if(e.getStateChange() == ItemEvent.SELECTED) {
283                     visualizationModel.setGraphLayout(gridLayout);
284                     vv.repaint();
285                 }
286             }});
287         graphRadio.add(graphButton);
288         graphRadio.add(gridButton);
289         
290         JPanel modePanel = new JPanel(new GridLayout(2,1));
291         modePanel.setBorder(BorderFactory.createTitledBorder("Display"));
292         modePanel.add(graphButton);
293         modePanel.add(gridButton);
294 
295         JMenuBar menubar = new JMenuBar();
296         menubar.add(graphMouse.getModeMenu());
297         gzsp.setCorner(menubar);
298         
299         Container controls = new JPanel(new BorderLayout());
300         JPanel zoomControls = new JPanel(new GridLayout(2,1));
301         zoomControls.setBorder(BorderFactory.createTitledBorder("Zoom"));
302         JPanel perspectiveControls = new JPanel(new GridLayout(3,1));
303         zoomControls.add(plus);
304         zoomControls.add(minus);
305         perspectiveControls.add(normal);
306         perspectiveControls.add(perspectiveModel);
307         perspectiveControls.add(perspectiveView);
308         
309         controls.add(zoomControls, BorderLayout.WEST);
310         controls.add(modePanel);
311         perspectivePanel.add(perspectiveControls, BorderLayout.WEST);
312         perspectiveCenterPanel.add(horizontalSlider, BorderLayout.SOUTH);
313         perspectivePanel.add(verticalSlider, BorderLayout.EAST);
314         perspectiveCenterPanel.add(center);
315         perspectivePanel.add(perspectiveCenterPanel);
316         controls.add(perspectivePanel, BorderLayout.EAST);
317 
318         content.add(controls, BorderLayout.SOUTH);
319     }
320 
321     private Graph<String,Number> generateVertexGrid(Map<String,Point2D> map,
322             Dimension d, int interval) {
323         int count = d.width/interval * d.height/interval;
324         Graph<String,Number> graph = new SparseMultigraph<String,Number>();
325         String[] v = new String[count];
326         for(int i=0; i<count; i++) {
327             int x = interval*i;
328             int y = x / d.width * interval;
329             x %= d.width;
330             
331             Point2D location = new Point2D.Float(x, y);
332             v[i] = ""+i;
333             map.put(v[i], location);
334             graph.addVertex(v[i]);
335         }
336         return graph;
337     }
338 
339     /**
340      * a driver for this demo
341      */
342     public static void main(String[] args) {
343         JFrame f = new JFrame();
344         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
345         f.getContentPane().add(new PerspectiveTransformerDemo());
346         f.pack();
347         f.setVisible(true);
348     }
349 }