Hover information on the map

Aug 2, 2012 at 8:19 PM

Axel,

  Thanks for a wonderful solution.  I was trying to see if/how to add more information to the hover element on the map.  Currently all I see is the "title" or for me customer name.  Is it possible to add more to this?

Coordinator
Oct 23, 2012 at 7:40 PM

Hi BPhall74! Yes of course it would be possible to add more functionality to the script. 

Oct 30, 2012 at 9:07 PM

Excellent, How do I go about this?  I'm a beginner and learning what I can as I go.

Coordinator
Oct 31, 2012 at 2:37 PM

Hi BPhall74! 

Your question is, how to customize the content of the bubble-window on the map while hovering one result.

Please have a look at the JavaScript (latest source is here). There is a function "SetMarkerForGoogleMapForSharePointList". In the signature of this function you can see an input-param "contentForInfoWindow". That is a html-snippet which will be shown in the bubble-window. So your goal should be to customize this input-param. 

To do so, you have to find the callers of the JavaScript-Function "SetMarkerForGoogleMapForSharePointList". The function will be called twice in the source-code from the JavaScript function "ShowGoogleMapForSharePointList"

In the current version of the script a) only the title or b) the title and the coordinates (lat, long) will be displayed. The values for the title and the coordinates are read from a xml-response. Example for reading the value of the title-column from the Xml-Response: "$(this).attr(colLinkTitleInternalName);" 

The xml-response contains all data of the SharePoint-List. To see the schema of the SharePoint-List as Xml-Response you should set the JavaScript-Variable "showWarningAndErrorAlerts" to 1. Then some custom-alert-messages will be shown. Click on the "ajax-request" hyperlink to see the pure Xml-Response. (For further information have a look at the documentation, page 19)

Hope this helps. 

Axel

Nov 20, 2012 at 9:31 PM

Hey Axel,

Once again, thanks for the help.  I'm getting closer to figuring this little bugger out.  Everytime I think I've got it, I crash and burn and have to reset it back.  I think I don't have my var's declared right for the columns.  Title comes out fine, but I have one called Well Name that won't show and the Lat & Long won't either.  Here's your code that I'm slowly modifying to suit my site.  I read and tried to understand your previous reply and got confused.

 



<script type="text/javascript">

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++

   Script-Name: Basic-SharePoint-Google-Maps-WebPart-For-SharePoint-Lists  

   Author:      Axel Schneider
   Last-Update: 01.08.2011
   Version:     1.3
   www:         http://spgooglemapswpforspl.codeplex.com
                http://axelschneider.info

   History:     01.08.2011 (v1.3) - Added link to information-window for marker that has the same functionality like the List-Item-Link - even with context-menu.
                31.07.2011 (v1.22)- Changed some debug-hints from German to English.
                13.07.2011 (v1.21)- Fixed bug for "hideMapUntilClick=false".
                29.06.2011 (v1.2) - Changed pre-check; Added map-toggle; Made data available even if list-view does not show certain fields
                26.06.2011 (v1.1) - Added functionality for SharePoint 2010 and added some descriptions.
          21.06.2011 (v1.0) - Inital version after some nights of development (only for SharePoint 2007).
  
   +++++++++++++++++++++++++++++++++++++++++++++++++++++ */

/* *****************************************************
   AND NOW SOME VARIABLES YOU MAY WANT TO CHANGE.
   ***************************************************** */
var mapWidth = "900px";     //the width of the map
var mapHeight = "600px";    //the height of the map

//if true the coordinates (latitude, longitude) will be used
//if false the addresses (street, zip, city, country) will be used
var useCoordinates = true;

//if true the map will not be shown by default
//if false the map will be shown by default
var hideMapUntilClick = false;

//if 0 absolutely no warning- and error-alerts will be written to a log-div
//if 1 the warning- and error-alerts will be written to a log-div
//if 2 the warning- and error-alerts will be alerted via javascript-alert
var showWarningAndErrorAlerts = 1;

