ADF 11g RichFaces – Creating a googleMaps Mashup Part I: clientListeners and clientAttributes

3

While creating the itinerary for my next trip I had to look for things like campgrounds and gasstations on my route. For this I use google Maps. It wasn’t the first time I did this, however this time I wondered if it was possible to integrate googleMaps in an ADF 11g application. It turned out that it wasn’t that difficult at all. I decided to share my findings here. In this part I will show you how you can use <af:clientListener/> and <af:clientAttribute/> to pinpoint a location in your ADF application on the map.....

The first thing I need is a table containing the geographical data that I want to show on the map.

  CREATE TABLE "MAPLOCATIONS"
   ("DEPARTMENT_NAME" VARCHAR2(30 BYTE) NOT NULL ENABLE,
    "STREET_ADDRESS" VARCHAR2(40 BYTE),
    "CITY" VARCHAR2(30 BYTE) NOT NULL ENABLE,
    "POSTAL_CODE" VARCHAR2(12 BYTE),
    "STATE_PROVINCE" VARCHAR2(25 BYTE),
    "LONGITUDE" NUMBER(9,6),
    "LATITUDE" NUMBER(9,6)
   )

There are two columns in this new table, LONGITUDE and LATITUDE  that I use to hold the coordinates of the actual location.

Lets put some data in the table.

Insert into MAPLOCATIONS ("DEPARTMENT_NAME","STREET_ADDRESS","CITY","POSTAL_CODE","STATE_PROVINCE","LONGITUDE","LATITUDE") values ('Oracle HQ','500 Oracle Parkway','Redwood Shores','CA 94065', null, -122.262168 , 37.530480);
Insert into MAPLOCATIONS ("DEPARTMENT_NAME","STREET_ADDRESS","CITY","POSTAL_CODE","STATE_PROVINCE","LONGITUDE","LATITUDE") values ('Oracle Nederland','Rijnzathe 6','de Meern','3454PV',null ,5.052166,52.071718);
Insert into MAPLOCATIONS ("DEPARTMENT_NAME","STREET_ADDRESS","CITY","POSTAL_CODE","STATE_PROVINCE","LONGITUDE","LATITUDE") values ('AMIS','Edisonbaan 15','Nieuwegein','3439MN','Utrecht',5.098922,52.033576);
Insert into MAPLOCATIONS ("DEPARTMENT_NAME","STREET_ADDRESS","CITY","POSTAL_CODE","STATE_PROVINCE","LONGITUDE","LATITUDE") values ('My next destination','Flamingo Lodge hwy','Everglades national park',null, 'Florida' , -80.836029,25.210822);

With the database part in place I now create a new ADF Fusion web application, an entity object and viewobject based on the mapLocations table, and I publish the viewobject in the applicationmodule. I Create a new page and call the page googleMapsMashup, and I drop the mapLocations collection from the datacontrol pallete onto the page as an ADF readonly table.

Now it’s all set up to create the mashup. For that I need a couple of things. First I have to sign up for a Google Maps API key at http://code.google.com/apis/maps. The call to the googleMaps javascript API, and the API key have to be included in the ADF page. It is best practice to add JavaScript into the metaContainer facet of the <af:document> element.

&lt;f:facet name="metaContainer"&gt;
    &lt;af:group&gt;
        &lt;trh:script source="http://www.google.com/jsapi?key=ABCDEFG"&gt;&lt;/trh:script&gt;
    &lt;/af:group&gt;
&lt;/f:facet&gt;

Now it’s time to add a component that will render the map on the page. Lets use a div to do that.

&lt;div id="map" style="width: 400px; height: 400px"&gt;&lt;/div&gt;

This <div> with the id ‘map’ will be used in javascript to create the actual map. Put the code below in the metaContainer facet

  &lt;trh:script&gt; google.load("maps", "2.x");
  // Call this function when the page has been loaded
  function initialize() {
       var map = new google.maps.Map2(document.getElementById("map"));
       map.setCenter(new google.maps.LatLng(0,0), 1);
       map.addControl(new GLargeMapControl());
       map.addControl(new GMapTypeControl());
       }
      google.setOnLoadCallback(initialize);
  &lt;/trh:script&gt;

When I run the page now the map is in place. However, when I select any of the rows in the table, nothing happens on the map. To create the interaction between the table and the map I need to create some kind of a connection between the two. The map has to know what the coordinates of the selected location are. I use the clientAttribute to provide that information. It’s a very simple way of using information like rownumbers or other values from an ADF table in a javascript function. I add the clientAttributes to the first column of the table.

&lt;af:column sortProperty="DepartmentName" filterable="true" sortable="true"
        headerText="#{bindings.MaplocationsView1.hints.DepartmentName.label}"&gt;
    &lt;af:outputText value="#{row.DepartmentName}"&gt;
        &lt;af:clientAttribute name="lat" value="#{row.Latitude}"/&gt;
        &lt;af:clientAttribute name="long" value="#{row.Longitude}"/&gt;
    &lt;/af:outputText&gt;
&lt;/af:column&gt;

It is also nessecary to call a javascript function that activates the map upon selecting a row in the table. To actually call this javascript function that recenters the map I use the <af:clientListener>.

   &lt;af:clientListener method="doNavigate" type="click"/&gt;

Finally I need to add the doNavigate function to the page. I goes in the same place as the previous javascript functions. What it does is actually read the values of the two defined client attributes by calling getSource().getProperty(“”), create a latlong variable that is used to put a marker on the exact location. Finally addControl and setCenter will create some controls and center the map.

&lt;trh:script&gt;
   function doNavigate(evt)
      {long = evt.getSource().getProperty("long");
       lat = evt.getSource().getProperty("lat");

       var latlng = new GLatLng(lat,long);
       var map = new google.maps.Map2(document.getElementById("map"));

       map.addControl(new GLargeMapControl());
       map.addControl(new GMapTypeControl());

       map.setCenter(new GLatLng(0,0), 1);
       map.addOverlay(new GMarker(latlng));
   }
&lt;/trh:script&gt;

On clicking a row the function doNavigate is called, and because the clientAttributes lat and long contain the coordinates of the selected row, the map will now place a pointer on exactly the location of the selected row !

reLocate

reLocate

This is not the most fancy map for viewing the locations. It is easy however to show a full blown sattelite image of the selected location. The only thing I have to do is changes some settings in the doNavigate function. First I make sure to center the map at the coordinates of the selected location, and zoom in a litle more. This is achieved by the following line of javascript.

map.setCenter(new GLatLng(lat,long), 16);

Finally I make sure that the map is initially shown as a sattelite image.

map.setMapType(G_SATELLITE_MAP);

When I select Oracle HQ I get a sattelite image of the Oracle HQ.

Oracle HQ

Oracle HQ

In the next part I will explain how to control the map type from within the ADF application and how to add context dependent pointers.

References:

A Sample workspace can be downloaded here.

http://code.google.com/apis/maps/

 

Share.

About Author

Luc Bors is Expertise Lead ADF and technical specialist/architect at AMIS, Nieuwegein (The Netherlands). He developed several Workshops and training on ADF and also is an ADF and JHeadstart instructor. Luc is a member of the ADF Methodology group and publishes articles on ADF in oracle technology related magazines, on the AMIS technology blog, (http://technology.amis.nl/blog).

3 Comments

  1. Hi, where do you call initialize() method?
    this method is returning null: document.getElementById(“map”)
    Can you help? Thanks

  2. JairoCortes on

    Hi Luc,
    This article is very insteresting. But I don´t know do it to run. Please, can you help me with a JDeveloper app. sample?