WorldMapGraphDemo.java Source code

Java tutorial

Introduction

Here is the source code for WorldMapGraphDemo.java

Source

/*
 * Copyright (c) 2003, the JUNG Project and the Regents of the University of
 * California All rights reserved.
 * 
 * This software is open-source under the BSD license; see either "license.txt"
 * or http://jung.sourceforge.net/license.txt for a description.
 * 
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.functors.ChainedTransformer;

import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractModalGraphMouse;
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.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.GradientVertexRenderer;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.renderers.BasicVertexLabelRenderer.InsidePositioner;

/**
 * Shows a graph overlaid on a world map image.
 * Scaling of the graph also scales the image background.
 * @author Tom Nelson
 * 
 */
@SuppressWarnings("serial")
public class WorldMapGraphDemo extends JApplet {

    /**
     * the graph
     */
    Graph<String, Number> graph;

    /**
     * the visual component and renderer for the graph
     */
    VisualizationViewer<String, Number> vv;

    Map<String, String[]> map = new HashMap<String, String[]>();
    List<String> cityList;

    /**
     * create an instance of a simple graph with controls to
     * demo the zoom features.
     * 
     */
    public WorldMapGraphDemo() {
        setLayout(new BorderLayout());

        map.put("TYO", new String[] { "35 40 N", "139 45 E" });
        map.put("PEK", new String[] { "39 55 N", "116 26 E" });
        map.put("MOW", new String[] { "55 45 N", "37 42 E" });
        map.put("JRS", new String[] { "31 47 N", "35 13 E" });
        map.put("CAI", new String[] { "30 03 N", "31 15 E" });
        map.put("CPT", new String[] { "33 55 S", "18 22 E" });
        map.put("PAR", new String[] { "48 52 N", "2 20 E" });
        map.put("LHR", new String[] { "51 30 N", "0 10 W" });
        map.put("HNL", new String[] { "21 18 N", "157 51 W" });
        map.put("NYC", new String[] { "40 77 N", "73 98 W" });
        map.put("SFO", new String[] { "37 62 N", "122 38 W" });
        map.put("AKL", new String[] { "36 55 S", "174 47 E" });
        map.put("BNE", new String[] { "27 28 S", "153 02 E" });
        map.put("HKG", new String[] { "22 15 N", "114 10 E" });
        map.put("KTM", new String[] { "27 42 N", "85 19 E" });
        map.put("IST", new String[] { "41 01 N", "28 58 E" });
        map.put("STO", new String[] { "59 20 N", "18 03 E" });
        map.put("RIO", new String[] { "22 54 S", "43 14 W" });
        map.put("LIM", new String[] { "12 03 S", "77 03 W" });
        map.put("YTO", new String[] { "43 39 N", "79 23 W" });

        cityList = new ArrayList<String>(map.keySet());

        // create a simple graph for the demo
        graph = new DirectedSparseMultigraph<String, Number>();
        createVertices();
        createEdges();

        ImageIcon mapIcon = null;
        String imageLocation = "/images/political_world_map.jpg";
        try {
            mapIcon = new ImageIcon(getClass().getResource(imageLocation));
        } catch (Exception ex) {
            System.err.println("Can't load \"" + imageLocation + "\"");
        }
        final ImageIcon icon = mapIcon;

        Dimension layoutSize = new Dimension(2000, 1000);

        Layout<String, Number> layout = new StaticLayout<String, Number>(graph,
                new ChainedTransformer(new Transformer[] { new CityTransformer(map),
                        new LatLonPixelTransformer(new Dimension(2000, 1000)) }));

        layout.setSize(layoutSize);
        vv = new VisualizationViewer<String, Number>(layout, new Dimension(800, 400));

        if (icon != null) {
            vv.addPreRenderPaintable(new VisualizationViewer.Paintable() {
                public void paint(Graphics g) {
                    Graphics2D g2d = (Graphics2D) g;
                    AffineTransform oldXform = g2d.getTransform();
                    AffineTransform lat = vv.getRenderContext().getMultiLayerTransformer()
                            .getTransformer(Layer.LAYOUT).getTransform();
                    AffineTransform vat = vv.getRenderContext().getMultiLayerTransformer()
                            .getTransformer(Layer.VIEW).getTransform();
                    AffineTransform at = new AffineTransform();
                    at.concatenate(g2d.getTransform());
                    at.concatenate(vat);
                    at.concatenate(lat);
                    g2d.setTransform(at);
                    g.drawImage(icon.getImage(), 0, 0, icon.getIconWidth(), icon.getIconHeight(), vv);
                    g2d.setTransform(oldXform);
                }

                public boolean useTransform() {
                    return false;
                }
            });
        }

        vv.getRenderer().setVertexRenderer(new GradientVertexRenderer<String, Number>(Color.white, Color.red,
                Color.white, Color.blue, vv.getPickedVertexState(), false));

        // add my listeners for ToolTips
        vv.setVertexToolTipTransformer(new ToStringLabeller());
        vv.setEdgeToolTipTransformer(new Transformer<Number, String>() {
            public String transform(Number edge) {
                return "E" + graph.getEndpoints(edge).toString();
            }
        });

        vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
        vv.getRenderer().getVertexLabelRenderer().setPositioner(new InsidePositioner());
        vv.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.AUTO);

