Building Maps into Your Swing Application with the JXMapViewer Blog

Версия 2


    Since the early days of navigation, maps have played a vital part of commerce. A sailor without a map was completely lost. Without a map, a land owner wouldn't know what they owned. Thomas Jefferson even sent Lewis and Clark on a two-year trip across the entire North American continent to bring back accurate maps. Despite this long history of mapping, things are changing quickly. Thanks to recent innovations in devices, networks, and satellites, mapping technology is set to completely explode with new ideas and applications. Google really kicked off this mapping explosion with the release of Google Mapsand their acquisition of 3D mapping company Keyhole (now called Google Earth). A few enterprising developers quickly began hacking on Google Maps, creating a new application type, the mashup. However, Google Maps mashups were just the beginning.

    Many websites now provide all sorts of interesting data that can be searched, indexed, and visualized geographically. Flickr, Craigslist, and Wikipedia are just a few of the many providers of geodata. Yet despite all of the many ways people generate and use geographic data, there is one common component: the map viewer. Though much of the attention has been focused on Ajax maps from Yahoo and Google, Swing has its own mapping component, the open source JXMapViewer. Originally created for a JavaOne demo, the JXMapViewer can let you embed mapping abilities into your own Swing-based Java application (or applet). By the end of this article, you will know how to build and run a simple Swing application using the JXMapViewercombined with new features in NetBeans 6 that can greatly increase your productivity.

    Building a Basic Application

    The JXMapViewer is an open source (LGPL) Swing component created by the developers at SwingLabs. At its core, theJXMapViewer is a special JPanel that knows how to load map tiles from an image server. All of the details of how to convert coordinates to pixels, cache tiles, and stitch them together on screen are nicely hidden insideJXMapViewer's API. All you need to do is add it to your Swing application the way you would with any otherJPanel.

    In this article, we will build a simple program that shows a map and lets you zoom and pan around. We will also add a few controls to show locations on the map with custom code. You can see what the application looks like in Figure 1.

    Figure 1. Basic Map Application
    Figure 1. Basic map application

    The easiest way to work with the JXMapViewer is by using a recent build of NetBeans 6, which you can get from the NetBeans download page. You must use Beta 2 to get the JNLP support used at the end of this article. Like other SwingLabs projects, theJXMapViewer will work with any IDE or Java development tool, but this article will use NetBeans because recently added features in NetBeans 6 will greatly increase your productivity and let you build complex programs very quickly.

    After you have NetBeans 6 installed and running, create a new project and choose the Java Desktop Application project type (Figure 2). Accept the default Application Shell type of Basic Application (Figure 3).

    Figure 2. Creating a Desktop Java Application project
    Figure 2. Creating a Desktop Java Application project (click for full-size image)

    Figure 3. Using the Basic Application shell
    Figure 3. Using the Basic Application shell (click for full-size image)

    You will now have a basic desktop application with a default form containing a menu bar, status label, and prefab resource bundles (Figure 4).

    Figure 4. Empty Java desktop application
    Figure 4. Empty Java desktop application

    Adding the JXMapKit

    Now download the latest weekly build of swingx-wsfrom the SwingLabs download page and unzip it in a lib directory inside of your project. You can add the .jars to your project by right-clicking on the Libraries node in the Projectsinspector and choosing Add Jar/Folder. (Figure 5). You will need to add the swingx-ws-2007_10_14.jar (the exact name may be different, depending on which weekly build you downloaded). You must also add the support .jars (swingx-bean.jar, swingx.jar, andswing-worker.jar) to thelib/swingx-ws-[YY_MM_DD]-bin/lib/cobundle directory of your project.

    Figure 5. Empty Java desktop application
    Figure 5. Empty Java desktop application

    Now that the .jars are added to your project, you can add theJXMapKit to your form (I'll explain in a second why we are using the JXMapKit instead of theJXMapViewer). One of the new features of NetBeans 6 is the ability to add components directly from your library .jars without having to add them to the palette first. Navigate through the class hierarchy of the SwingX-WS .jar in the Projects inspector to find the org.jdesktop.swingx.JXMapKit class(Figure 6).

    Figure 6. Find the JXMapKit class
    Figure 6. Find the JXMapKit class

    Once you have found the class, you can drag it directly into your form. NetBeans will create a new instance of theJXMapKit and add it (Figure 7). Note that the drag operation will only work if all of the .jars are inside of your project directory. That's why you must move them all to the[projectdir]/lib directory first.

    Figure 7. Dragging the JXMapKit into the form
    Figure 7. Dragging the JXMapKit into the form (click for full-size image)

    In this example, I'm using the JXMapKit class instead of the JXMapViewer because the kit version includes zoom buttons, a zoom slider, and a mini-view. TheJXMapKit is just a wrapper for theJXMapViewer that includes the most commonly used features. Once you have added the component, you can resize it to fill the form.

    Now press the triangle-shaped run button or selectRun->Run Main Project from the main menu to see your program running (Figure 8). You can drag the map around and also zoom in and out. That's it! This is your first mapping application.

    Figure 8. Basic Map Application
    Figure 8. Basic map application

    Customizing the Map

    Now that you have a map application, you might want to customize it. Fortunately, the JXMapKit has many customization options. The first things you might want to change are the visible control components. There are properties to turn on and off the mini-map, zoom slider, and zoom buttons. For example, if you wanted to show the map in a smaller space, you could turn off the zoom slider and mini-map but leave the zoom buttons visible. You can set these properties in the Property Sheet to the left of the form editor.

    Re-Centering and Adding Waypoints

    Now that you have a map, you probably want to do something with it. The two basic operations supported by theJXMapViewer are moving the map and adding markers. To move the map, you can use the setAddressLocation()method. New features in NetBeans 6 make it very easy to tie a button to the map.

    Let's make a button that will center the map on Chicago. Just add a button to the form from the palette, and then right-click the button and choose Set Action... to open the Action editor for that button. In the Action to edit combo box, chooseCreate New Action. Next, type in the method namegoChicago and the text Go To Chicago. (Figure 9). Finally, press the OK button to close the Action editor. NetBeans will create the new empty goChicagomethod and jump to it.

    Figure 9. Creating a goChicago action
    Figure 9. Creating a goChicago action (click for full-size image)

    Type this code into the method body:

    jXMapKit1.setAddressLocation(new GeoPosition(41.881944,-87.627778));

    The GeoPosition class represents a coordinate on the globe expressed as a latitude and longitude. AllJXMapViewer APIs express coordinates using theGeoPosition class. You can find the coordinates of many cities and landmarks at Wikipedia. Each entry has coordinates in the sidebar summary on the right side of the screen under the map.

    Now run the application and press the Go To Chicagobutton. The map will re-center above Chicago using the coordinates I grabbed from Wikipedia(Figure 10).

    Figure 10. Centering on Chicago
    Figure 10. Centering on Chicago

    The JXMapKit tracks two different positions. Whenever you call the setAddressPosition() method, the map will move and set a marker on the selected point. You can also read the current center position of the map using thegetCenterPosition() method. The center position will change whenever the user moves around the map. The address position only changes when you call setAddressPosition().

    Adding Waypoints

    To make your map really useful, you need to draw points on it that represent locations. In the mapping world, coordinates that represent physical locations are called waypoints. Waypoints are represented with the WayPoint class. TheJXMapViewer has a special painter that can properly draw points on the map. Painters are classes that implement thePainter interface and can be set on a SwingX component to customize that component's drawing. JXMapViewer can accept painters using the setOverlayPainter() method. Below is an action method that will add the points for New York City and Chicago using the standardWaypointPainter.

    @org.jdesktop.application.Action public void addWaypoint() { //create a Set of waypoints Set<Waypoint> waypoints = new HashSet<Waypoint>(); waypoints.add(new Waypoint(41.881944,-87.627778)); waypoints.add(new Waypoint(40.716667,-74)); //crate a WaypointPainter to draw the points WaypointPainter painter = new WaypointPainter(); painter.setWaypoints(waypoints); jXMapKit1.getMainMap().setOverlayPainter(painter); }

    Note the call to jXMapKit1.getMainMap().JXMapKit is actually a wrapper for two instances of the JXMapViewer; one for the main map and one for the mini map. You can get access to those instances with thegetMainMap() and getMiniMap()methods.

    Using a Custom Waypoint Renderer

    By default, waypoints are drawn using a blue teardrop shape, but you may want to customize them with your own drawing code. You can easily do this by implementing the WaypointRendererinterface. Below is an addition to the code above where I have added a custom WaypointRenderer to the painter that draws each waypoint as a red "X."

    painter.setWaypoints(waypoints); painter.setRenderer(new WaypointRenderer() { public boolean paintWaypoint(Graphics2D g, JXMapViewer map, Waypoint wp) { g.setColor(Color.RED); g.drawLine(-5,-5,+5,+5); g.drawLine(-5,+5,+5,-5); return true; } }); jXMapKit1.getMainMap().setOverlayPainter(painter); 

    The WaypointPainter does all necessary coordinate calculations and pre-translates the Graphics2D object before calling your paintWaypoint() method. This means the center of the waypoint will be at 0,0, so creating a ten-pixel "X" is easily accomplished by drawing from -5 to +5. References to the map and current waypoint are provided in case your code needs to conditionally draw certain waypoints differently. The return Boolean is not currently used so you can just returntrue.

    Using Alternate Map Servers

    By default the JXMapKit uses a copy of NASA's Blue Marble satellite images hosted on a SwingLabs server. The Blue Marble data only goes to 8-km resolution, however. Another option is the tile server, which serves up a vector map of the world created by volunteers with GPS receivers. JXMapKit is preconfigured with both maps so you can switch between them by setting the defaultProvider property in the Property Sheet.

    You can also select custom as thedefaultProvider to use your own map server, but this is a more complicated task that I will cover in a future article. If you select the OpenStreetMaps, your application will look like Figure 11.

    Figure 11. Using the OpenStreetMaps server
    Figure 11. Using the OpenStreetMaps server

    Deploying Your Application

    Now that you have built a cool mapping application, you probably want to share it on the Web. One of the great new features in NetBeans 6 is support for Java Web Start deployment. To use it, you must turn on Web Start by going to the Project Properties, selecting the Web Start tab, and checking the "Enable Web Start" checkbox (Figure 12). Then you should change the codebase to "User defined (e.g. HTTP deployment)," type in the base URL where you will upload your application, and then check the "Self-signed" checkbox. Now you can build the project and upload the contents of your project's dist directory to your web server.

    Figure 12. Enabling Java Web Start
    Figure 12. Enabling Java Web Start (click for full-size image)

    Once your application is uploaded to your web server, you can point your browser at the uploaded JNLP file. For example, I uploaded my application, so the JNLP URL is You can test my copy of the program here.

    Future Work

    Thanks to recent innovations in wireless networks, GPS receivers, and general web technology, mapping is becoming cheaper and more flexible. Many people believe that mapping will eventually become a part of the fabric of the internet. Nokia believes this so much it recently paid over eight billion dollars to buy one of the premier map vendors, Navteq. And the OpenStreetMap project, mentioned earlier, has attracted a group of volunteers to the huge undertaking of building a completely free and open map of the world. I highly encourage you to check them out and consider contributing.

    Mapping is becoming so important that the ability to work with maps and geocoded data will one day be a part of every software platform. Fortunately, with the JXMapViewer you can easily build mapping into your own Java applications today. Come back for my next article, where I will show you how to plug in a custom tile server, perform coordinate transformations, add rollovers and animation, and build mashups with several popular web services.