//the internal-names of list-columns (not the display-name!)
var colLinkTitleInternalName = "ows_LinkTitle";     //will be used as the title of the geo-markers
var colLongitudeInternalName = "ows_Long";     //useCoordinates == true
var colLatitudeInternalName = "ows_Lat";       //useCoordinates == true
var colStreetInternalName = "ows_Wellname";        //useCoordinates == false
var colStreetDisplayName = "ows_County";             //useCoordinates == false
var colZipInternalName = "ows_Basin";                 //useCoordinates == false

var defaultCountryValue = "Germany";                //the default country which will be used if no country-name will be found in the list-column

//default position (Germany: 51.165691,10.451526) > used if no markers will be set to the map
var defaultLatitude = 51.165691;
var defaultLongitude = 10.451526;

//some language-specific messages
var resxGoogleMapsLink = "Google-Map";  //the name of new menu-point in the menu-toolbar of the sharepoint-list
var resxGoogleMapsLinkTitle = "Menu: Show or hide Google-Map";  //the title which will be visible while hovering
var resxAlertsMessageText = resxGoogleMapsLink+": There are # hints!";   //the hint which will be visible if configuration warnings or errors occured.
var resxAlertsMessageTextTitle = "Click here to show or hide the hints!";    //the title which will be visible while hovering

/* *******************************************************************
   NOW DO NOT CHANGE ANYTHING IF YOU ARE NOT FAMILIAR WITH JAVASCRIPT!
   ******************************************************************* */
var isSharePoint2010 = false;
var hasMapBeenLoadedInitially = false;

var idOfMapDiv = "divGoogleMapForSharePointList";
var idOfCustomLogDiv = "divCustomLog";
var idOfCustomLogOverview = "divCustomLogOverview";

var noOfCustomLogEntries = 0;
var noOfMaxGeocodingRequest = 10;

//the attribute-name of the column "id" > will be used for a) finding the id of a certain row and b) for building the ajax-request-url
var colID = "ID";

//now some templates for jquery-selects
var jQuerySelect_2007_GetListRowByAttributeCTXName = "table[CTXName]";
var jQuerySelect_2010_GetListRowByAttributeCTXName = "div[CTXName]";

function InitializeGoogleMapForSharePointList()
{
  BuildGoogleMapCustomLogForSharePointList();

  if(!DoPreCheckForInitializationOfGooglemapsForSharePointList())
  {
    //pre-check not successfully done > abort now!   
    customAlert("The Pre-Check has not been successfully! > Abort now.");   
    return;
  }

  DoSchemaCheckAndBuildGoogleMapIconForSharePointList(); 
}

function DoSchemaCheckAndBuildGoogleMapIconForSharePointList()
{
  //get the schema-data for the list
  $.get(BuildAjaxRequestUrlForSharePointListSchemaOnly(), {}, function (xml)
  {   
    //find all necessary internal-field-names
    var arrNeccessaryFields = new Array();
    arrNeccessaryFields.push(colLinkTitleInternalName);
    if(useCoordinates)
    {
      arrNeccessaryFields.push(colLatitudeInternalName);
      arrNeccessaryFields.push(colLongitudeInternalName);
    }
    else
    {
      arrNeccessaryFields.push(colStreetInternalName);
      arrNeccessaryFields.push(colZipInternalName);
      arrNeccessaryFields.push(colCityInternalName);
      arrNeccessaryFields.push(colCountryInternalName);
    }
 
    //check all neccessary internal-field-names
    var foundAllNeccessaryFields = true;
    for(i=0;i<arrNeccessaryFields.length;i++)
    {
      //getting <xml>
      var xmlQuery = 'xml > *:first > *:first > *[name='+arrNeccessaryFields[i]+']';
      if($(xmlQuery, xml).length<1)
      {
        foundAllNeccessaryFields = false;
        customAlert("Schema-Check failed for internal-field-name '"+arrNeccessaryFields[i]+"'. The field is not available in this list.");
      }     
    }

    //check if the neccessary fields have been found
    if(foundAllNeccessaryFields)
    {
      BuildGoogleMapIconForSharePointList();
    }   
    else
    {
      var ajaxRequestLinkTag = 'ajax-request for list-schema';
      customAlert("Hint: You can get the internal names of the columns by calling the "+ajaxRequestLinkTag+" for the current sharepoint-list manually.");
      customAlert("Schema-Check failed. Abort now!");
    }
  });
}

function DoPreCheckForInitializationOfGooglemapsForSharePointList()
{
  //check if this is SharePoint2010 or not
  //if it is not 2010 it is assumed that it is 2007
  if(typeof(_fV4UI)!='undefined')
  {
    //the checked javascript-variable exists only in 2010
    isSharePoint2010 = true;   
  }
  else
  {
    isSharePoint2010 = false;   
  }

  //for the first shot: support only one table
  //for further version we could support more tables (table[class=ms-listviewtable].length>1)
  var noOfListViews = $("table[class=ms-listviewtable]").length;
  if(noOfListViews==0)
  {   
    //no list-view exists > there is no need to show google-maps
    customAlert("There is no list-view available on this site. > No need to show google-maps. > Abort now.");
    return false;
  }
  else if(noOfListViews>1)
  {   
    //there are more than one list-view > this is not supported at the moment
    customAlert("There are more than one list-views on the site. This is not supported at the moment. > Abort now!");
    return false;
  }

  //check if multi-lookup exists
  if($("table[FieldType=LookupMulti]").length>0)
  {   
    //If there are columns in the list-view which are of type multi-lookup the ajax-call (via owssrv.dll) will return zero results.
    var multiMsg = "Multi-lookup exists! Please remove the mulit-lookup-column or use another view (otherwise the ajax-request will receive an empty result). > Abort now!";

    multiMsg += "\n\nColumns which are of type multi-lookup are (the display-name will be shown):";

    $("table[FieldType=LookupMulti]").each(function(){
      var displayName = $(this).attr("displayName");
      multiMsg += "\n- "+displayName;
    });   

    customAlert(multiMsg);
    return false;
  }

  //check if javascript-variable exists > we need ctx to get the id of the sharepoint-list
  if(ctx==null)
  {
    //this javascript-variable is essential for getting the list-id and the list-view-id.
    customAlert("The javascript-variable 'ctx' does not exist within the html-dom. > Abort now!");
    return false;
  }

  //all checks passed - return true
  return true;
}

function BuildGoogleMapCustomLogForSharePointList()
{
  if(showWarningAndErrorAlerts!=1)
  {
    return;
  }

  var divCustomLogOverview = '

';
  $("table.ms-menutoolbar").parent().append(divCustomLogOverview);

  var divCustomLog = '

';
  $("table.ms-menutoolbar").parent().append(divCustomLog);
}

function ToggleCustomLog()
{
  //show or hide
  $("#"+idOfCustomLogDiv).toggle();
}

function ToggleGoogleMapDiv()
{
  //check if the map will be called for the first time 
  if(!hasMapBeenLoadedInitially)
  {
    ShowGoogleMapForSharePointList();
  }

  //show or hide
  $("#"+idOfMapDiv).toggle();
}

function BuildGoogleMapIconForSharePointList()
{
  //searching for the correct position in the menu-toolbar (ms-menutoolbar)
  $("td.ms-toolbar").each(function(j){
    if($(this).attr("width")=="99%")
    {
      //insert a new menu-item before the found placeholder
      //var newMenuItem = '</internal-name-of-column>';
      var newMenuItem = '';
      newMenuItem += '';
      newMenuItem += '';
      newMenuItem += '';
      newMenuItem += '';
      newMenuItem += '

';
      newMenuItem += ''+resxGoogleMapsLink+'';
      newMenuItem += '
';
      newMenuItem += '';
      newMenuItem += '';
      $(this).before(newMenuItem);
    }
  });

  //adding map-canvas as div-tag to the dom
  var divMapCanvas = '

';
  $("table.ms-menutoolbar").parent().append(divMapCanvas);

  //check if the map should be shown as soon as possible or if it should be hidden until the user clicked the new menu-point
  if(!hideMapUntilClick)
  {   
    ToggleGoogleMapDiv();
  }
}