        final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
        add(panel);
        final AbstractModalGraphMouse graphMouse = new DefaultModalGraphMouse();
        vv.setGraphMouse(graphMouse);

        vv.addKeyListener(graphMouse.getModeKeyListener());
        vv.setToolTipText("<html><center>Type 'p' for Pick mode<p>Type 't' for Transform mode");

        final ScalingControl scaler = new CrossoverScalingControl();

        //        vv.scaleToLayout(scaler);

        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());
            }
        });

        JButton reset = new JButton("reset");
        reset.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).setToIdentity();
                vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).setToIdentity();
            }
        });

        JPanel controls = new JPanel();
        controls.add(plus);
        controls.add(minus);
        controls.add(reset);
        add(controls, BorderLayout.SOUTH);
    }

    /**
     * create some vertices
     * @param count how many to create
     * @return the Vertices in an array
     */
    private void createVertices() {
        for (String city : map.keySet()) {
            graph.addVertex(city);
        }
    }

    /**
     * create edges for this demo graph
     * @param v an array of Vertices to connect
     */
    void createEdges() {

        for (int i = 0; i < map.keySet().size() * 1.3; i++) {
            graph.addEdge(new Double(Math.random()), randomCity(), randomCity(), EdgeType.DIRECTED);
        }
    }

    private String randomCity() {
        int m = cityList.size();
        return cityList.get((int) (Math.random() * m));
    }

    static class CityTransformer implements Transformer<String, String[]> {

        Map<String, String[]> map;

        public CityTransformer(Map<String, String[]> map) {
            this.map = map;
        }

        /**
         * transform airport code to latlon string
         */
        public String[] transform(String city) {
            return map.get(city);
        }
    }

    static class LatLonPixelTransformer implements Transformer<String[], Point2D> {
        Dimension d;
        int startOffset;

        public LatLonPixelTransformer(Dimension d) {
            this.d = d;
        }

        /**
         * transform a lat
         */
        public Point2D transform(String[] latlon) {
            double latitude = 0;
            double longitude = 0;
            String[] lat = latlon[0].split(" ");
            String[] lon = latlon[1].split(" ");
            latitude = Integer.parseInt(lat[0]) + Integer.parseInt(lat[1]) / 60f;
            latitude *= d.height / 180f;
            longitude = Integer.parseInt(lon[0]) + Integer.parseInt(lon[1]) / 60f;
            longitude *= d.width / 360f;
            if (lat[2].equals("N")) {
                latitude = d.height / 2 - latitude;

            } else { // assume S
                latitude = d.height / 2 + latitude;
            }

            if (lon[2].equals("W")) {
                longitude = d.width / 2 - longitude;

            } else { // assume E
                longitude = d.width / 2 + longitude;
            }

            return new Point2D.Double(longitude, latitude);
        }

    }

    /**
     * a driver for this demo
     */
    public static void main(String[] args) {
        // create a frome to hold the graph
        final JFrame frame = new JFrame();
        Container content = frame.getContentPane();
        content.add(new WorldMapGraphDemo());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}