Tuesday, January 11, 2011

Living in Keru - Another late night session on the API, Episode 1

Your properties, mapped (1/3): The basics of "Search"

All right, so you are a real estate agent or developer and all of your offers have been included with casa.keru - nice!

But wouldn't it be great to have this same cool bells and whistles map representation of your properties on your own web site?

"Of course", you will say, "but isn't that terribly complicated?"

Long answer: No.

Today we'll talk about integrating casa.keru maps into your web site - it will only take 20 minutes. This is what the result will look like:


Here we go … we will build a single small HTML page presenting all of your properties for sale on a map, allowing for basic yet complete user interaction.

Prerequisites: Besides some  basic knowledge of HTML and JavaScript, an HTML editor is essential for this session. In case you don't have one installed, notepad.exe will do. Other suggested tools include the Firefox browser with the latest Firebug Add-on (1) installed.

First, we create a very basic HTML structure which marks the starting point for any HTML document:

<html>
<head>
<title>My own casa.keru property map</title>
</head>
<body>
</body>
</html>
Listing 1

Now, we'll add some content to the page in three easy steps:
  • Step 1: The HTML
  • Step 2: Some Includes
  • Step 3: The JavaScript logic

1) The HTML

Creating a Google map within our web page is very easy. Inside the <body> section of our code (somewhere between the <body> and </body> tags), we create a <div> that will later contain the map. Always specify the required dimensions; in this example the map will be 800 pixels wide and 400 pixels high.

<div id="map1" style="width:800px;height:400px;"></div>
Listing 2

Yes, that's right: The total HTML fits in just one line of code.

2) Some includes

In order to make the Google map come alive, we need to include the maps library with the HTML document. Also needed is the jquery (2) library which will make the connection between our page and the casa.keru server.

Insert the following block of code within the <head> section of your HTML document, right after the <title>:

<script type="text/javascript" src="http://www.google.com/jsapi?key=null"></script>
<script type="text/javascript">
  google.load("maps", "2.x", {"language" : "PT"});
  google.load("jquery", "1.4.4");
</script>
Listing 3

3) The JavaScript logic

For the map to come alive, we will need to put some logic into the page. The JavaScript code should not execute before the document is ready (fully loaded), so all of the code will go into the so called ready function:

<script type="text/javascript">
$(document).ready(function(){
  // one after another, insert all of the following code here
});
</script>
Listing 4

In step 1 and 2 we put both the maps container and library in place. We can now go ahead and initialize the map, put it into "hybrid" mode (satellite imagery with street names), add the standard user interface (zoom, panning, map type controls, etc.), define the viewport, and center the map which is necessary to draw it for the first time.

// initialize map
var map = new GMap2(document.getElementById("map1"));
map.setMapType(G_HYBRID_MAP);
map.setUIToDefault();
// set initial viewport, e.g. the Algarve
var algarveBounds = new GLatLngBounds(new GLatLng(36.94, -9.01), new GLatLng(37.53, -7.39)); //SW, NE
map.setCenter(algarveBounds.getCenter(), map.getBoundsZoomLevel(algarveBounds));
Listing 5

Save the HTML document and refresh it in your browser – voilá, we already got an interactive map in our page!

But where are the markers?

By this time, we are ready to request all of our properties from the casa.keru server in order to display the markers on the map. We need to have our user id provided by the keru team available (it is usually a four letter code like "ABCD").

We will put the request into a function called search() - this way, we can update the markers any time by simply calling this function, e.g. when the map viewport or zoom level changes.

"Who are you and what do you want?" I hear the server asking. So we need to give him some information before he can return the requested marker information.

Here's the information we provide below in Listing 6:
  • Our user id (UserID: "ABCD")
and the information we need ...:
  • markers, obviously (ResponseDetails: "Map")
  • limited to properties for sale (BusinessType: "SALE")
  • and particular property types (PropertyType: "Apartments, ...")
  • and narrowed by price (MinPrice/MaxPrice)
Additionaly, with every (!) single request, we need to pass the current viewport and dimensions of our map. The casa.keru server will spend some milliseconds on this information in order to deliver perfectly clustered items back to you.

Here's what the AJAX (3) call looks like:

