Wednesday, May 9, 2007

Embedding Google Maps in your Groovy application

Google provides a wide variety of API for embedding their applications into your web pages. They are very convenient if your are developing web applications but I find it very painful to embed them into any Java application. Hopefully as far as GMaps is considered, the swingx-ws project is providing a JXMapViewer class in which you can configure a tile provider for using the Google map servers. Let's use Groovy to build a small apps using Google geocoding and putting some information on a map.

Central to our small application is the JXMapViewer. Each mapviewer is associated to a tile factory which delivers the image pieces. Once configured, the mapviewer will take care of the rest querying the map server when required depending on your location. Configuring the tile factory is the more tricky part of the snipplet, here are all the arguments of the constructor:

def tfi = new TileFactoryInfo(0, 20, 17, 256, true, true,"can't disclose", "x", "y", "zoom")

The first four numbers to the TileFactoryInfo constructor represent the minimum zoom, the maximum zoom, the total zoom levels, and the tile size (very often a tile is a 256 pixels square) . The two booleans are used to indicate if the x coordinates go left to right or right to left and if the y coordinate goes from top to bottom or out from the equator. The rest of the parameters are for the base url and the name of the http parameters in the get request to fetch tiles.

Let's continue by defining our Swing interface including the JXMapViewer. Here the code defining our panel which includes a textfield (in which you could type an address), the widget containing the map viewer and two buttons for zooming in and out.


import java.awt.*
import java.awt.BorderLayout as BL

import javax.swing.*
import javax.swing.WindowConstants as WC
import javax.swing.JOptionPane as JOP
import javax.swing.BorderFactory as BF
import javax.swing.SwingUtilities as SU

import org.jdesktop.swingx.mapviewer.*
import org.jdesktop.swingx.JXMapViewer

import groovy.swing.SwingBuilder

def googleKey = "your google api key"

def mapViewer = new JXMapViewer()
def tfi = new TileFactoryInfo(...)

mapViewer.tileFactory = new DefaultTileFactory(tfi)
mapViewer.zoom = 5
mapViewer.centerPosition = [48.856558, 2.350966] // Paris

def swing = new SwingBuilder()
def frame = swing.frame(title: 'Groovy Maps',defaultCloseOperation:WC.DISPOSE_ON_CLOSE) {
panel(id: "mainPanel", layout: new BL()) {
panel(constraints: BL.NORTH, layout: new BL()) {
textField(id: "address", constraints: BL.CENTER, columns: 50,
border: BF.createTitledBorder("Address"), actionPerformed: {
def address = swing.address.text
// geocoding code here
}
widget(mapViewer)
panel(constraints: BL.SOUTH) {
button(text: "+", actionPerformed: { mapViewer.zoom -= 1 })
button(text: "-", actionPerformed: { mapViewer.zoom += 1 })
}
}
}
frame.pack()
frame.size = [800, 600]
frame.locationRelativeTo = null

frame.visible = true



Using the Google geocoder is pretty simple when using an http request to http://maps.google.com/maps/geo? with the following parameters in the URI:
# q, the address that you want to geocode,
# key, you API key,
# output , the format in which the output should be generated. In our example, we will use xml, the other options are kml, csv, or json.

In our case, the address will come from a texfield so the code looks like this:

textField(id: "address", constraints: BL.CENTER, columns: 50,
border: BF.createTitledBorder("Address"), actionPerformed: {
def address = swing.address.text

// geocoding
SU.invokeLater {
Thread.start {
def geocodingUrl = "http://maps.google.com/maps/geo?q=
{URLEncoder.encode(address)}&output=xml&key=${googleKey}".toURL()
def node = new XmlSlurper().parseText(geocodingUrl.text)
if (node.Response.Status.code == "200") {
def coord = node.Response.Placemark.Point.coordinates.text().
tokenize(',').collect{Float.parseFloat(it) }
mapViewer.centerPosition = coord[1..0]
}
}
}
})


Assemby all the pieces give you the global application ...

In conclusion, JXMapViewer is a powerful component that make it easy to embed maps in your groovy application. In a next stage, I will show you how to add more information in a different layer.

No comments: