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