// request your markers
function search() {
                   
  // call the casa.keru server
  $.ajax({
    url: "http://arrakis.tredix.com:59180/apache-tomcat/Tredix/ISS?Context=Tredix/IFS/ImmoPT/ProtoTyp2/Search",
    dataType: "jsonp",
    jsonp: "jsoncallback",
    scriptCharset: "utf-8",
    contentType: "application/json",
    data: {

      // your user id
      UserID: "ORBL", // e.g. Orbial - Soc. Mediação Imobiliária, Lda

      // request the results sets you need (map, list, tags, translations ...)
      ResponseDetails: "Map",

      // apply your filters (there are many more parameters and options ...)
      BusinessType: "SALE",
      PropertyType: "Apartments, DetachedHousesVillas, Townhouses, Lands, Ruins, FarmsEstates, CommercialProperties, Garages",
      MinPrice: 0,
      MaxPrice: 0, // == any

      // clustering needs map dimensions & viewport (mandatory for each request)
      ViewportLatitudeSouth: map.getBounds().getSouthWest().lat(),
      ViewportLongitudeWest: map.getBounds().getSouthWest().lng(),
      ViewportLatitudeNorth: map.getBounds().getNorthEast().lat(),
      ViewportLongitudeEast: map.getBounds().getNorthEast().lng(),
      MapDimensionX: $("#map1").width(),
      MapDimensionY: $("#map1").height()

    },
...
Listing 6

In response to our request the server will now return all markers for your current map size and zoom level. To prevent individual markers from being stacked, some might get combined into clusters if necessary. This is a really cool and pretty unique feature once you think about it. For the moment we need to understand that we are looking at two different types of markers:

MapHits representing one single property, and
MapClusters containing two or more properties.

Apart from the latitude/longitude coordinates, the casa.keru server also deliveres many more relevant details about each marker, e.g. title and your reference for a MapHit or the number of properties contained in a MapCluster.

The following code will clear all markers from the map and paint a new icon ("G" as in geo point) for each MapHit on your map. Since these are all individual properties, we'll add some information (title plus ref) in the markers' tooltips.

Additionally, we will register a click event for each marker. The code redirects to the real estate web site's search for the corresponding ref. So if you click on the marker, you go straight to the details of the property. This is just one out of many examples how to connect casa.keru information with your own content.

    success:function(data)
    {
      // clear map
      map.clearOverlays();

      // display geo referenced lat/lng objects (MapHits)
      if (data.SearchResult.MapHits!=undefined) {
        $.each(data.SearchResult.MapHits, function(i,item)
        {
          var geoPoint  = new GLatLng(item.Latitude,item.Longitude);
          var geoIcon   = new GIcon(G_DEFAULT_ICON);
          geoIcon.image ="http://www.google.com/mapfiles/markerG.png";
          var geoTitle  = item.Title + " (Ref. " + item.PropertyID + ")";
          var geoMarker = new GMarker(geoPoint, {
            title: geoTitle, 
            icon:geoIcon
          });
          map.addOverlay(geoMarker);

          // add geopoint click handler to connect to your web site
          GEvent.addListener(geoMarker, "click", function() {
            // e.g. search for property's reference
            window.location = "http://www.realestatealbufeira.com/pt/listagem.htm?ref="+item.PropertyID;
          });
        })
      }
Listing 7

We'll treat the MapClusters pretty much in the same way like the MapHits above (we are using "C" icons as in cluster). However, the click behaviour differs: When ever we click on a cluster, the map zooms in in order to eventually "spread" the cluster.

      // display clustered object groups (MapClusters)
      if (data.SearchResult.MapClusters!=undefined) {
        $.each(data.SearchResult.MapClusters, function(i,item)
        {
          var clusterPoint  = new GLatLng(item.Latitude,item.Longitude);
          var clusterIcon   = new GIcon(G_DEFAULT_ICON);
          clusterIcon.image = "http://www.google.com/mapfiles/markerC.png";
          var clusterTitle  = item.NumberOfObjects + " object/s";
          var clusterMarker = new GMarker(clusterPoint, {
            title: clusterTitle, 
            icon:clusterIcon
          });
          map.addOverlay(clusterMarker);

          // add cluster click handler to zoom into clusters
          GEvent.addListener(clusterMarker, "click", function() {
            map.setCenter(new GLatLng(item.Latitude,item.Longitude), map.getZoom()+1);
          });
        });
      }
    }
  })
}
Listing 8

Finally, it would be nice to see the markers updated when ever the user moves (drags) the map or zooms into or out of the map. We can easily listen for this kind of change through the dragend and zoomend events of the map. Once fired, they simply call the search() function which will update all MapHits and MapClusters immediately.

The following code should be inserted between Listing 5 and Listing 6:

// search() updates the markers on the map
search();

// update the map when the user changes the zoom level ...
GEvent.addListener(map, "zoomend", function() {
  search();
});

// ... or when the user drags the map / changes the viewport
GEvent.addListener(map, "dragend", function() {
  search();
});
Listing 9

That's it - the map application for your web site is all done! Wasn't that easy?

You can watch the demo here. It includes all the code we have just developed - just copy the source HTML of the page and paste it into your editor.

If you want to put your page straight into production, you will need to apply for your free personal Google Maps key (4) by providing Google with the domain name the map will run on (like www.yourdomain.com or maps.yourotherdomain.org).

In the next two episodes, we'll look into casa.keru's "Suggest" and "Area" services. Stay tuned.

PS: Ah, yes, you are finally asking about the price tag. Integrating your properties into your web site is 100% free. All you need to do is register your access with us. Please contact felix@tredix.com for further information.

Links:

1. Get the Firebug Add-on: http://getfirebug.com/
2. Learn about jQuery: http://www.jquery.com
3. A brief intro to AJAX: http://en.wikipedia.org/wiki/Ajax_(programming)
4. Obtaining your Google Maps key: http://code.google.com/intl/en-EN/apis/maps/signup.html

No comments:

Post a Comment