Add Markers and Info window on Google Maps

In this article, I have documented the process of adding Google Maps (API v3) on to an Html page, the use, and application of the Markers and Info-window. In this example, I have created a form that takes Latitude, Longitude, Tooltip for Marker and plain text for Info-window as inputs. And plot the Marker on the map with the Info-window and is also populating a table with the same information but with an additional button that is used to remove the Markers from the map.

To do this we have to do the following.

  1. Adding Map to Page
  2. Create a function to add a Marker on Map
  3. Create a function to add an Info-window to the Marker
  4. Create a function to remove the Marker on Map with the Info-window
  5. Create a function that populates the Grid

1> Adding Map to Page

To display a google map on the page we first need to embed a script to the page in the body tag. The URL contained in the script tag is the location of a JavaScript file that loads all of the symbols and definitions you need for using the Maps JavaScript API.

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
Note-: The key parameter contains your application's API key. The API key is a unique identifier that is used to authenticate requests associated with your project for usage and billing purposes. Please check the doc "Get an API Key" for creating the API key.

After adding the script we need to reserve an area on the page where the map will be displayed.

<div class="col-md-6" id="map" style="height:350px;">
     Loading Map...
</div>

Now, we need to create a Map Options object what will be used to determine the appearances of the map. The Map Options have many properties, of which center, zoom & mapTypeId are required and the rest are optional. Below given are lists of some options which, we will be using for this example.

    var options = {
                zoom: 10,// used to set the scale of map
                mapTypeId: google.maps.MapTypeId.ROADMAP, // set the type of map like ROADMAP,SATELLITE,TERRAIN
                disableDefaultUI: true,//Disable Default View Of the Map
                mapTypeControl: true,//Disable mapType Button
                mapTypeControlOptions: {
                    style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
                    position: google.maps.ControlPosition.TOP_LEFT,//set position of the dropdown menu
                    mapTypeIds: [google.maps.MapTypeId.ROADMAP,
                    google.maps.MapTypeId.SATELLITE,
                    google.maps.MapTypeId.HYBRID,
                    google.maps.MapTypeId.TERRAIN]
                },
                navigationControl: true,//Disable mapType Button
                navigationControlOptions: {
                    position: google.maps.ControlPosition.TOP_LEFT,
                    style: google.maps.NavigationControlStyle.ZOOM_PAN
                },
                scaleControl: true,//Disable Scale Control
                keyboardShortcuts: true,//Disable keyboard Shortcuts
                disableDoubleClickZoom: false,//Disable Double Click Zoom
                draggable: true,//Disable draggable
                scrollwheel: true,//Disable draggable
                streetViewControl: true,//Disable StreetView
                noClear: false,//Use to clear contents in div before loading(Default Value False)
                //backgroundColor: '#00ff00',//Use to set Backgorund for div
                draggableCursor: 'move',// Change Cursor style,can add Images Also(while hover)
                draggingCursor: 'move',// Change Cursor style,can add Images Also(while dragging)
            };

Now that the Map Options are ready all we need to do is to create an object of 'google.maps.Map' which takes the following parameters as inputs

  • HTML element -: The object of the Html element(i.e the div with id 'map')
  • options -: The object of the Map Options as shown above.
var gMap = null;
var onLoad = function () {
        mapDiv = $("#map").get(0);
        defaultLatLng = new google.maps.LatLng(19.119219, 72.882743);
        options["center"] = defaultLatLng;
        if (gMap == null) {
            gMap = new google.maps.Map(mapDiv, options);
        }
}

 

2> Create a function to add a Marker on Map

To add a Marker on the map we need to use the object of 'google.maps.Marker' which takes the following parameters as inputs.

  • position -: this parameter takes an object of 'google.maps.LatLng' to mark the position of the marker on the map which takes in latitude and longitude as input parameters. This is a required property.
  • map -: this parameter takes the object of the map itself. This is a required property.
  • title -: this parameter is used to set the value of the tooltip for the Marker.
  • draggable -: this is a property of the marker that makes it draggable. By default the Marker is not draggable, to give the user the option to reposition the marker on the map the draggable property of the marker should be set to true. For this example will be setting the draggable property to false.

We have created a function AddMarker that takes all of the above-mentioned properties as parameters for creating the object of the Marker and return the same. It also adds the object to a list 'ListMarker' such that it contains all the objects of the Markers created.

var ListMarker = [];
var AddMarker = function (lat, lng, text, draggable) {
    var marker = new google.maps.Marker({
             position: new google.maps.LatLng(lat, lng),
             map: gMap,
             title: text,
             draggable: draggable
    });
    ListMarker.push(marker);
    return marker;
}

 

3> Create a function to remove the Marker on Map with the Info-window

An info window is used to display content over a popup window on the maps. Here we are going to add the info-window to the marker and add a click event in which the info-window will be displayed. By default, the Info-window is not visible on the map, we have to invoke a function named open(map, marker) which takes in the object of the map and the marker on which the info-window needs to be displayed.

We have to create a function 'AddInfo' that will create an object of the info-window with the Html contents that will be displayed on the popup. The function also creates a click event on the marker which in turn calls the 'open' function of the info-window. The object of the info-window is also added to the array 'ListInfoWindow'.

var ListInfoWindow=[];
var AddInfo = function (marker, text) {
     var content = '<div class="infowindow"><p>' + text + ' </p></div>';
     var infowindow = new google.maps.InfoWindow({
         content: content,
     });
     ListInfoWindow.push(infowindow);
     google.maps.event.addListener(marker, 'click', function () {
         infowindow.open(map, marker);
     });
     return infowindow;
}

 

4> Create a function to remove the Marker on Map with the Info-window

As the title of this section suggests, we have to create a function that removes the Marker from the map. The 'RemoveMarker(idx)' function takes an index as input which is used to identify the row in the list that has to be deleted. On finding the 'rowIdx' of the record that has to be deleted we need to remove data from all the arrays that are storing relevant data associated with it(i.e the ListInfoWindow, ListMarker, ListOfTextForGrid) using the same index. Once the rows are removed the grid needs to be reloaded.

var RemoveMarker = function (idx) {
    var rowIdx = 0;
    for (var i = 0; i < LitOfTextForGrid.length; i++) {
         if (LitOfTextForGrid[i].index == idx) {
             rowIdx = i;
             break;
         }
    }
    ListOfTextForGrid.splice(rowIdx, 1);
    ListInfoWindow.splice(rowIdx, 1);
    ListMarker[rowIdx].setMap(null);
    ListMarker.splice(rowIdx, 1);
    LoadGrid();
}

 

5> Create a function that populates the Grid

Here we are using 'jquery-tmpl' to render the data to the table. 

var LoadGrid = function () {
     $('#tblBody').html('');
     $.tmpl($('#tblRow').html(), ListOfTextForGrid).appendTo("#tblBody");
}

<script type="text/x-jquery-tmpl" id="tblRow">
        <tr>
            <td>${index}</td>
            <td>${lat}</td>
            <td>${lng}</td>
            <td>${infoText}</td>
            <td><a href="#" class="btn btn-danger btn-sm" onclick="MarkersWithInfoWindow.removeMarker(${index})" onmouseover="MarkersWithInfoWindow.onMoveHover(${index})">Remove</a></td>
        </tr>
</script>

 

In addition, we have to make a function that helps us identify the marker that we wish to delete on the map. To do this we can add a simple animation to the Marker on the hover of the button in the grid.

var OnMoveHover = function (idx) {
    var rowIdx = 0;
    for (var i = 0; i < ListOfTextForGrid.length; i++) {
         if (ListOfTextForGrid[i].index == idx) {
             rowIdx = i;
             break;
         }
    }
    // There are to type of animation
    // 1. BOUNCE
    // 2. DROP
    ListMarker[rowIdx].setAnimation(google.maps.Animation.BOUNCE);
    // setTimeout is used to remove the animation after 1 second
    setTimeout(function () {
        if (ListMarker.length > rowIdx) {
            ListMarker[rowIdx].setAnimation(null);
        }
    }, 1000);
}

Now that all the functions are built all we need to do is consume them all. So in the below-given click event, we have to read all the inputs from the form i.e Latitude, Longitude, text for the tooltip, plain text for Info-Window(Html tags can also be used in info-window) to create a Marker with Info-window.

$('#btnInfoWinText').click(function (e) {
     e.preventDefault();
     var lat = $('#txtLatMarkerIW').val();
     var lng = $('#txtLngMarkerIW').val();
     var toolTip = $('#txtIWMarkerToolTip').val();
     var infoText = $('#txtIWText').val();
     //Create object of Marker
     var marker = AddMarker(lat, lng, toolTip, false);
     //Create object of Info-Window
     var infoWin = AddInfo(marker, infoText);
     // idx for keeping a count of Markers added
     idx++;
     ListOfTextForGrid.push({ index: idx, lat: lat, lng: lng, toolTip: toolTip, infoText: infoText });
     LoadGrid();
});

 

Complete Code

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>How to add Markers with Info-window on Google Maps </title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Add Markers with Info-window on Google Maps</a>
            </div>
        </div>
    </nav>
    <div class="container theme-showcase" style="padding-top:70px;">
        <div class="row">
            <div class="col-md-6">
                <form class="form-horizontal" action="/action_page.php">
                    <div class="form-group">
                        <label for="txtLatMarkerIW" class="control-label col-sm-3">Latitude:</label>
                        <div class="col-sm-9">
                            <input type="text" class="form-control" name="" id="txtLatMarkerIW" placeholder="Latitude" value="19.119219" />
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="txtLngMarkerIW" class="control-label col-sm-3">Longitude:</label>
                        <div class="col-sm-9">
                            <input type="text" class="form-control" name="" id="txtLngMarkerIW" placeholder="Lnggitude" value="72.882743" />
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="txtIWMarkerToolTip" class="control-label col-sm-3">Marker Tool Tip:</label>
                        <div class="col-sm-9">
                            <input type="text" class="form-control" name="" id="txtIWMarkerToolTip" placeholder="Marker Tool Tip" value="Tooltip" />
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="txtIWText" class="control-label col-sm-3">Info-Window Text:</label>
                        <div class="col-sm-9">
                            <input type="text" class="form-control" name="" id="txtIWText" placeholder="Info Window Text" value="Hello Ajith" />
                        </div>
                    </div>

                    <button type="submit" class="btn btn-primary pull-right" id="btnInfoWinText">Add Marker With InfoWindow</button>
                </form>
            </div>
            <div class="col-md-6" id="map" style="height:350px;">
                Loading Map...
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                <table class="table">
                    <thead>
                        <tr>
                            <th>RowNo</th>
                            <th>Latitude</th>
                            <th>Longitude</th>
                            <th>Info-window text</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody id="tblBody">
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js"></script>
    <script>
        var MarkersWithInfoWindow = function () {
            var gMap = null, mapDiv = null, defaultLatLng = null;
            var ListMarker = [], ListInfoWindow = [];
            var ListOfTextForGrid = [];
            var idx = 0;

            var options = {
                zoom: 10,// used to set the scale of map
                mapTypeId: google.maps.MapTypeId.ROADMAP, // set the type of map like ROADMAP,SATELLITE,TERRAIN
                disableDefaultUI: true,//Disable Default View Of the Map
                mapTypeControl: true,//Disable mapType Button
                mapTypeControlOptions: {
                    style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
                    position: google.maps.ControlPosition.TOP_LEFT,//set position of the dropdown menu
                    mapTypeIds: [google.maps.MapTypeId.ROADMAP,
                    google.maps.MapTypeId.SATELLITE,
                    google.maps.MapTypeId.HYBRID,
                    google.maps.MapTypeId.TERRAIN]
                },
                navigationControl: true,//Disable mapType Button
                navigationControlOptions: {
                    position: google.maps.ControlPosition.TOP_LEFT,
                    style: google.maps.NavigationControlStyle.ZOOM_PAN
                },
                scaleControl: true,//Disable Scale Control
                keyboardShortcuts: true,//Disable keyboard Shortcuts
                disableDoubleClickZoom: false,//Disable Double Click Zoom
                draggable: true,//Disable draggable
                scrollwheel: true,//Disable draggable
                streetViewControl: true,//Disable StreetView
                noClear: false,//Use to clear contents in div before loading(Default Value False)
                //backgroundColor: '#00ff00',//Use to set Backgorund for div
                draggableCursor: 'move',// Change Cursor style,can add Images Also(while hover)
                draggingCursor: 'move',// Change Cursor style,can add Images Also(while dragging)
            };

            var onLoad = function () {
                mapDiv = $("#map").get(0);
                defaultLatLng = new google.maps.LatLng(19.119219, 72.882743);
                options["center"] = defaultLatLng;
                if (gMap == null) {
                    gMap = new google.maps.Map(mapDiv, options);
                }
            }

            var registerEvents = function () {
                $('#btnInfoWinText').click(function (e) {
                    e.preventDefault();
                    var lat = $('#txtLatMarkerIW').val();
                    var lng = $('#txtLngMarkerIW').val();
                    var toolTip = $('#txtIWMarkerToolTip').val();
                    var infoText = $('#txtIWText').val();
                    var marker = AddMarker(lat, lng, toolTip, false);
                    var infoWin = AddInfo(marker, infoText);
                    idx++;
                    ListOfTextForGrid.push({ index: idx, lat: lat, lng: lng, toolTip: toolTip, infoText: infoText });
                    LoadGrid();
                });
            }

            var AddMarker = function (lat, lng, text, draggable) {
                var marker = new google.maps.Marker({
                    position: new google.maps.LatLng(lat, lng),
                    map: gMap,
                    title: text,
                    draggable: draggable
                });
                ListMarker.push(marker);
                return marker;
            }

            var AddInfo = function (marker, text) {
                var content = '<div class="infowindow"><p> (' + idx + ')' + text + ' </p></div>';

                var infowindow = new google.maps.InfoWindow({
                    content: content,
                });
                ListInfoWindow.push(infowindow);
                google.maps.event.addListener(marker, 'click', function () {
                    infowindow.open(map, marker);
                });
                return infowindow;
            }

            var LoadGrid = function () {
                $('#tblBody').html('');
                $.tmpl($('#tblRow').html(), ListOfTextForGrid).appendTo("#tblBody");
            }

            var OnMoveHover = function (idx) {
                var rowIdx = 0;
                for (var i = 0; i < ListOfTextForGrid.length; i++) {
                    if (ListOfTextForGrid[i].index == idx) {
                        rowIdx = i;
                        break;
                    }
                }

                ListMarker[rowIdx].setAnimation(google.maps.Animation.BOUNCE);
                setTimeout(function () {
                    if (ListMarker.length > rowIdx) {
                        ListMarker[rowIdx].setAnimation(null);
                    }
                }, 1000);
            }

            var RemoveMarker = function (idx) {
                var rowIdx = 0;
                for (var i = 0; i < ListOfTextForGrid.length; i++) {
                    if (ListOfTextForGrid[i].index == idx) {
                        rowIdx = i;
                        break;
                    }
                }
                ListOfTextForGrid.splice(rowIdx, 1);
                ListInfoWindow.splice(rowIdx, 1);
                ListMarker[rowIdx].setMap(null);
                ListMarker.splice(rowIdx, 1);
                LoadGrid();
            }

            return {
                init: function () {
                    onLoad();
                    registerEvents();
                },
                onMoveHover: OnMoveHover,
                removeMarker: RemoveMarker
            }
        }();

        $(document).ready(function () {
            MarkersWithInfoWindow.init();
        });
    </script>
    <script type="text/x-jquery-tmpl" id="tblRow">
        <tr>
            <td>${index}</td>
            <td>${lat}</td>
            <td>${lng}</td>
            <td>${infoText}</td>
            <td><a href="#" class="btn btn-danger btn-sm" onclick="MarkersWithInfoWindow.removeMarker(${index})" onmouseover="MarkersWithInfoWindow.onMoveHover(${index})">Remove</a></td>
        </tr>
    </script>
</body>

</html>

 

Referred from book
This book is about the next generation of the Google Maps API. It will provide the reader with the skills and knowledge necessary to incorporate Google Maps version 3 on web pages in both desktop and mobile browsers. It also describes how to deal with common problems that most map developers encounter at some point, like performance and usability issues with having too many markers and possible solutions to that.