1
2
3
4
5
6
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.Font;
16 import java.awt.FontMetrics;
17 import java.awt.Graphics;
18 import java.awt.GridLayout;
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.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.Icon;
30 import javax.swing.ImageIcon;
31 import javax.swing.JApplet;
32 import javax.swing.JButton;
33 import javax.swing.JCheckBox;
34 import javax.swing.JFrame;
35 import javax.swing.JMenu;
36 import javax.swing.JMenuBar;
37 import javax.swing.JPanel;
38 import javax.swing.JRadioButton;
39 import javax.swing.JSlider;
40 import javax.swing.event.ChangeEvent;
41 import javax.swing.event.ChangeListener;
42
43 import org.apache.commons.collections15.Transformer;
44
45 import edu.uci.ics.jung.algorithms.layout.FRLayout;
46 import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
47 import edu.uci.ics.jung.graph.Graph;
48 import edu.uci.ics.jung.graph.util.EdgeType;
49 import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
50 import edu.uci.ics.jung.visualization.LayeredIcon;
51 import edu.uci.ics.jung.visualization.VisualizationServer;
52 import edu.uci.ics.jung.visualization.VisualizationViewer;
53 import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
54 import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
55 import edu.uci.ics.jung.visualization.control.ScalingControl;
56 import edu.uci.ics.jung.visualization.decorators.DefaultVertexIconTransformer;
57 import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
58 import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
59 import edu.uci.ics.jung.visualization.decorators.VertexIconShapeTransformer;
60 import edu.uci.ics.jung.visualization.jai.PerspectiveImageLensSupport;
61 import edu.uci.ics.jung.visualization.jai.PerspectiveLayoutTransformSupport;
62 import edu.uci.ics.jung.visualization.jai.PerspectiveTransformSupport;
63 import edu.uci.ics.jung.visualization.picking.PickedState;
64 import edu.uci.ics.jung.visualization.renderers.Checkmark;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 public class PerspectiveVertexImageShaperDemo extends JApplet {
88
89
90
91
92 private static final long serialVersionUID = -1943329822820885759L;
93
94
95
96
97 Graph<Number,Number> graph;
98
99
100
101
102 VisualizationViewer<Number,Number> vv;
103
104
105
106
107 String[] iconNames = {
108 "apple",
109 "os",
110 "x",
111 "linux",
112 "inputdevices",
113 "wireless",
114 "graphics3",
115 "gamespcgames",
116 "humor",
117 "music",
118 "privacy"
119 };
120
121 PerspectiveTransformSupport viewSupport;
122 PerspectiveTransformSupport layoutSupport;
123
124
125
126
127
128 @SuppressWarnings("serial")
129 public PerspectiveVertexImageShaperDemo() {
130
131
132 graph = new DirectedSparseMultigraph<Number,Number>();
133 Number[] vertices = createVertices(11);
134
135
136 Map<Number,String> map = new HashMap<Number,String>();
137 for(int i=0; i<vertices.length; i++) {
138 map.put(vertices[i], iconNames[i%iconNames.length]);
139 }
140
141
142 Map<Number,Icon> iconMap = new HashMap<Number,Icon>();
143 for(int i=0; i<vertices.length; i++) {
144 String name = "/images/topic"+iconNames[i]+".gif";
145 try {
146 Icon icon =
147 new LayeredIcon(new ImageIcon(PerspectiveVertexImageShaperDemo.class.getResource(name)).getImage());
148 iconMap.put(vertices[i], icon);
149 } catch(Exception ex) {
150 System.err.println("You need slashdoticons.jar in your classpath to see the image "+name);
151 }
152 }
153
154 createEdges(vertices);
155
156 final VertexStringerImpl<Number> vertexStringerImpl =
157 new VertexStringerImpl<Number>(map);
158
159 final VertexIconShapeTransformer<Number> vertexImageShapeFunction =
160 new VertexIconShapeTransformer<Number>(new EllipseVertexShapeTransformer<Number>());
161
162 FRLayout<Number,Number> layout = new FRLayout<Number,Number>(graph);
163 layout.setMaxIterations(100);
164 vv = new VisualizationViewer<Number,Number>(layout, new Dimension(400,400));
165
166 vv.setBackground(Color.decode("0xffffdd"));
167 final DefaultVertexIconTransformer<Number> vertexIconFunction =
168 new DefaultVertexIconTransformer<Number>();
169 vertexImageShapeFunction.setIconMap(iconMap);
170 vertexIconFunction.setIconMap(iconMap);
171 vv.getRenderContext().setVertexShapeTransformer(vertexImageShapeFunction);
172 vv.getRenderContext().setVertexIconTransformer(vertexIconFunction);
173 vv.getRenderContext().setVertexLabelTransformer(vertexStringerImpl);
174 PickedState<Number> ps = vv.getPickedVertexState();
175 ps.addItemListener(new PickWithIconListener(vertexIconFunction));
176
177
178 vv.addPostRenderPaintable(new VisualizationServer.Paintable(){
179 int x;
180 int y;
181 Font font;
182 FontMetrics metrics;
183 int swidth;
184 int sheight;
185 String str = "Thank You, slashdot.org, for the images!";
186
187 public void paint(Graphics g) {
188 Dimension d = vv.getSize();
189 if(font == null) {
190 font = new Font(g.getFont().getName(), Font.BOLD, 20);
191 metrics = g.getFontMetrics(font);
192 swidth = metrics.stringWidth(str);
193 sheight = metrics.getMaxAscent()+metrics.getMaxDescent();
194 x = (d.width-swidth)/2;
195 y = (int)(d.height-sheight*1.5);
196 }
197 g.setFont(font);
198 Color oldColor = g.getColor();
199 g.setColor(Color.lightGray);
200 g.drawString(str, x, y);
201 g.setColor(oldColor);
202 }
203 public boolean useTransform() {
204 return false;
205 }
206 });
207
208
209 vv.setVertexToolTipTransformer(new ToStringLabeller<Number>());
210
211 Container content = getContentPane();
212 final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
213 content.add(panel);
214
215 final DefaultModalGraphMouse<Number, Number> graphMouse =
216 new DefaultModalGraphMouse<Number, Number>();
217
218 vv.setGraphMouse(graphMouse);
219
220 this.viewSupport = new PerspectiveImageLensSupport<Number,Number>(vv);
221 this.layoutSupport = new PerspectiveLayoutTransformSupport<Number,Number>(vv);
222
223 final ScalingControl scaler = new CrossoverScalingControl();
224
225 JButton plus = new JButton("+");
226 plus.addActionListener(new ActionListener() {
227 public void actionPerformed(ActionEvent e) {
228 scaler.scale(vv, 1.1f, vv.getCenter());
229 }
230 });
231 JButton minus = new JButton("-");
232 minus.addActionListener(new ActionListener() {
233 public void actionPerformed(ActionEvent e) {
234 scaler.scale(vv, 0.9f, vv.getCenter());
235 }
236 });
237 final JSlider horizontalSlider = new JSlider(-120,120,0){
238
239
240
241
242 @Override
243 public Dimension getPreferredSize() {
244 return new Dimension(80, super.getPreferredSize().height);
245 }
246 };
247
248 final JSlider verticalSlider = new JSlider(-120,120,0) {
249
250
251
252
253 @Override
254 public Dimension getPreferredSize() {
255 return new Dimension(super.getPreferredSize().width, 80);
256 }
257 };
258 verticalSlider.setOrientation(JSlider.VERTICAL);
259 final ChangeListener changeListener = new ChangeListener() {
260
261 public void stateChanged(ChangeEvent e) {
262 int vval = -verticalSlider.getValue();
263 int hval = horizontalSlider.getValue();
264
265 Dimension d = vv.getSize();
266 PerspectiveTransform pt = null;
267 pt = PerspectiveTransform.getQuadToQuad(
268 vval, hval,
269 d.width-vval, -hval,
270 d.width+vval, d.height+hval,
271 -vval, d.height-hval,
272
273 0, 0,
274 d.width, 0,
275 d.width, d.height,
276 0, d.height);
277
278 viewSupport.getPerspectiveTransformer().setPerspectiveTransform(pt);
279 layoutSupport.getPerspectiveTransformer().setPerspectiveTransform(pt);
280 vv.repaint();
281 }};
282 horizontalSlider.addChangeListener(changeListener);
283 verticalSlider.addChangeListener(changeListener);
284
285
286 JPanel perspectivePanel = new JPanel(new BorderLayout());
287 JPanel perspectiveCenterPanel = new JPanel(new BorderLayout());
288 perspectivePanel.setBorder(BorderFactory.createTitledBorder("Perspective Controls"));
289 final JButton center = new JButton("Center");
290 center.addActionListener(new ActionListener() {
291
292 public void actionPerformed(ActionEvent e) {
293 horizontalSlider.setValue(0);
294 verticalSlider.setValue(0);
295 }});
296
297 final JCheckBox noText = new JCheckBox("No Text");
298 noText.addItemListener(new ItemListener(){
299
300 public void itemStateChanged(ItemEvent e) {
301 JCheckBox cb = (JCheckBox)e.getSource();
302 vertexStringerImpl.setEnabled(!cb.isSelected());
303 vv.repaint();
304 }
305 });
306 JPanel centerPanel = new JPanel();
307 centerPanel.add(noText);
308
309 ButtonGroup radio = new ButtonGroup();
310 JRadioButton none = new JRadioButton("None");
311 none.addItemListener(new ItemListener(){
312 public void itemStateChanged(ItemEvent e) {
313 boolean selected = e.getStateChange() == ItemEvent.SELECTED;
314 if(selected) {
315 if(viewSupport != null) {
316 viewSupport.deactivate();
317 }
318 if(layoutSupport != null) {
319 layoutSupport.deactivate();
320 }
321 }
322 center.setEnabled(!selected);
323 horizontalSlider.setEnabled(!selected);
324 verticalSlider.setEnabled(!selected);
325 }
326 });
327 none.setSelected(true);
328
329 JRadioButton hyperView = new JRadioButton("View");
330 hyperView.addItemListener(new ItemListener(){
331 public void itemStateChanged(ItemEvent e) {
332 viewSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
333 }
334 });
335
336 JRadioButton hyperModel = new JRadioButton("Layout");
337 hyperModel.addItemListener(new ItemListener(){
338 public void itemStateChanged(ItemEvent e) {
339 layoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
340 }
341 });
342 radio.add(none);
343 radio.add(hyperView);
344 radio.add(hyperModel);
345
346 JMenuBar menubar = new JMenuBar();
347 JMenu modeMenu = graphMouse.getModeMenu();
348 menubar.add(modeMenu);
349
350 panel.setCorner(menubar);
351
352 JPanel scaleGrid = new JPanel(new GridLayout(2,0));
353 scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));
354 JPanel controls = new JPanel(new BorderLayout());
355 scaleGrid.add(plus);
356 scaleGrid.add(minus);
357 controls.add(scaleGrid, BorderLayout.WEST);
358
359 JPanel lensPanel = new JPanel(new GridLayout(2,0));
360 lensPanel.add(none);
361 lensPanel.add(hyperView);
362 lensPanel.add(hyperModel);
363
364 perspectivePanel.add(lensPanel, BorderLayout.WEST);
365 perspectiveCenterPanel.add(horizontalSlider, BorderLayout.SOUTH);
366 perspectivePanel.add(verticalSlider, BorderLayout.EAST);
367 perspectiveCenterPanel.add(center);
368 perspectivePanel.add(perspectiveCenterPanel);
369 controls.add(perspectivePanel, BorderLayout.EAST);
370
371
372 controls.add(centerPanel);
373 content.add(controls, BorderLayout.SOUTH);
374 }
375
376
377
378
379
380
381
382
383
384 class VertexStringerImpl<V> implements Transformer<V,String> {
385
386 Map<V,String> map = new HashMap<V,String>();
387
388 boolean enabled = true;
389
390 public VertexStringerImpl(Map<V,String> map) {
391 this.map = map;
392 }
393
394 public String transform(Object v) {
395 if(isEnabled()) {
396 return map.get(v);
397 } else {
398 return "";
399 }
400 }
401
402
403
404
405 public boolean isEnabled() {
406 return enabled;
407 }
408
409
410
411
412 public void setEnabled(boolean enabled) {
413 this.enabled = enabled;
414 }
415 }
416
417
418
419
420
421
422 private Number[] createVertices(int count) {
423 Number[] v = new Number[count];
424 for (int i = 0; i < count; i++) {
425 v[i] = new Integer(i);
426 graph.addVertex(v[i]);
427 }
428 return v;
429 }
430
431
432
433
434
435 void createEdges(Number[] v) {
436 graph.addEdge(new Double(Math.random()), v[0], v[1], EdgeType.DIRECTED);
437 graph.addEdge(new Double(Math.random()), v[3], v[0], EdgeType.DIRECTED);
438 graph.addEdge(new Double(Math.random()), v[0], v[4], EdgeType.DIRECTED);
439 graph.addEdge(new Double(Math.random()), v[4], v[5], EdgeType.DIRECTED);
440 graph.addEdge(new Double(Math.random()), v[5], v[3], EdgeType.DIRECTED);
441 graph.addEdge(new Double(Math.random()), v[2], v[1], EdgeType.DIRECTED);
442 graph.addEdge(new Double(Math.random()), v[4], v[1], EdgeType.DIRECTED);
443 graph.addEdge(new Double(Math.random()), v[8], v[2], EdgeType.DIRECTED);
444 graph.addEdge(new Double(Math.random()), v[3], v[8], EdgeType.DIRECTED);
445 graph.addEdge(new Double(Math.random()), v[6], v[7], EdgeType.DIRECTED);
446 graph.addEdge(new Double(Math.random()), v[7], v[5], EdgeType.DIRECTED);
447 graph.addEdge(new Double(Math.random()), v[0], v[9], EdgeType.DIRECTED);
448 graph.addEdge(new Double(Math.random()), v[9], v[8], EdgeType.DIRECTED);
449 graph.addEdge(new Double(Math.random()), v[7], v[6], EdgeType.DIRECTED);
450 graph.addEdge(new Double(Math.random()), v[6], v[5], EdgeType.DIRECTED);
451 graph.addEdge(new Double(Math.random()), v[4], v[2], EdgeType.DIRECTED);
452 graph.addEdge(new Double(Math.random()), v[5], v[4], EdgeType.DIRECTED);
453 graph.addEdge(new Double(Math.random()), v[4], v[10], EdgeType.DIRECTED);
454 graph.addEdge(new Double(Math.random()), v[10], v[4], EdgeType.DIRECTED);
455 }
456
457 public static class PickWithIconListener implements ItemListener {
458 DefaultVertexIconTransformer<Number> imager;
459 Icon checked;
460
461 public PickWithIconListener(DefaultVertexIconTransformer<Number> imager) {
462 this.imager = imager;
463 checked = new Checkmark(Color.red);
464 }
465
466 public void itemStateChanged(ItemEvent e) {
467 Icon icon = imager.transform((Number)e.getItem());
468 if(icon != null && icon instanceof LayeredIcon) {
469 if(e.getStateChange() == ItemEvent.SELECTED) {
470 ((LayeredIcon)icon).add(checked);
471 } else {
472 ((LayeredIcon)icon).remove(checked);
473 }
474 }
475 }
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566 public static void main(String[] args) {
567 JFrame frame = new JFrame();
568 Container content = frame.getContentPane();
569 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
570
571 content.add(new PerspectiveVertexImageShaperDemo());
572 frame.pack();
573 frame.setVisible(true);
574 }
575 }