All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uci.ics.jung.samples.VertexImageShaperDemo Maven / Gradle / Ivy

Go to download

Sample programs using JUNG. Nearly all JUNG capabilities are demonstrated here. Please study the source code for these examples prior to asking how to do something.

The newest version!
/*
 * Copyright (c) 2003, The JUNG Authors
 * All rights reserved.
 * 
 * This software is open-source under the BSD license; see either "license.txt"
 * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 * 
 */
package edu.uci.ics.jung.samples;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.google.common.base.Function;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.util.RandomLocationTransformer;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.LayeredIcon;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.decorators.VertexIconShapeTransformer;
import edu.uci.ics.jung.visualization.picking.PickedState;
import edu.uci.ics.jung.visualization.renderers.BasicVertexRenderer;
import edu.uci.ics.jung.visualization.renderers.Checkmark;
import edu.uci.ics.jung.visualization.renderers.DefaultEdgeLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer;
import edu.uci.ics.jung.visualization.util.ImageShapeUtils;

/**
 * Demonstrates the use of images to represent graph vertices.
 * The images are supplied via the VertexShapeFunction so that
 * both the image and its shape can be utilized.
 * 
 * The images used in this demo (courtesy of slashdot.org) are
 * rectangular but with a transparent background. When vertices
 * are represented by these images, it looks better if the actual
 * shape of the opaque part of the image is computed so that the
 * edge arrowheads follow the visual shape of the image. This demo
 * uses the FourPassImageShaper class to compute the Shape from
 * an image with transparent background.
 * 
 * @author Tom Nelson
 * 
 */
public class VertexImageShaperDemo extends JApplet {

    /**
	 * 
	 */
	private static final long serialVersionUID = -4332663871914930864L;
	
	private static final int VERTEX_COUNT=11;

	/**
     * the graph
     */
    DirectedSparseGraph graph;

    /**
     * the visual component and renderer for the graph
     */
    VisualizationViewer vv;
    
    /**
     * some icon names to use
     */
    String[] iconNames = {
            "apple",
            "os",
            "x",
            "linux",
            "inputdevices",
            "wireless",
            "graphics3",
            "gamespcgames",
            "humor",
            "music",
            "privacy"
    };
    
