Java tutorial
/* * 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 com.google.common.graph.MutableNetwork; import com.google.common.graph.Network; import com.google.common.graph.NetworkBuilder; import edu.uci.ics.jung.layout.algorithms.FRLayoutAlgorithm; import edu.uci.ics.jung.layout.model.LayoutModel; import edu.uci.ics.jung.visualization.GraphZoomScrollPane; import edu.uci.ics.jung.visualization.LayeredIcon; import edu.uci.ics.jung.visualization.MultiLayerTransformer.Layer; 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.LensMagnificationGraphMousePlugin; import edu.uci.ics.jung.visualization.control.ModalGraphMouse.Mode; import edu.uci.ics.jung.visualization.control.ModalLensGraphMouse; import edu.uci.ics.jung.visualization.control.ScalingControl; import edu.uci.ics.jung.visualization.decorators.EllipseNodeShapeFunction; import edu.uci.ics.jung.visualization.decorators.NodeIconShapeFunction; import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintFunction; import edu.uci.ics.jung.visualization.decorators.PickableNodePaintFunction; import edu.uci.ics.jung.visualization.picking.PickedState; import edu.uci.ics.jung.visualization.renderers.Checkmark; import edu.uci.ics.jung.visualization.renderers.DefaultEdgeLabelRenderer; import edu.uci.ics.jung.visualization.renderers.DefaultNodeLabelRenderer; import edu.uci.ics.jung.visualization.transform.LayoutLensSupport; import edu.uci.ics.jung.visualization.transform.Lens; import edu.uci.ics.jung.visualization.transform.LensSupport; import edu.uci.ics.jung.visualization.transform.MagnifyTransformer; import edu.uci.ics.jung.visualization.transform.shape.MagnifyImageLensSupport; import edu.uci.ics.jung.visualization.transform.shape.MagnifyShapeTransformer; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import javax.swing.*; /** * Demonstrates the use of images to represent graph nodes. The images are added to the * DefaultGraphLabelRenderer and can either be offset from the node, or centered on the node. * Additionally, the relative positioning of the label and image is controlled by subclassing the * DefaultGraphLabelRenderer and setting the appropriate properties on its JLabel superclass * FancyGraphLabelRenderer * * <p>The images used in this demo (courtesy of slashdot.org) are rectangular but with a transparent * background. When nodes 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 LensNodeImageShaperDemo extends JPanel { /** */ private static final long serialVersionUID = 5432239991020505763L; /** the graph */ Network<Number, Number> graph; /** the visual component and renderer for the graph */ VisualizationViewer<Number, Number> vv; /** some icon names to use */ String[] iconNames = { "apple", "os", "x", "linux", "inputdevices", "wireless", "graphics3", "gamespcgames", "humor", "music", "privacy" }; LensSupport magnifyLayoutSupport; LensSupport magnifyViewSupport; /** create an instance of a simple graph with controls to demo the zoom features. */ public LensNodeImageShaperDemo() { setLayout(new BorderLayout()); // create a simple graph for the demo graph = createGraph(); // Maps for the labels and icons Map<Number, String> map = new HashMap<>(); Map<Number, Icon> iconMap = new HashMap<>(); for (Number node : graph.nodes()) { int i = node.intValue(); map.put(node, iconNames[i % iconNames.length]); String name = "/images/topic" + iconNames[i] + ".gif"; try { Icon icon = new LayeredIcon( new ImageIcon(LensNodeImageShaperDemo.class.getResource(name)).getImage()); iconMap.put(node, icon); } catch (Exception ex) { System.err.println("You need slashdoticons.jar in your classpath to see the image " + name); } } FRLayoutAlgorithm<Number> layoutAlgorithm = new FRLayoutAlgorithm<>(); layoutAlgorithm.setMaxIterations(100); vv = new VisualizationViewer<>(graph, layoutAlgorithm, new Dimension(600, 600)); Function<Number, Paint> vpf = new PickableNodePaintFunction<>(vv.getPickedNodeState(), Color.white, Color.yellow); vv.getRenderContext().setNodeFillPaintFunction(vpf); vv.getRenderContext().setEdgeDrawPaintFunction( new PickableEdgePaintFunction<>(vv.getPickedEdgeState(), Color.black, Color.cyan)); vv.setBackground(Color.white); vv.getRenderContext().setNodeLabelFunction(map::get); vv.getRenderContext().setNodeLabelRenderer(new DefaultNodeLabelRenderer(Color.cyan)); vv.getRenderContext().setEdgeLabelRenderer(new DefaultEdgeLabelRenderer(Color.cyan)); final NodeIconShapeFunction<Number> nodeImageShapeFunction = new NodeIconShapeFunction<>( new EllipseNodeShapeFunction<>()); final Function<Number, Icon> nodeIconFunction = iconMap::get; nodeImageShapeFunction.setIconMap(iconMap); vv.getRenderContext().setNodeShapeFunction(nodeImageShapeFunction); vv.getRenderContext().setNodeIconFunction(nodeIconFunction); // Get the pickedState and add a listener that will decorate the //Node images with a checkmark icon when they are picked PickedState<Number> ps = vv.getPickedNodeState(); ps.addItemListener(new PickWithIconListener(nodeIconFunction)); 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.setNodeToolTipFunction(Object::toString); final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv); add(panel); final DefaultModalGraphMouse<Number, Number> graphMouse = new DefaultModalGraphMouse<>(); vv.setGraphMouse(graphMouse); final ScalingControl scaler = new CrossoverScalingControl(); JButton plus = new JButton("+"); plus.addActionListener(e -> scaler.scale(vv, 1.1f, vv.getCenter())); JButton minus = new JButton("-"); minus.addActionListener(e -> scaler.scale(vv, 1 / 1.1f, vv.getCenter())); JComboBox<Mode> 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 controls = new JPanel(); scaleGrid.add(plus); scaleGrid.add(minus); controls.add(scaleGrid); controls.add(modePanel); add(controls, BorderLayout.SOUTH); LayoutModel<Number> layoutModel = vv.getModel().getLayoutModel(); Dimension d = new Dimension(layoutModel.getWidth(), layoutModel.getHeight()); Lens lens = new Lens(d); lens.setMagnification(2.f); magnifyViewSupport = new MagnifyImageLensSupport<>(vv, new MagnifyShapeTransformer(lens, vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)), new ModalLensGraphMouse(new LensMagnificationGraphMousePlugin(1.f, 6.f, .2f))); magnifyLayoutSupport = new LayoutLensSupport<>(vv, new MagnifyTransformer(lens, vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT)), new ModalLensGraphMouse(new LensMagnificationGraphMousePlugin(1.f, 6.f, .2f))); graphMouse.addItemListener(magnifyLayoutSupport.getGraphMouse().getModeListener()); graphMouse.addItemListener(magnifyViewSupport.getGraphMouse().getModeListener()); ButtonGroup radio = new ButtonGroup(); JRadioButton none = new JRadioButton("None"); none.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { if (magnifyViewSupport != null) { magnifyViewSupport.deactivate(); } if (magnifyLayoutSupport != null) { magnifyLayoutSupport.deactivate(); } } }); final JRadioButton magnifyView = new JRadioButton("Magnified View"); magnifyView.addItemListener(e -> magnifyViewSupport.activate(e.getStateChange() == ItemEvent.SELECTED)); final JRadioButton magnifyModel = new JRadioButton("Magnified Layout"); magnifyModel.addItemListener(e -> magnifyLayoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED)); radio.add(none); radio.add(magnifyView); radio.add(magnifyModel); JMenuBar menubar = new JMenuBar(); JMenu modeMenu = graphMouse.getModeMenu(); menubar.add(modeMenu); JPanel lensPanel = new JPanel(new GridLayout(2, 0)); lensPanel.setBorder(BorderFactory.createTitledBorder("Lens")); lensPanel.add(none); lensPanel.add(magnifyView); lensPanel.add(magnifyModel); controls.add(lensPanel); } Network<Number, Number> createGraph() { MutableNetwork<Number, Number> graph = NetworkBuilder.directed().build(); graph.addEdge(0, 1, Math.random()); graph.addEdge(3, 0, Math.random()); graph.addEdge(0, 4, Math.random()); graph.addEdge(4, 5, Math.random()); graph.addEdge(5, 3, Math.random()); graph.addEdge(2, 1, Math.random()); graph.addEdge(4, 1, Math.random()); graph.addEdge(8, 2, Math.random()); graph.addEdge(3, 8, Math.random()); graph.addEdge(6, 7, Math.random()); graph.addEdge(7, 5, Math.random()); graph.addEdge(0, 9, Math.random()); graph.addEdge(9, 8, Math.random()); graph.addEdge(7, 6, Math.random()); graph.addEdge(6, 5, Math.random()); graph.addEdge(4, 2, Math.random()); graph.addEdge(5, 4, Math.random()); graph.addEdge(4, 10, Math.random()); graph.addEdge(10, 4, Math.random()); return graph; } public static class PickWithIconListener implements ItemListener { Function<Number, Icon> imager; Icon checked; public PickWithIconListener(Function<Number, Icon> imager) { this.imager = imager; checked = new Checkmark(Color.red); } public void itemStateChanged(ItemEvent e) { Icon icon = imager.apply((Number) e.getItem()); if (icon != null && icon instanceof LayeredIcon) { if (e.getStateChange() == ItemEvent.SELECTED) { ((LayeredIcon) icon).add(checked); } else { ((LayeredIcon) icon).remove(checked); } } } } public static void main(String[] args) { JFrame frame = new JFrame(); Container content = frame.getContentPane(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); content.add(new LensNodeImageShaperDemo()); frame.pack(); frame.setVisible(true); } }