Skip to main content

Using Google Maps Places API and ColdFusion's CFMAP to render places of interests

Google announced the Places API recently at Google I/O (2011) and I was looking into this, to see how this API can be used in conjunction with ColdFusion maps created with CFMAP. The Places API can be used to retrieve place information which includes:
  • Places of interests such as parks, restaurants, hospitals which are nearby to the users location.
  • More detailed information on the place, such as the address, phone number etc,.
The API can also be used to perform check-in at a particular place and to add\delete a place. These check-ins can then be used to evaluate the popularity of the place. In this post I'll explain how to retrieve the places of interests and displaying the same on a ColdFusion map using CFMAP.


Place Search Requests - retrieving the places of interests near a user's location:
You can send a HTTP request to the URL of the form:

https://maps.googleapis.com/maps/api/place/search/output?parameters

Here the user has an option of specifying the output format as either json or xml and is required to pass a few parameters:
  • key (required): The application's API key. The Places API uses this information to identify your application.
  • location (required): This will be the latitude and longitude information of a particular place around which the places of interests are to be found.
  • radius (required): to specify the radius within which the places of interests are to be found. The value specified will be considered in meters.
  • sensor (required): to indicate whether the place request is from a device using the location sensor. It can be either true or false.
  • types (optional): the user might be interested in various types of businesses such as library, park, gym etc,. You can also specify multiple types which are separated by a '|' (type1|type2|type3).
  • name (optional): A term to be matched against the names of places. This will restrict the results to contain only those with the specified name.
  • language (optional): The language code to indicate the language in which the results are to be returned. 
With the above information, you can issue a HTTP request using ColdFusion's cfhttp tag:

 <cfhttp url="https://maps.googleapis.com/maps/api/place/search/json"  
         method="get"  
         result="gmapData">  

      <cfhttpparam type="url"  
                   name="location"  
                   value="-33.8670522,151.1957362">  
      <cfhttpparam type="url"  
                   name="types"  
                   value="doctor|book_store">  
      <cfhttpparam type="url"  
                   name="radius"  
                   value="2000">  
      <cfhttpparam type="url"  
                   name="sensor"  
                   value="false">  
      <cfhttpparam type="url"  
                   name="key"  
                   value="{API_Key}">  
 </cfhttp>  

For the purpose of this example, I have specified the latitude and longitude values for 'Sydney, Australia' (I've lived here!!) and have specified the type of business as doctor and book_store. The radius is specified as 2000 meters (2 Kms) and the sensor is set to false. The output format is specified as json.

The json response would contain three root elements: status, results and html_attributions. If there were no errors in performing the request operation and the response contained at least one result then the response status is set to "OK". The result element is an array of places sent in response to a request, this would include the place name, its geometry (latitude and longitude information), place id, reference, icon, types, vicinity.

The results array in the response can then be used to add places to the ColdFusion's map. However, on a Google Map when a user clicks on a location a popup is shown which includes the Address and the Phone number of the selected location. To get more details on a particular location, another request should be made to retrieve the place details such as address, phone number, rating.

Place Detail requests - retrieve place details:

Similar to the previous one, the HTTP request to retrieve the place details is:

https://maps.googleapis.com/maps/api/place/details/output?parameters

As mentioned earlier, output can be either json or xml. The reference value obtained from the previous HTTP call (Place Search request) is then passed as a parameter to retrieve the place details. Other required parameters include the sensor and the key. The cfhttp request to get the details is of the form:

 <cfloop array="#arrayResults#"  
         index="placesObject">  
      <cfhttp url="https://maps.googleapis.com/maps/api/place/details/json"  
              method="get"  
              result="placeDetails">  
           <cfhttpparam type="url"  
                        name="reference"  
                        value="#placesObject.reference#">  
           <cfhttpparam type="url"  
                        name="sensor"  
                        value="false">  
           <cfhttpparam type="url"  
                        name="key"  
                        value="{API_Key}">  
      </cfhttp>  
      <cfset placeDetails = #deserializeJSON(placeDetails.fileContent).result#>  
      <cfset arrayAppend(windowContent,   
                "<h3>" & placeDetails.name & "</h3><br><h5>" & placeDetails.formatted_address &   
 "<br>Phone: " & placeDetails.formatted_phone_number & "</h5>")/>  
 </cfloop>  

As seen in the above code, the arrayResults containing the results of the place search request is iterated in the cfloop tag. The reference value in the arrayResults is then used in each iteration to get the place details. The place details are then used populate the windowContent array, which contains the html markup to show when the user clicks on any of the map item.

The CFMAP and CFMAPITEM tag can then be used to render a Google map and add places of interests to the map:

 <cfmap name="myMap"  
        centerlatitude="-33.8670522"  
        centerlongitude="151.1957362"  
        tip="Sydney"  
        width="800"  
        height="700"  
        zoomlevel="16">  
      <cfloop array="#arrayResults#"  
             index="mapObject">  
           <cfmapitem name="#mapObject.name#"  
                      latitude="#mapObject.geometry.location.lat#"  
                      longitude="#mapObject.geometry.location.lng#"  
                      tip="#mapObject.name#"  
                      markerwindowcontent="#windowContent[count++]#"  
                      markericon="#mapObject.icon#">  
      </cfloop>  
 </cfmap>  

The CFMAPITEM tag is used to add places of interests on the map using the latitude and longitude information obtained from the place search request. The markerwindowcontent attribute would contain the address and the phone number information obtained from place detail request. The map rendered would look similar to the one shown below:



Comments

  1. I'm struggling with getting this to work.  I have tried to use the exact code above (except substituting API_Key for my Google Maps API key) and I get an error - "Variable ARRAYRESULTS is undefined."  Granted, I'm a novice at ColdFusion (and brand new to CFMAP), so I apologize in advance if this is a stupid rookie mistake...

    ReplyDelete
  2. John, the response that you receive from the HTTP request has to be de-serialized. Try putting  before the cfloop tag. I think that would fix it. Let me know if it doesn't I'll send you the cfm file.

    ReplyDelete
  3. Thanks so much, but now I get an error with this CFSET that says "Complex object types cannot be converted to simple values."

    ReplyDelete
  4. Let me know your email id, I'll send the cfm file to you. You can send me your email id through the 'Contact Me' page as well.

    ReplyDelete

Post a Comment

Popular posts from this blog

Adding beforeRender and afterRender functions to a Backbone View

I was working on a Backbone application that updated the DOM when a response was received from the server. In a Backbone View, the initialize method would perform some operations and then call the render method to update the view. This worked fine, however there was scenario where in I wanted to perform some tasks before and after rendering the view. This can be considered as firing an event before and after the function had completed its execution. I found a very simple way to do this with Underscore's wrap method.

De-obfuscating javascript code in Chrome Developer Tools

I had blogged about JavaScript debugging with Chrome Developer Tools  some time back, wherein I have explained how these developer tools can help in debugging javascript code. Today Google Chrome 12 was released and my Chrome browser was updated to this version. As with every release, there have been some improvements made on performance, usability etc,. One feature that stood out for me is the ability to De-obfuscate the javascript code. What is Minification? Minification is the process of removing unnecessary characters such as white spaces, comments, new lines from the source code. These otherwise would be added to make the code more readable. Minifying the source code helps in reducing the file size and thereby reducing the time taken to download the file. This is the reason why most of the popular javascript libraries such as jQuery are minified. A minified jQuery file is of 31 KB in size where as an uncompressed one is about 229 KB. Unfortunately, debugging minified javascript f

On GraphQL and building an application using React Apollo

When I visualize building an application, I would think of using React and Redux on the front-end which talks to a set of RESTful services built with Node and Hapi (or Express). However, over a period of time, I've realized that this approach does not scale well when you add new features to the front-end. For example, consider a page that displays user information along with courses that a user has enrolled in. At a later point, you decide to add a section that displays popular book titles that one can view and purchase. If every entity is considered as a microservice then to get data from three different microservices would require three http  requests to be sent by the front-end app. The performance of the app would degrade with the increase in the number of http requests. I read about GraphQL and knew that it is an ideal way of building an app and I need not look forward to anything else. The GraphQL layer can be viewed as a facade which sits on top of your RESTful services o