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.Image;
20 import java.awt.Paint;
21 import java.awt.Shape;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.awt.event.ItemEvent;
25 import java.awt.event.ItemListener;
26 import java.awt.geom.AffineTransform;
27 import java.awt.geom.Rectangle2D;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 import javax.swing.BorderFactory;
32 import javax.swing.Icon;
33 import javax.swing.ImageIcon;
34 import javax.swing.JApplet;
35 import javax.swing.JButton;
36 import javax.swing.JCheckBox;
37 import javax.swing.JComboBox;
38 import javax.swing.JFrame;
39 import javax.swing.JPanel;
40
41 import com.google.common.base.Function;
42
43 import edu.uci.ics.jung.algorithms.layout.FRLayout;
44 import edu.uci.ics.jung.algorithms.layout.util.RandomLocationTransformer;
45 import edu.uci.ics.jung.graph.DirectedSparseGraph;
46 import edu.uci.ics.jung.graph.util.EdgeType;
47 import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
48 import edu.uci.ics.jung.visualization.LayeredIcon;
49 import edu.uci.ics.jung.visualization.VisualizationViewer;
50 import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
51 import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
52 import edu.uci.ics.jung.visualization.control.ScalingControl;
53 import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
54 import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
55 import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
56 import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
57 import edu.uci.ics.jung.visualization.decorators.VertexIconShapeTransformer;
58 import edu.uci.ics.jung.visualization.picking.PickedState;
59 import edu.uci.ics.jung.visualization.renderers.BasicVertexRenderer;
60 import edu.uci.ics.jung.visualization.renderers.Checkmark;
61 import edu.uci.ics.jung.visualization.renderers.DefaultEdgeLabelRenderer;
62 import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer;
63 import edu.uci.ics.jung.visualization.util.ImageShapeUtils;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class VertexImageShaperDemo extends JApplet {
82
83
84
85
86 private static final long serialVersionUID = -4332663871914930864L;
87
88 private static final int VERTEX_COUNT=11;
89
90
91
92
93 DirectedSparseGraph<Number, Number> graph;
94
95
96
97
98 VisualizationViewer<Number, Number> vv;
99
100
101
102
103 String[] iconNames = {
104 "apple",
105 "os",
106 "x",
107 "linux",
108 "inputdevices",
109 "wireless",
110 "graphics3",
111 "gamespcgames",
112 "humor",
113 "music",
114 "privacy"
115 };
116
117 public VertexImageShaperDemo() {
118
119
120 graph = new DirectedSparseGraph<Number,Number>();
121 createGraph(VERTEX_COUNT);
122
123
124 Map<Number,String> map = new HashMap<Number,String>();
125 for(int i=0; i<VERTEX_COUNT; i++) {
126 map.put(i, iconNames[i%iconNames.length]);
127 }
128
129
130 Map<Number,Icon> iconMap = new HashMap<Number,Icon>();
131 for(int i=0; i<VERTEX_COUNT; i++) {
132 String name = "/images/topic"+iconNames[i]+".gif";
133 try {
134 Icon icon =
135 new LayeredIcon(new ImageIcon(VertexImageShaperDemo.class.getResource(name)).getImage());
136 iconMap.put(i, icon);
137 } catch(Exception ex) {
138 System.err.println("You need slashdoticons.jar in your classpath to see the image "+name);
139 }
140 }
141
142 FRLayout<Number, Number> layout = new FRLayout<Number, Number>(graph);
143 layout.setMaxIterations(100);
144 layout.setInitializer(new RandomLocationTransformer<Number>(new Dimension(400,400), 0));
145 vv = new VisualizationViewer<Number, Number>(layout, new Dimension(400,400));
146
147
148
149
150 vv.getRenderer().setVertexRenderer(new DemoRenderer<Number,Number>());
151
152 Function<Number,Paint> vpf =
153 new PickableVertexPaintTransformer<Number>(vv.getPickedVertexState(), Color.white, Color.yellow);
154 vv.getRenderContext().setVertexFillPaintTransformer(vpf);
155 vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv.getPickedEdgeState(), Color.black, Color.cyan));
156
157 vv.setBackground(Color.white);
158
159
160 final Function<Number,String> vertexStringerImpl =
161 new VertexStringerImpl<Number,String>(map);
162 vv.getRenderContext().setVertexLabelTransformer(vertexStringerImpl);
163 vv.getRenderContext().setVertexLabelRenderer(new DefaultVertexLabelRenderer(Color.cyan));
164 vv.getRenderContext().setEdgeLabelRenderer(new DefaultEdgeLabelRenderer(Color.cyan));
165
166
167
168
169
170
171
172
173
174 final DemoVertexIconShapeTransformer<Number> vertexIconShapeTransformer =
175 new DemoVertexIconShapeTransformer<Number>(new EllipseVertexShapeTransformer<Number>());
176 vertexIconShapeTransformer.setIconMap(iconMap);
177
178 final DemoVertexIconTransformer<Number> vertexIconTransformer
179 = new DemoVertexIconTransformer<Number>(iconMap);
180
181 vv.getRenderContext().setVertexShapeTransformer(vertexIconShapeTransformer);
182 vv.getRenderContext().setVertexIconTransformer(vertexIconTransformer);
183
184
185
186
187
188
189 PickedState<Number> ps = vv.getPickedVertexState();
190 ps.addItemListener(new PickWithIconListener<Number>(vertexIconTransformer));
191
192 vv.addPostRenderPaintable(new VisualizationViewer.Paintable(){
193 int x;
194 int y;
195 Font font;
196 FontMetrics metrics;
197 int swidth;
198 int sheight;
199 String str = "Thank You, slashdot.org, for the images!";
200
201 public void paint(Graphics g) {
202 Dimension d = vv.getSize();
203 if(font == null) {
204 font = new Font(g.getFont().getName(), Font.BOLD, 20);
205 metrics = g.getFontMetrics(font);
206 swidth = metrics.stringWidth(str);
207 sheight = metrics.getMaxAscent()+metrics.getMaxDescent();
208 x = (d.width-swidth)/2;
209 y = (int)(d.height-sheight*1.5);
210 }
211 g.setFont(font);
212 Color oldColor = g.getColor();
213 g.setColor(Color.lightGray);
214 g.drawString(str, x, y);
215 g.setColor(oldColor);
216 }
217 public boolean useTransform() {
218 return false;
219 }
220 });
221
222
223 vv.setVertexToolTipTransformer(new ToStringLabeller());
224
225 Container content = getContentPane();
226 final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
227 content.add(panel);
228
229 final DefaultModalGraphMouse<Number,Number> graphMouse = new DefaultModalGraphMouse<Number,Number>();
230 vv.setGraphMouse(graphMouse);
231 vv.addKeyListener(graphMouse.getModeKeyListener());
232 final ScalingControl scaler = new CrossoverScalingControl();
233
234 JButton plus = new JButton("+");
235 plus.addActionListener(new ActionListener() {
236 public void actionPerformed(ActionEvent e) {
237 scaler.scale(vv, 1.1f, vv.getCenter());
238 }
239 });
240 JButton minus = new JButton("-");
241 minus.addActionListener(new ActionListener() {
242 public void actionPerformed(ActionEvent e) {
243 scaler.scale(vv, 1/1.1f, vv.getCenter());
244 }
245 });
246
247 JCheckBox shape = new JCheckBox("Shape");
248 shape.addItemListener(new ItemListener(){
249
250 public void itemStateChanged(ItemEvent e) {
251 vertexIconShapeTransformer.setShapeImages(e.getStateChange()==ItemEvent.SELECTED);
252 vv.repaint();
253 }
254 });
255 shape.setSelected(true);
256
257 JCheckBox fill = new JCheckBox("Fill");
258 fill.addItemListener(new ItemListener(){
259
260 public void itemStateChanged(ItemEvent e) {
261 vertexIconTransformer.setFillImages(e.getStateChange()==ItemEvent.SELECTED);
262 vv.repaint();
263 }
264 });
265 fill.setSelected(true);
266
267 JCheckBox drawOutlines = new JCheckBox("Outline");
268 drawOutlines.addItemListener(new ItemListener(){
269
270 public void itemStateChanged(ItemEvent e) {
271 vertexIconTransformer.setOutlineImages(e.getStateChange()==ItemEvent.SELECTED);
272 vv.repaint();
273 }
274 });
275
276 JComboBox<?> modeBox = graphMouse.getModeComboBox();
277 JPanel modePanel = new JPanel();
278 modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
279 modePanel.add(modeBox);
280
281 JPanel scaleGrid = new JPanel(new GridLayout(1,0));
282 scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));
283 JPanel labelFeatures = new JPanel(new GridLayout(1,0));
284 labelFeatures.setBorder(BorderFactory.createTitledBorder("Image Effects"));
285 JPanel controls = new JPanel();
286 scaleGrid.add(plus);
287 scaleGrid.add(minus);
288 controls.add(scaleGrid);
289 labelFeatures.add(shape);
290 labelFeatures.add(fill);
291 labelFeatures.add(drawOutlines);
292
293 controls.add(labelFeatures);
294 controls.add(modePanel);
295 content.add(controls, BorderLayout.SOUTH);
296 }
297
298
299
300
301
302
303
304 public static class PickWithIconListener<V> implements ItemListener {
305 Function<V, Icon> imager;
306 Icon checked;
307
308 public PickWithIconListener(Function<V, Icon> imager) {
309 this.imager = imager;
310 checked = new Checkmark();
311 }
312
313 public void itemStateChanged(ItemEvent e) {
314 @SuppressWarnings("unchecked")
315 Icon icon = imager.apply((V)e.getItem());
316 if(icon != null && icon instanceof LayeredIcon) {
317 if(e.getStateChange() == ItemEvent.SELECTED) {
318 ((LayeredIcon)icon).add(checked);
319 } else {
320 ((LayeredIcon)icon).remove(checked);
321 }
322 }
323 }
324 }
325
326
327
328
329
330
331
332
333 public static class VertexStringerImpl<V,S> implements Function<V,String> {
334
335 Map<V,String> map = new HashMap<V,String>();
336
337 boolean enabled = true;
338
339 public VertexStringerImpl(Map<V,String> map) {
340 this.map = map;
341 }
342
343
344
345
346 public String apply(V v) {
347 if(isEnabled()) {
348 return map.get(v);
349 } else {
350 return "";
351 }
352 }
353
354
355
356
357 public boolean isEnabled() {
358 return enabled;
359 }
360
361
362
363
364 public void setEnabled(boolean enabled) {
365 this.enabled = enabled;
366 }
367 }
368
369
370
371
372
373
374 private void createGraph(int vertexCount) {
375 for (int i = 0; i < vertexCount; i++) {
376 graph.addVertex(i);
377 }
378 int j=0;
379 graph.addEdge(j++, 0, 1, EdgeType.DIRECTED);
380 graph.addEdge(j++, 3, 0, EdgeType.DIRECTED);
381 graph.addEdge(j++, 0, 4, EdgeType.DIRECTED);
382 graph.addEdge(j++, 4, 5, EdgeType.DIRECTED);
383 graph.addEdge(j++, 5, 3, EdgeType.DIRECTED);
384 graph.addEdge(j++, 2, 1, EdgeType.DIRECTED);
385 graph.addEdge(j++, 4, 1, EdgeType.DIRECTED);
386 graph.addEdge(j++, 8, 2, EdgeType.DIRECTED);
387 graph.addEdge(j++, 3, 8, EdgeType.DIRECTED);
388 graph.addEdge(j++, 6, 7, EdgeType.DIRECTED);
389 graph.addEdge(j++, 7, 5, EdgeType.DIRECTED);
390 graph.addEdge(j++, 0, 9, EdgeType.DIRECTED);
391 graph.addEdge(j++, 9, 8, EdgeType.DIRECTED);
392 graph.addEdge(j++, 7, 6, EdgeType.DIRECTED);
393 graph.addEdge(j++, 6, 5, EdgeType.DIRECTED);
394 graph.addEdge(j++, 4, 2, EdgeType.DIRECTED);
395 graph.addEdge(j++, 5, 4, EdgeType.DIRECTED);
396 graph.addEdge(j++, 4, 10, EdgeType.DIRECTED);
397 graph.addEdge(j++, 10, 4, EdgeType.DIRECTED);
398 }
399
400
401
402
403
404
405
406
407 public static class DemoVertexIconTransformer<V> implements Function<V,Icon> {
408 boolean fillImages = true;
409 boolean outlineImages = false;
410 Map<V, Icon> iconMap = new HashMap<V, Icon>();
411
412 public DemoVertexIconTransformer(Map<V, Icon> iconMap) {
413 this.iconMap = iconMap;
414 }
415
416
417
418
419 public boolean isFillImages() {
420 return fillImages;
421 }
422
423
424
425 public void setFillImages(boolean fillImages) {
426 this.fillImages = fillImages;
427 }
428
429 public boolean isOutlineImages() {
430 return outlineImages;
431 }
432 public void setOutlineImages(boolean outlineImages) {
433 this.outlineImages = outlineImages;
434 }
435
436 public Icon apply(V v) {
437 if(fillImages) {
438 return (Icon)iconMap.get(v);
439 } else {
440 return null;
441 }
442 }
443 }
444
445
446
447
448
449
450
451 public static class DemoVertexIconShapeTransformer<V> extends VertexIconShapeTransformer<V> {
452
453 boolean shapeImages = true;
454
455 public DemoVertexIconShapeTransformer(Function<V,Shape> delegate) {
456 super(delegate);
457 }
458
459
460
461
462 public boolean isShapeImages() {
463 return shapeImages;
464 }
465
466
467
468 public void setShapeImages(boolean shapeImages) {
469 shapeMap.clear();
470 this.shapeImages = shapeImages;
471 }
472
473 public Shape transform(V v) {
474 Icon icon = (Icon) iconMap.get(v);
475
476 if (icon != null && icon instanceof ImageIcon) {
477
478 Image image = ((ImageIcon) icon).getImage();
479
480 Shape shape = shapeMap.get(image);
481 if (shape == null) {
482 if (shapeImages) {
483 shape = ImageShapeUtils.getShape(image, 30);
484 } else {
485 shape = new Rectangle2D.Float(0, 0,
486 image.getWidth(null), image.getHeight(null));
487 }
488 if(shape.getBounds().getWidth() > 0 &&
489 shape.getBounds().getHeight() > 0) {
490 int width = image.getWidth(null);
491 int height = image.getHeight(null);
492 AffineTransform transform =
493 AffineTransform.getTranslateInstance(-width / 2, -height / 2);
494 shape = transform.createTransformedShape(shape);
495 shapeMap.put(image, shape);
496 }
497 }
498 return shape;
499 } else {
500 return delegate.apply(v);
501 }
502 }
503 }
504
505
506
507
508
509
510
511
512
513
514 class DemoRenderer<V,E> extends BasicVertexRenderer<V,E> {
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 public static void main(String[] args) {
545 JFrame frame = new JFrame();
546 Container content = frame.getContentPane();
547 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
548
549 content.add(new VertexImageShaperDemo());
550 frame.pack();
551 frame.setVisible(true);
552 }
553 }