//gets the complete list-schema and one row with all its values (not filtered by the current used view)
function BuildAjaxRequestUrlForSharePointListByID_Template()
{
  if(ctx!=null)
  {
    //build the url of the ajax-request
    return ctx.HttpRoot+'/_vti_bin/owssvr.dll?XMLDATA=1&List=' + ctx.listName + '&Query=*&FilterField1='+colID+'&FilterValue1=';
  }
}

//gets the list-schema and no rows
function BuildAjaxRequestUrlForSharePointListSchemaOnly()
{
  //build the url of the ajax-request
  return BuildAjaxRequestUrlForSharePointListByID_Template()+'-1'; 
}

function ShowGoogleMapForSharePointList()
{
  //build the url of the ajax-request
  var urlTemplate = BuildAjaxRequestUrlForSharePointListByID_Template();

  //build map
  $('#'+idOfMapDiv).css({"width":mapWidth, "height":mapHeight});   
  var latlng = new google.maps.LatLng(defaultLatitude,defaultLongitude);
  var myOptions = {
      zoom: 6,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var gmMap = new google.maps.Map(document.getElementById(idOfMapDiv), myOptions);
  var gmBounds = new google.maps.LatLngBounds();
  var gmGeocoder = new google.maps.Geocoder();

  var jQuerySelect_GetListRowByAttributeCTXName;
  if(isSharePoint2010)
  {
    jQuerySelect_GetListRowByAttributeCTXName = jQuerySelect_2010_GetListRowByAttributeCTXName;
  }
  else
  {
    jQuerySelect_GetListRowByAttributeCTXName = jQuerySelect_2007_GetListRowByAttributeCTXName;
  }

  //check if the number of geocodings will exceed the max-number
  if(!useCoordinates && $(jQuerySelect_GetListRowByAttributeCTXName).length > noOfMaxGeocodingRequest)
  {
    var linkToStatusCodes = 'OVER_QUERY_LIMIT-Statusnull'">http://code.google.com/intl/de-DE/apis/maps/documentation/javascript/services.html#GeocodingStatusCodes">OVER_QUERY_LIMIT-Status';
    var tooManyMsg = "Hint: In the current view of the SharePoint-List there are more than "+noOfMaxGeocodingRequest+" list-entries. ";
    tooManyMsg += "This will result in an "+linkToStatusCodes+" by Google-Maps (and not all markers will be shown on the map). > You have 2 options: ";
    tooManyMsg += "a) Change your view to get no more than "+noOfMaxGeocodingRequest+" list-entries or ";
    tooManyMsg += "b) use the coordinates (longitude, latitude) of the addresses (they will be shown on the map).";
    customAlert(tooManyMsg); 
  }

  //get each row from list-view which is shown at the moment
  $(jQuerySelect_GetListRowByAttributeCTXName).each(function(j)
  {
    var lat, long, gmLatLng, gmMarker, title, customUrl, street, city, country;
    var idOfListItem = $(this).attr(colID);
    var linkToListItem = $(this).parent().html();
    linkToListItem = linkToListItem.replace(/100%/g, "auto");   //exchange tag-attributes for width and height
    //alert(linkToListItem)   

    //build url for the ajax-request which reads all data for a certain row (for the current list-view)
    customUrl = urlTemplate+idOfListItem;

    //get the data for the row
    $.get(customUrl, {}, function (xml)
    {   
      $('xml > *:last > *', xml).each(function (i)
      {
        //get some data from the xml-response
        title = $(this).attr(colLinkTitleInternalName);

        if(useCoordinates)
        {
          //getting coordinates
          lat = $(this).attr(colLatitudeInternalName);
          long = $(this).attr(colLongitudeInternalName);

          if(typeof(lat)!='undefined' && typeof(long)!='undefined')
          {
            gmLatLng = new google.maps.LatLng(lat, long);
            msgForInfoWindow = linkToListItem;            //you may add more information-text here
            SetMarkerForGoogleMapForSharePointList(gmLatLng, gmMap, gmBounds, title, msgForInfoWindow);
          }       
          else
          {
            customAlert(title +" has undefined lat+long. > Do not add marker on map.");
          }
        }
        else
        {
          //getting address
          street = $(this).attr(colStreetInternalName);
          zip = $(this).attr(colZipInternalName);
          city = $(this).attr(colCityInternalName);
          country = $(this).attr(colCountryInternalName);  
 
       //checking received values
          if(typeof(street)=='undefined') street = "";  //optional
          if(typeof(zip)=='undefined') zip = "";        //optional
          if(typeof(city)=='undefined')
          {
            customAlert("The ajax-response got no city for '"+title+"'. > Do not add marker on map.");
            return;
          }
          if(typeof(country)=='undefined') country = defaultCountryValue;

          address = street+","+zip+","+city+","+country;

          //getting coordinates
          gmGeocoder.geocode( { 'address': address}, function(results, status) {           
            if (status == google.maps.GeocoderStatus.OK)
            {
              if(results.length==0)
              {
                customAlert("Geocoding: There are no results for address '"+results[0].formatted_address+"'! Expected exactly one result. > Do not show any marker on map for this address.");
              }
              else if(results.length>1)
              {
                var msg = "Geocoding: There are too many ("+results.length+") results for given address! Expected exactly one result. > Do not show any marker on map for this address.\n\nFound addresses:\n";
                for(i=0;i<results.length;i++)
                {
                  var c = i+1;
                  msg += "\n"+c+": "+results[i].formatted_address;
                }
                customAlert(msg);
              }
              else
              {
                gmLatLng = results[0].geometry.location;
                var msgForInfoWindow = linkToListItem+"
";
                msgForInfoWindow += "Koordinaten (Lat, Long): "+gmLatLng+"
Adresse: "+results[0].formatted_address+"
";
                SetMarkerForGoogleMapForSharePointList(gmLatLng, gmMap, gmBounds, title, msgForInfoWindow);
              }
            }
            else
            {
              customAlert("Geocode for address '"+address+"' was not successful for the following reason: " + status);
            }
          });         
        }
               
      });    
    });   
  });

  hasMapBeenLoadedInitially = true;
}

function SetMarkerForGoogleMapForSharePointList(gmLatLng, gmMap, gmBounds, title, contentForInfoWindow)
{
  var gmMarker = new google.maps.Marker({
    position: gmLatLng,
    map: gmMap,
    title: title,
    zIndex: 0
  });
  gmBounds.extend(gmLatLng);
  gmMap.setCenter(gmBounds.getCenter());
  gmMap.fitBounds(gmBounds);

  if(contentForInfoWindow!=null && contentForInfoWindow!="")
  {
    var gmInfowindow = new google.maps.InfoWindow({
      content: contentForInfoWindow
    });
   
    google.maps.event.addListener(gmMarker, 'click', function() {
      gmInfowindow.open(gmMap,gmMarker);
    });
  }
}

function customAlert(msg)
{
  if(msg==null || msg=="")
  {
    return;
  }
  else
  {
    var now = new Date();
    msg = now.getHours()+":"+now.getMinutes()+":"+now.getSeconds()+": "+msg;
  }

  if(showWarningAndErrorAlerts==1)
  {
    //do nothing
  }
  else if(showWarningAndErrorAlerts==1)
  {
    //do log in log-div
    msg = msg.replace(/\n/g, "
");
    msg += "

";
    $("#"+idOfCustomLogDiv).append(msg);

    noOfCustomLogEntries++;
    $("#"+idOfCustomLogOverview).show();
    var overviewText = resxAlertsMessageText.replace(/#/g, noOfCustomLogEntries);
    $("#"+idOfCustomLogOverview).text(overviewText);   

  }
  else if(showWarningAndErrorAlerts==2)
  {
    //do alert via javascript-alert
    alert(msg);
  }
  else
  {
    //unsupported
  }
}

//call initialization after the dom has been loaded completely > so it does not matter where this piece of javascript will be inserted in the dom
$(document).ready(InitializeGoogleMapForSharePointList);

</script>