Skip to main content

Building Maps into Your Swing Application with the JXMapViewer

October 30, 2007

{cs.r.title}



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 Maps and 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 JXMapViewer combined 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, the JXMapViewer 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 inside JXMapViewer's API. All you need to do is add it to your Swing application the way you would with any other JPanel.

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, the JXMapViewer 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-ws from 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 Projects inspector 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, and swing-worker.jar) to the lib/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 the JXMapKit to your form (I'll explain in a second why we are using the JXMapKit instead of the JXMapViewer). 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 the JXMapKit 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. The JXMapKit is just a wrapper for the JXMapViewer 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 select Run->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 the JXMapViewer 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, choose Create New Action. Next, type in the method name goChicago and the text Go To Chicago. (Figure 9). Finally, press the OK button to close the Action editor. NetBeans will create the new empty goChicago method 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. All JXMapViewer APIs express coordinates using the GeoPosition 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 Chicago button. 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 the getCenterPosition() 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. The JXMapViewer has a special painter that can properly draw points on the map. Painters are classes that implement the Painter 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 standard WaypointPainter.

@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 the getMainMap() 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 WaypointRenderer interface. 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 return true.

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 OpenStreetMap.org 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 the defaultProvider 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 to projects.joshy.org/articles/MapApp, so the JNLP URL is http://projects.joshy.org/articles/MapApp/launch.jnlp. 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.

Resources

Josh Marinacci first tried Java in 1995 at the request of his favorite TA and has never looked back.
Related Topics >> Swing   |   

Comments

hi I followed the

hi I followed the instructions. but getting trouble in dragging and dropping the JXMapkit into the form . all specified .jar files added in Library ,But It isn't working. help me.

i don't get the map when i

i don't get the map when i drag and drop the JXMap kit onto the form....

did you create the lib folder

did you create the lib folder inside your netbeans project folder? Re-read the instruction if you have not.

does application using google

does application using google map in their applications can run without getting launch on web. I am having a problem i am not able to view the google map please help.

Sir I was following your

Sir I was following your steps for embedding google maps in swing application but drag and drop of component is not working in netbeansIDE 6.8 I am waiting for your reply with warm regards raju krishna

g

g

Project cannot be run with

Project cannot be run with non-local codebase. how can ı solve this ?

Hi, I tried this project but

Hi,
I tried this project but I am getting a runtime error like this :
Exception in thread "AWT-EventQueue-0" java.lang.NoSuchMethodError: org.jdesktop.swingx.painter.AbstractPainter.<init>(Z)V
at org.jdesktop.swingx.JXMapKit$10.<init>(JXMapKit.java:581)
at org.jdesktop.swingx.JXMapKit.<init>(JXMapKit.java:581)
at mapapp.MapView.initComponents(MapView.java:117)
at mapapp.MapView.<init>(MapView.java:36)
at mapapp.MapApp.startup(MapApp.java:19)
at org.jdesktop.application.Application$1.run(Application.java:174)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

By looking to this error it seems that JVM could not able to find the method in that class, but this I could not able to understand if the jar file is there and in that jar file this class is also present then why the method could not be found ?
Please suggest me.