/* * JXMapKit.java * * Created on November 19, 2006, 3:52 AM */ package org.jdesktop.swingx; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.geom.Point2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.Set; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import org.jdesktop.swingx.mapviewer.DefaultTileFactory; import org.jdesktop.swingx.mapviewer.DefaultWaypoint; import org.jdesktop.swingx.mapviewer.GeoPosition; import org.jdesktop.swingx.mapviewer.TileFactory; import org.jdesktop.swingx.mapviewer.TileFactoryInfo; import org.jdesktop.swingx.mapviewer.Waypoint; import org.jdesktop.swingx.mapviewer.WaypointPainter; import org.jdesktop.swingx.mapviewer.bmng.CylindricalProjectionTileFactory; import org.jdesktop.swingx.painter.AbstractPainter; import org.jdesktop.swingx.painter.CompoundPainter; import org.jdesktop.swingx.painter.Painter; /** * <p>The JXMapKit is a pair of JXMapViewers preconfigured to be easy to use * with common features built in. This includes zoom buttons, a zoom slider, * and a mini-map in the lower right corner showing an overview of the map. * Each feature can be turned off using an appropriate * <CODE>is<I>X</I>visible</CODE> property. For example, to turn * off the minimap call * * <PRE><CODE>jxMapKit.setMiniMapVisible(false);</CODE></PRE> * </p> * * <p> * The JXMapViewer is preconfigured to connect to maps.swinglabs.org which * serves up global satellite imagery from NASA's * <a href="http://earthobservatory.nasa.gov/Newsroom/BlueMarble/">Blue * Marble NG</a> image collection. * </p> * @author joshy */ public class JXMapKit extends JPanel { private static final long serialVersionUID = -8366577998349912380L; private boolean miniMapVisible = true; private boolean zoomSliderVisible = true; private boolean zoomButtonsVisible = true; private final boolean sliderReversed = false; @SuppressWarnings("javadoc") public enum DefaultProviders { SwingLabsBlueMarble, OpenStreetMaps, Custom } private DefaultProviders defaultProvider = DefaultProviders.SwingLabsBlueMarble; private boolean addressLocationShown = true; private boolean dataProviderCreditShown = true; /** * Creates a new JXMapKit */ public JXMapKit() { initComponents(); setDataProviderCreditShown(false); zoomSlider.setOpaque(false); try { Icon minusIcon = new ImageIcon(getClass().getResource("/org/jdesktop/swingx/mapviewer/resources/minus.png")); this.zoomOutButton.setIcon(minusIcon); this.zoomOutButton.setText(""); Icon plusIcon = new ImageIcon(getClass().getResource("/org/jdesktop/swingx/mapviewer/resources/plus.png")); this.zoomInButton.setIcon(plusIcon); this.zoomInButton.setText(""); } catch (Throwable thr) { System.out.println("error: " + thr.getMessage()); thr.printStackTrace(); } setTileFactory(new CylindricalProjectionTileFactory()); mainMap.setCenterPosition(new GeoPosition(0, 0)); miniMap.setCenterPosition(new GeoPosition(0, 0)); mainMap.setRestrictOutsidePanning(true); miniMap.setRestrictOutsidePanning(true); rebuildMainMapOverlay(); /* * // adapter to move the minimap after the main map has moved MouseInputAdapter ma = new MouseInputAdapter() { * public void mouseReleased(MouseEvent e) { miniMap.setCenterPosition(mapCenterPosition); } }; * mainMap.addMouseMotionListener(ma); mainMap.addMouseListener(ma); */ mainMap.addPropertyChangeListener("center", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { Point2D mapCenter = (Point2D) evt.getNewValue(); TileFactory tf = mainMap.getTileFactory(); GeoPosition mapPos = tf.pixelToGeo(mapCenter, mainMap.getZoom()); miniMap.setCenterPosition(mapPos); } }); mainMap.addPropertyChangeListener("centerPosition", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { mapCenterPosition = (GeoPosition) evt.getNewValue(); miniMap.setCenterPosition(mapCenterPosition); Point2D pt = miniMap.getTileFactory().geoToPixel(mapCenterPosition, miniMap.getZoom()); miniMap.setCenter(pt); miniMap.repaint(); } }); mainMap.addPropertyChangeListener("zoom", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { zoomSlider.setValue(mainMap.getZoom()); miniMap.setZoom(mainMap.getZoom() + 4); } }); // an overlay for the mini-map which shows a rectangle representing the main map miniMap.setOverlayPainter(new Painter<JXMapViewer>() { @Override public void paint(Graphics2D g, JXMapViewer map, int width, int height) { // get the viewport rect of the main map Rectangle mainMapBounds = mainMap.getViewportBounds(); // convert to Point2Ds Point2D upperLeft2D = mainMapBounds.getLocation(); Point2D lowerRight2D = new Point2D.Double(upperLeft2D.getX() + mainMapBounds.getWidth(), upperLeft2D .getY() + mainMapBounds.getHeight()); // convert to GeoPostions GeoPosition upperLeft = mainMap.getTileFactory().pixelToGeo(upperLeft2D, mainMap.getZoom()); GeoPosition lowerRight = mainMap.getTileFactory().pixelToGeo(lowerRight2D, mainMap.getZoom()); // convert to Point2Ds on the mini-map upperLeft2D = map.getTileFactory().geoToPixel(upperLeft, map.getZoom()); lowerRight2D = map.getTileFactory().geoToPixel(lowerRight, map.getZoom()); g = (Graphics2D) g.create(); Rectangle rect = map.getViewportBounds(); // p("rect = " + rect); g.translate(-rect.x, -rect.y); // Point2D centerpos = map.getTileFactory().geoToPixel(mapCenterPosition, map.getZoom()); // p("center pos = " + centerpos); g.setPaint(Color.RED); // g.drawRect((int)centerpos.getX()-30,(int)centerpos.getY()-30,60,60); g.drawRect((int) upperLeft2D.getX(), (int) upperLeft2D.getY(), (int) (lowerRight2D.getX() - upperLeft2D.getX()), (int) (lowerRight2D.getY() - upperLeft2D.getY())); g.setPaint(new Color(255, 0, 0, 50)); g.fillRect((int) upperLeft2D.getX(), (int) upperLeft2D.getY(), (int) (lowerRight2D.getX() - upperLeft2D.getX()), (int) (lowerRight2D.getY() - upperLeft2D.getY())); // g.drawOval((int)lowerRight2D.getX(),(int)lowerRight2D.getY(),1,1); g.dispose(); } }); if (getDefaultProvider() == DefaultProviders.OpenStreetMaps) { setZoom(10); } else { setZoom(3);// joshy: hack, i shouldn't need this here } this.setCenterPosition(new GeoPosition(0, 0)); } // private Point2D mapCenter = new Point2D.Double(0,0); private GeoPosition mapCenterPosition = new GeoPosition(0, 0); private boolean zoomChanging = false; /** * Set the current zoomlevel for the main map. The minimap will be updated accordingly * @param zoom the new zoom level */ public void setZoom(int zoom) { zoomChanging = true; mainMap.setZoom(zoom); miniMap.setZoom(mainMap.getZoom() + 4); if (sliderReversed) { zoomSlider.setValue(zoomSlider.getMaximum() - zoom); } else { zoomSlider.setValue(zoom); } zoomChanging = false; } /** * Returns an action which can be attached to buttons or menu items to make the map zoom out * @return a preconfigured Zoom Out action */ public Action getZoomOutAction() { Action act = new AbstractAction() { /** * */ private static final long serialVersionUID = 5525706163434375107L; @Override public void actionPerformed(ActionEvent e) { setZoom(mainMap.getZoom() - 1); } }; act.putValue(Action.NAME, "-"); return act; } /** * Returns an action which can be attached to buttons or menu items to make the map zoom in * @return a preconfigured Zoom In action */ public Action getZoomInAction() { Action act = new AbstractAction() { /** * */ private static final long serialVersionUID = 5779971489365451352L; @Override public void actionPerformed(ActionEvent e) { setZoom(mainMap.getZoom() + 1); } }; act.putValue(Action.NAME, "+"); return act; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The * content of this method is always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; mainMap = new org.jdesktop.swingx.JXMapViewer(); miniMap = new org.jdesktop.swingx.JXMapViewer(); jPanel1 = new javax.swing.JPanel(); zoomInButton = new javax.swing.JButton(); zoomOutButton = new javax.swing.JButton(); zoomSlider = new javax.swing.JSlider(); setLayout(new java.awt.GridBagLayout()); mainMap.setLayout(new java.awt.GridBagLayout()); miniMap.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); miniMap.setMinimumSize(new java.awt.Dimension(100, 100)); miniMap.setPreferredSize(new java.awt.Dimension(100, 100)); miniMap.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; mainMap.add(miniMap, gridBagConstraints); jPanel1.setOpaque(false); jPanel1.setLayout(new java.awt.GridBagLayout()); zoomInButton.setAction(getZoomOutAction()); zoomInButton.setIcon(new javax.swing.ImageIcon(getClass().getResource( "/org/jdesktop/swingx/mapviewer/resources/plus.png"))); zoomInButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); zoomInButton.setMaximumSize(new java.awt.Dimension(20, 20)); zoomInButton.setMinimumSize(new java.awt.Dimension(20, 20)); zoomInButton.setOpaque(false); zoomInButton.setPreferredSize(new java.awt.Dimension(20, 20)); zoomInButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { zoomInButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; jPanel1.add(zoomInButton, gridBagConstraints); zoomOutButton.setAction(getZoomInAction()); zoomOutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource( "/org/jdesktop/swingx/mapviewer/resources/minus.png"))); zoomOutButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); zoomOutButton.setMaximumSize(new java.awt.Dimension(20, 20)); zoomOutButton.setMinimumSize(new java.awt.Dimension(20, 20)); zoomOutButton.setOpaque(false); zoomOutButton.setPreferredSize(new java.awt.Dimension(20, 20)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; jPanel1.add(zoomOutButton, gridBagConstraints); zoomSlider.setMajorTickSpacing(1); zoomSlider.setMaximum(15); zoomSlider.setMinimum(10); zoomSlider.setMinorTickSpacing(1); zoomSlider.setOrientation(SwingConstants.VERTICAL); zoomSlider.setPaintTicks(true); zoomSlider.setSnapToTicks(true); zoomSlider.setMinimumSize(new java.awt.Dimension(35, 100)); zoomSlider.setPreferredSize(new java.awt.Dimension(35, 190)); zoomSlider.addChangeListener(new javax.swing.event.ChangeListener() { @Override public void stateChanged(javax.swing.event.ChangeEvent evt) { zoomSliderStateChanged(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; jPanel1.add(zoomSlider, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); mainMap.add(jPanel1, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(mainMap, gridBagConstraints); }// </editor-fold>//GEN-END:initComponents @SuppressWarnings("unused") private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_zoomInButtonActionPerformed // TODO add your handling code here: }// GEN-LAST:event_zoomInButtonActionPerformed @SuppressWarnings("unused") private void zoomSliderStateChanged(javax.swing.event.ChangeEvent evt) {// GEN-FIRST:event_zoomSliderStateChanged if (!zoomChanging) { setZoom(zoomSlider.getValue()); } // TODO add your handling code here: }// GEN-LAST:event_zoomSliderStateChanged // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel jPanel1; private org.jdesktop.swingx.JXMapViewer mainMap; private org.jdesktop.swingx.JXMapViewer miniMap; private javax.swing.JButton zoomInButton; private javax.swing.JButton zoomOutButton; private javax.swing.JSlider zoomSlider; // End of variables declaration//GEN-END:variables /** * Indicates if the mini-map is currently visible * @return the current value of the mini-map property */ public boolean isMiniMapVisible() { return miniMapVisible; } /** * Sets if the mini-map should be visible * @param miniMapVisible a new value for the miniMap property */ public void setMiniMapVisible(boolean miniMapVisible) { boolean old = this.isMiniMapVisible(); this.miniMapVisible = miniMapVisible; miniMap.setVisible(miniMapVisible); firePropertyChange("miniMapVisible", old, this.isMiniMapVisible()); } /** * Indicates if the zoom slider is currently visible * @return the current value of the zoomSliderVisible property */ public boolean isZoomSliderVisible() { return zoomSliderVisible; } /** * Sets if the zoom slider should be visible * @param zoomSliderVisible the new value of the zoomSliderVisible property */ public void setZoomSliderVisible(boolean zoomSliderVisible) { boolean old = this.isZoomSliderVisible(); this.zoomSliderVisible = zoomSliderVisible; zoomSlider.setVisible(zoomSliderVisible); firePropertyChange("zoomSliderVisible", old, this.isZoomSliderVisible()); } /** * Indicates if the zoom buttons are visible. This is a bound property and can be listed for using a * PropertyChangeListener * @return current value of the zoomButtonsVisible property */ public boolean isZoomButtonsVisible() { return zoomButtonsVisible; } /** * Sets if the zoom buttons should be visible. This ia bound property. Changes can be listened for using a * PropertyChaneListener * @param zoomButtonsVisible new value of the zoomButtonsVisible property */ public void setZoomButtonsVisible(boolean zoomButtonsVisible) { boolean old = this.isZoomButtonsVisible(); this.zoomButtonsVisible = zoomButtonsVisible; zoomInButton.setVisible(zoomButtonsVisible); zoomOutButton.setVisible(zoomButtonsVisible); firePropertyChange("zoomButtonsVisible", old, this.isZoomButtonsVisible()); } /** * Sets the tile factory for both embedded JXMapViewer components. Calling this method will also reset the center * and zoom levels of both maps, as well as the bounds of the zoom slider. * @param fact the new TileFactory */ public void setTileFactory(TileFactory fact) { mainMap.setTileFactory(fact); mainMap.setZoom(fact.getInfo().getDefaultZoomLevel()); mainMap.setCenterPosition(new GeoPosition(0, 0)); miniMap.setTileFactory(fact); miniMap.setZoom(fact.getInfo().getDefaultZoomLevel() + 3); miniMap.setCenterPosition(new GeoPosition(0, 0)); zoomSlider.setMinimum(fact.getInfo().getMinimumZoomLevel()); zoomSlider.setMaximum(fact.getInfo().getMaximumZoomLevel()); } /** * @param pos the new center position */ public void setCenterPosition(GeoPosition pos) { mainMap.setCenterPosition(pos); miniMap.setCenterPosition(pos); } /** * @return the center geo position */ public GeoPosition getCenterPosition() { return mainMap.getCenterPosition(); } /** * @return the adress location */ public GeoPosition getAddressLocation() { return mainMap.getAddressLocation(); } /** * @param pos the address location */ public void setAddressLocation(GeoPosition pos) { mainMap.setAddressLocation(pos); } /** * Returns a reference to the main embedded JXMapViewer component * @return the main map */ public JXMapViewer getMainMap() { return this.mainMap; } /** * Returns a reference to the mini embedded JXMapViewer component * @return the minimap JXMapViewer component */ public JXMapViewer getMiniMap() { return this.miniMap; } /** * returns a reference to the zoom in button * @return a jbutton */ public JButton getZoomInButton() { return this.zoomInButton; } /** * returns a reference to the zoom out button * @return a jbutton */ public JButton getZoomOutButton() { return this.zoomOutButton; } /** * returns a reference to the zoom slider * @return a jslider */ public JSlider getZoomSlider() { return this.zoomSlider; } /** * @param b the visibility flag */ public void setAddressLocationShown(boolean b) { boolean old = isAddressLocationShown(); this.addressLocationShown = b; addressLocationPainter.setVisible(b); firePropertyChange("addressLocationShown", old, b); repaint(); } /** * @return true if the address location is shown */ public boolean isAddressLocationShown() { return addressLocationShown; } /** * @param b the visibility flag */ public void setDataProviderCreditShown(boolean b) { boolean old = isDataProviderCreditShown(); this.dataProviderCreditShown = b; dataProviderCreditPainter.setVisible(b); repaint(); firePropertyChange("dataProviderCreditShown", old, b); } /** * @return true if the data provider credit is shown */ public boolean isDataProviderCreditShown() { return dataProviderCreditShown; } @SuppressWarnings("unchecked") private void rebuildMainMapOverlay() { CompoundPainter<JXMapViewer> cp = new CompoundPainter<JXMapViewer>(); cp.setCacheable(false); /* * List<Painter> ptrs = new ArrayList<Painter>(); if(isDataProviderCreditShown()) { * ptrs.add(dataProviderCreditPainter); } if(isAddressLocationShown()) { ptrs.add(addressLocationPainter); } */ cp.setPainters(dataProviderCreditPainter, addressLocationPainter); mainMap.setOverlayPainter(cp); } /** * @param prov the default provider */ public void setDefaultProvider(DefaultProviders prov) { DefaultProviders old = this.defaultProvider; this.defaultProvider = prov; if (prov == DefaultProviders.SwingLabsBlueMarble) { setTileFactory(new CylindricalProjectionTileFactory()); setZoom(3); } if (prov == DefaultProviders.OpenStreetMaps) { TileFactoryInfo info = new OSMTileFactoryInfo(); TileFactory tf = new DefaultTileFactory(info); setTileFactory(tf); setZoom(11); setAddressLocation(new GeoPosition(51.5, 0)); } firePropertyChange("defaultProvider", old, prov); repaint(); } /** * @return the default provider */ public DefaultProviders getDefaultProvider() { return this.defaultProvider; } private AbstractPainter<JXMapViewer> dataProviderCreditPainter = new AbstractPainter<JXMapViewer>(false) { @Override protected void doPaint(Graphics2D g, JXMapViewer map, int width, int height) { g.setPaint(Color.WHITE); g.drawString("data ", 50, map.getHeight() - 10); } }; private WaypointPainter<Waypoint> addressLocationPainter = new WaypointPainter<Waypoint>() { @Override public Set<Waypoint> getWaypoints() { Set<Waypoint> set = new HashSet<Waypoint>(); if (getAddressLocation() != null) { set.add(new DefaultWaypoint(getAddressLocation())); } else { set.add(new DefaultWaypoint(0, 0)); } return set; } }; /** * @param args the program args */ public static void main(String... args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JXMapKit kit = new JXMapKit(); kit.setDefaultProvider(DefaultProviders.OpenStreetMaps); TileFactoryInfo info = new OSMTileFactoryInfo(); TileFactory tf = new DefaultTileFactory(info); kit.setTileFactory(tf); kit.setZoom(14); kit.setAddressLocation(new GeoPosition(51.5, 0)); kit.getMainMap().setDrawTileBorders(true); kit.getMainMap().setRestrictOutsidePanning(true); kit.getMainMap().setHorizontalWrapped(false); ((DefaultTileFactory) kit.getMainMap().getTileFactory()).setThreadPoolSize(8); JFrame frame = new JFrame("JXMapKit test"); frame.add(kit); frame.pack(); frame.setSize(500, 300); frame.setVisible(true); } }); } }