    public VertexImageShaperDemo() {
        
        // create a simple graph for the demo
        graph = new DirectedSparseGraph();
        createGraph(VERTEX_COUNT);
        
        // a Map for the labels
        Map map = new HashMap();
        for(int i=0; i iconMap = new HashMap();
        for(int i=0; i layout = new FRLayout(graph);
        layout.setMaxIterations(100);
        layout.setInitializer(new RandomLocationTransformer(new Dimension(400,400), 0));
        vv =  new VisualizationViewer(layout, new Dimension(400,400));
        
        // This demo uses a special renderer to turn outlines on and off.
        // you do not need to do this in a real application.
        // Instead, just let vv use the Renderer it already has
        vv.getRenderer().setVertexRenderer(new DemoRenderer());

        Function vpf = 
            new PickableVertexPaintTransformer(vv.getPickedVertexState(), Color.white, Color.yellow);
        vv.getRenderContext().setVertexFillPaintTransformer(vpf);
        vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer(vv.getPickedEdgeState(), Color.black, Color.cyan));

        vv.setBackground(Color.white);
        
        
        final Function vertexStringerImpl = 
            new VertexStringerImpl(map);
        vv.getRenderContext().setVertexLabelTransformer(vertexStringerImpl);
        vv.getRenderContext().setVertexLabelRenderer(new DefaultVertexLabelRenderer(Color.cyan));
        vv.getRenderContext().setEdgeLabelRenderer(new DefaultEdgeLabelRenderer(Color.cyan));
//        vv.getRenderContext().setEdgeLabelTransformer(new Function() {
//        	URL url = getClass().getResource("/images/lightning-s.gif");
//			public String transform(Number input) {
//				
//				return ""+input.toString();
//			}});
        
        // For this demo only, I use a special class that lets me turn various
        // features on and off. For a real application, use VertexIconShapeTransformer instead.
        final DemoVertexIconShapeTransformer vertexIconShapeTransformer =
            new DemoVertexIconShapeTransformer(new EllipseVertexShapeTransformer());
        vertexIconShapeTransformer.setIconMap(iconMap);

        final DemoVertexIconTransformer vertexIconTransformer
        	= new DemoVertexIconTransformer(iconMap);
        
        vv.getRenderContext().setVertexShapeTransformer(vertexIconShapeTransformer);
        vv.getRenderContext().setVertexIconTransformer(vertexIconTransformer);
        
        // un-comment for RStar Tree visual testing
        //vv.addPostRenderPaintable(new BoundingRectanglePaintable(vv.getRenderContext(), vv.getGraphLayout()));

        // Get the pickedState and add a listener that will decorate the
        // Vertex images with a checkmark icon when they are picked
        PickedState ps = vv.getPickedVertexState();
        ps.addItemListener(new PickWithIconListener(vertexIconTransformer));
        
        vv.addPostRenderPaintable(new VisualizationViewer.Paintable(){
            int x;
            int y;
            Font font;
            FontMetrics metrics;
            int swidth;
            int sheight;
            String str = "Thank You, slashdot.org, for the images!";
            
            public void paint(Graphics g) {
                Dimension d = vv.getSize();
                if(font == null) {
                    font = new Font(g.getFont().getName(), Font.BOLD, 20);
                    metrics = g.getFontMetrics(font);
                    swidth = metrics.stringWidth(str);
                    sheight = metrics.getMaxAscent()+metrics.getMaxDescent();
                    x = (d.width-swidth)/2;
                    y = (int)(d.height-sheight*1.5);
                }
                g.setFont(font);
                Color oldColor = g.getColor();
                g.setColor(Color.lightGray);
                g.drawString(str, x, y);
                g.setColor(oldColor);
            }
            public boolean useTransform() {
                return false;
            }
        });

        // add a listener for ToolTips
        vv.setVertexToolTipTransformer(new ToStringLabeller());
        
        Container content = getContentPane();
        final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
        content.add(panel);
        
        final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
        vv.setGraphMouse(graphMouse);
        vv.addKeyListener(graphMouse.getModeKeyListener());
        final ScalingControl scaler = new CrossoverScalingControl();

        JButton plus = new JButton("+");
        plus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1.1f, vv.getCenter());
            }
        });
        JButton minus = new JButton("-");
        minus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1/1.1f, vv.getCenter());
            }
        });

        JCheckBox shape = new JCheckBox("Shape");
        shape.addItemListener(new ItemListener(){

            public void itemStateChanged(ItemEvent e) {
                vertexIconShapeTransformer.setShapeImages(e.getStateChange()==ItemEvent.SELECTED);
                vv.repaint();
            }
        });
        shape.setSelected(true);

        JCheckBox fill = new JCheckBox("Fill");
        fill.addItemListener(new ItemListener(){

            public void itemStateChanged(ItemEvent e) {
                vertexIconTransformer.setFillImages(e.getStateChange()==ItemEvent.SELECTED);
                vv.repaint();
            }
        });
        fill.setSelected(true);
        
        JCheckBox drawOutlines = new JCheckBox("Outline");
        drawOutlines.addItemListener(new ItemListener(){

            public void itemStateChanged(ItemEvent e) {
                vertexIconTransformer.setOutlineImages(e.getStateChange()==ItemEvent.SELECTED);
                vv.repaint();
            }
        });
        
        JComboBox modeBox = graphMouse.getModeComboBox();
        JPanel modePanel = new JPanel();
        modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
        modePanel.add(modeBox);
        
        JPanel scaleGrid = new JPanel(new GridLayout(1,0));
        scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));
        JPanel labelFeatures = new JPanel(new GridLayout(1,0));
        labelFeatures.setBorder(BorderFactory.createTitledBorder("Image Effects"));
        JPanel controls = new JPanel();
        scaleGrid.add(plus);
        scaleGrid.add(minus);
        controls.add(scaleGrid);
        labelFeatures.add(shape);
        labelFeatures.add(fill);
        labelFeatures.add(drawOutlines);

        controls.add(labelFeatures);
        controls.add(modePanel);
        content.add(controls, BorderLayout.SOUTH);
    }
    
    /**
     * When Vertices are picked, add a checkmark icon to the imager.
     * Remove the icon when a Vertex is unpicked
     * @author Tom Nelson
     *
     */
    public static class PickWithIconListener implements ItemListener {
        Function imager;
        Icon checked;
        
        public PickWithIconListener(Function imager) {
            this.imager = imager;
            checked = new Checkmark();
        }

        public void itemStateChanged(ItemEvent e) {
            @SuppressWarnings("unchecked")
			Icon icon = imager.apply((V)e.getItem());
            if(icon != null && icon instanceof LayeredIcon) {
                if(e.getStateChange() == ItemEvent.SELECTED) {
                    ((LayeredIcon)icon).add(checked);
                } else {
                    ((LayeredIcon)icon).remove(checked);
                }
            }
        }
    }
    /**
     * A simple implementation of VertexStringer that
     * gets Vertex labels from a Map  
     * 
     * @author Tom Nelson
     *
     *
     */
    public static class VertexStringerImpl implements Function {
        
        Map map = new HashMap();
        
        boolean enabled = true;
        
        public VertexStringerImpl(Map map) {
            this.map = map;
        }
        
        /* (non-Javadoc)
         * @see edu.uci.ics.jung.graph.decorators.VertexStringer#getLabel(edu.uci.ics.jung.graph.Vertex)
         */
        public String apply(V v) {
            if(isEnabled()) {
                return map.get(v);
            } else {
                return "";
            }
        }
        
        /**
         * @return Returns the enabled.
         */
        public boolean isEnabled() {
            return enabled;
        }
        
        /**
         * @param enabled The enabled to set.
         */
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }
    
    /**
     * create some vertices
     * @param count how many to create
     * @return the Vertices in an array
     */
    private void createGraph(int vertexCount) {
        for (int i = 0; i < vertexCount; i++) {
            graph.addVertex(i);
        }
    	int j=0;
        graph.addEdge(j++, 0, 1, EdgeType.DIRECTED);
        graph.addEdge(j++, 3, 0, EdgeType.DIRECTED);
        graph.addEdge(j++, 0, 4, EdgeType.DIRECTED);
        graph.addEdge(j++, 4, 5, EdgeType.DIRECTED);
        graph.addEdge(j++, 5, 3, EdgeType.DIRECTED);
        graph.addEdge(j++, 2, 1, EdgeType.DIRECTED);
        graph.addEdge(j++, 4, 1, EdgeType.DIRECTED);
        graph.addEdge(j++, 8, 2, EdgeType.DIRECTED);
        graph.addEdge(j++, 3, 8, EdgeType.DIRECTED);
        graph.addEdge(j++, 6, 7, EdgeType.DIRECTED);
        graph.addEdge(j++, 7, 5, EdgeType.DIRECTED);
        graph.addEdge(j++, 0, 9, EdgeType.DIRECTED);
        graph.addEdge(j++, 9, 8, EdgeType.DIRECTED);
        graph.addEdge(j++, 7, 6, EdgeType.DIRECTED);
        graph.addEdge(j++, 6, 5, EdgeType.DIRECTED);
        graph.addEdge(j++, 4, 2, EdgeType.DIRECTED);
        graph.addEdge(j++, 5, 4, EdgeType.DIRECTED);
        graph.addEdge(j++, 4, 10, EdgeType.DIRECTED);
        graph.addEdge(j++, 10, 4, EdgeType.DIRECTED);
    }

    /** 
     * This class exists only to provide settings to turn on/off shapes and image fill
     * in this demo.
     * 
     * 

For a real application, just use {@code Functions.forMap(iconMap)} to provide a * {@code Function}. */ public static class DemoVertexIconTransformer implements Function { boolean fillImages = true; boolean outlineImages = false; Map iconMap = new HashMap(); public DemoVertexIconTransformer(Map iconMap) { this.iconMap = iconMap; } /** * @return Returns the fillImages. */ public boolean isFillImages() { return fillImages; } /** * @param fillImages The fillImages to set. */ public void setFillImages(boolean fillImages) { this.fillImages = fillImages; } public boolean isOutlineImages() { return outlineImages; } public void setOutlineImages(boolean outlineImages) { this.outlineImages = outlineImages; } public Icon apply(V v) { if(fillImages) { return (Icon)iconMap.get(v); } else { return null; } } } /** * this class exists only to provide settings to turn on/off shapes and image fill * in this demo. * In a real application, use VertexIconShapeTransformer instead. * */ public static class DemoVertexIconShapeTransformer extends VertexIconShapeTransformer { boolean shapeImages = true; public DemoVertexIconShapeTransformer(Function delegate) { super(delegate); } /** * @return Returns the shapeImages. */ public boolean isShapeImages() { return shapeImages; } /** * @param shapeImages The shapeImages to set. */ public void setShapeImages(boolean shapeImages) { shapeMap.clear(); this.shapeImages = shapeImages; } public Shape transform(V v) { Icon icon = (Icon) iconMap.get(v); if (icon != null && icon instanceof ImageIcon) { Image image = ((ImageIcon) icon).getImage(); Shape shape = shapeMap.get(image); if (shape == null) { if (shapeImages) { shape = ImageShapeUtils.getShape(image, 30); } else { shape = new Rectangle2D.Float(0, 0, image.getWidth(null), image.getHeight(null)); } if(shape.getBounds().getWidth() > 0 && shape.getBounds().getHeight() > 0) { int width = image.getWidth(null); int height = image.getHeight(null); AffineTransform transform = AffineTransform.getTranslateInstance(-width / 2, -height / 2); shape = transform.createTransformedShape(shape); shapeMap.put(image, shape); } } return shape; } else { return delegate.apply(v); } } } /** * a special renderer that can turn outlines on and off * in this demo. * You won't need this for a real application. * Use BasicVertexRenderer instead * * @author Tom Nelson * */ class DemoRenderer extends BasicVertexRenderer { // public void paintIconForVertex(RenderContext rc, V v, Layout layout) { // // Point2D p = layout.transform(v); // p = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p); // float x = (float)p.getX(); // float y = (float)p.getY(); // // GraphicsDecorator g = rc.getGraphicsContext(); // boolean outlineImages = false; // Function vertexIconFunction = rc.getVertexIconTransformer(); // // if(vertexIconFunction instanceof DemoVertexIconTransformer) { // outlineImages = ((DemoVertexIconTransformer)vertexIconFunction).isOutlineImages(); // } // Icon icon = vertexIconFunction.transform(v); // if(icon == null || outlineImages) { // // Shape s = AffineTransform.getTranslateInstance(x,y). // createTransformedShape(rc.getVertexShapeTransformer().transform(v)); // paintShapeForVertex(rc, v, s); // } // if(icon != null) { // int xLoc = (int) (x - icon.getIconWidth()/2); // int yLoc = (int) (y - icon.getIconHeight()/2); // icon.paintIcon(rc.getScreenDevice(), g.getDelegate(), xLoc, yLoc); // } // } } public static void main(String[] args) { JFrame frame = new JFrame(); Container content = frame.getContentPane(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); content.add(new VertexImageShaperDemo()); frame.pack(); frame.setVisible(true); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy