Thursday, January 27, 2011

Liferay (s)mashup - Google Maps


In the previous blog, we saw how to fire events asynchronously on the client side. In this blog, we will see the integration of Google Maps in a portlet.
Showing Google Maps in a portlet is a breeze. For this, create a portlet called 'Visual View'. This portlet displays the Google Map for visual interaction. It receives the source and destination from the Plan Your Travel portlet and shows the road route in the map.

Using Google Maps API

Google Maps API is a collection of web services providing geographic data for creating maps applications. These web services use HTTP requests to specific URLs, passing URL parameters as arguments to the services. Generally, these services return data in the HTTP request as either JSON or XML for parsing and/or processing by an application.  Let's get straight to the code.

Code Listing

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<portlet:defineObjects />
<style type="text/css">
#map_canvas {
    height: 500px;
    width: 400px
}
</style>

<script type="text/javascript">
    var <portlet:namespace />map;
    var <portlet:namespace />geocoder;
    var <portlet:namespace />directionDisplay;
    var <portlet:namespace />directionsService;
    var <portlet:namespace />rendererOptions = {
        draggable : true //make the map points draggable
    };
    var <portlet:namespace />initialLocation;
    var <portlet:namespace />infowindow;

    function <portlet:namespace />initialize() {
        var myLatlng = new google.maps.LatLng(-34.397, 150.644);
        var myOptions = {
            zoom : 8,
            center : myLatlng,
            mapTypeId : google.maps.MapTypeId.ROADMAP
        };

        <portlet:namespace />map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
        <portlet:namespace />geocoder = new google.maps.Geocoder();
        <portlet:namespace />directionsService = new google.maps.DirectionsService();
        <portlet:namespace />directionsDisplay = new google.maps.DirectionsRenderer(
                                                    <portlet:namespace />rendererOptions);
        <portlet:namespace />directionsDisplay.setMap(<portlet:namespace />map);
        <portlet:namespace />infowindow = new google.maps.InfoWindow();

        //geo location
        // Try W3C Geolocation method (Preferred)
        if (navigator.geolocation) {
            browserSupportFlag = true;
            navigator.geolocation.getCurrentPosition(function(position) {
                <portlet:namespace />initialLocation = new google.maps.LatLng(
                        position.coords.latitude, position.coords.longitude);
                contentString = "Location found using W3C standard";
                <portlet:namespace />map
                        .setCenter(<portlet:namespace />initialLocation);
                var marker = new google.maps.Marker({
                    map : <portlet:namespace />map,
                    position : <portlet:namespace />initialLocation
                });
            }, function() {
                <portlet:namespace />handleNoGeolocation(browserSupportFlag);
            });
        } else if (google.gears) {
            // Try Google Gears Geolocation
            browserSupportFlag = true;

            var geo = google.gears.factory.create('beta.geolocation');
            geo.getCurrentPosition(function(position) {
                <portlet:namespace />initialLocation = new google.maps.LatLng(
                        position.latitude, position.longitude);
                contentString = "Location found using Google Gears";
                <portlet:namespace />map.setCenter(<portlet:namespace />initialLocation);
                <portlet:namespace />infowindow.setContent(contentString);
                <portlet:namespace />infowindow.setPosition(<portlet:namespace />initialLocation);
                <portlet:namespace />infowindow.open(<portlet:namespace />map);
            }, function() {
                <portlet:namespace />handleNoGeolocation(browserSupportFlag);
            });
        } else {
            // Browser doesn't support Geolocation
            browserSupportFlag = false;
            <portlet:namespace />handleNoGeolocation(browserSupportFlag);
        }

        //add listener for directions change
        google.maps.event.addListener(
            <portlet:namespace />directionsDisplay,
            'directions_changed',
            function() {
                var leg = <portlet:namespace />directionsDisplay.directions.routes[0].legs[0];
                Liferay.fire('directionsChanged', {
                        origin : leg.start_address,
                        destination : leg.end_address
                });
            });
    }

    function <portlet:namespace />handleNoGeolocation(errorFlag) {
        if (errorFlag == true) {
            <portlet:namespace />initialLocation = newyork;
            contentString = "Error: The Geolocation service failed.";
        } else {
            <portlet:namespace />initialLocation = siberia;
            contentString = "Error: Your browser doesn't support geolocation. Are you in Siberia?";
        }
        <portlet:namespace />map.setCenter(<portlet:namespace />initialLocation);
        <portlet:namespace />infowindow.setContent(contentString);
        <portlet:namespace />infowindow.setPosition(<portlet:namespace />initialLocation);
        <portlet:namespace />infowindow.open(<portlet:namespace />map);
    }
 
    function <portlet:namespace />loadScript() {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=<portlet:namespace />initialize";
        document.body.appendChild(script);
    }

    window.onload = <portlet:namespace />loadScript;

    function <portlet:namespace />showDirection(source, destination) {
        var request = {
            origin : source,
            destination : destination,
            travelMode : google.maps.DirectionsTravelMode.DRIVING
        };
        <portlet:namespace />directionsService.route(request, function(
                response, status) {
            if (status == google.maps.DirectionsStatus.OK) {
                <portlet:namespace />directionsDisplay.setDirections(response);
            }
        });
    }

    Liferay.on('planTravel', function(event) {
        <portlet:namespace />showDirection(event.origin, event.destination);
    });
</script>

<div id="map_canvas"></div>

The Google Maps API requires a single div element with an id in the html page to be rendered. Here, we have given the id as 'map_canvas'. The loadScript() method dynamically loads the maps script file. This speeds up the page display. The initialize() method loads the map view with pre-configured values. Also, latest versions of most browsers support geolocation. Geolocation allows tracking user's current location. This information is used to load the map with user's current location.
Note the listener for the directions changed event from the map in the initialize function. When the directions changed event occurs, we republish the event using Liferay's event manager to notify other portlets. Other portlets receives this event to update their display. We saw this in the search form in the first part of this blog series.
To use the two portlets that we have developed so far, type in the names of cities in the origin and destination and hit the Search button. The road rout between the two cities will be shown in the Google map. Now, try changing the cities by dragging the marker in the map. The cities' names are updated in the Plan Your Travel portlet. We will see interesting applications of this event model in the next few portlets.
For more details working on the Google Maps API, see this and this.

7 comments:

  1. Dear Sheikh Mohammad Sajid,

    Can I have the source code for my study? like the above screenshot.

    Thank You very much.

    Gery
    gadis.glorious@gmail.com

    ReplyDelete
  2. Hi,i also like it much can you send me the source for personal use too?
    arapqueen(at)hotmail(dot)de


    Thanks

    ReplyDelete
  3. I'm a student from Viet Nam. Can you share me your example code for me? I can't get the map when portlet starting up.
    My email : lepteo14@gmail.com
    Thank you very much!

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Hello,
    This articula had resolved our more complex issue of project. this is awaysome artical thanks thanks lot!!!!!!!!!!!!!!!!!!!!!!!!!!

    Regards,
    Vaibhav Patil
    meet me on vaibhav.patil@accenture.com

    ReplyDelete
  6. Aslm sajid bhai,

    can I have the source code please : jaid.sk@gmail.com


    Thanks
    Jaid.Shaik

    ReplyDelete
  7. Thank you so much for the post .it wokrked

    ReplyDelete