Plotting locations on Google Maps

User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Re: Plotting locations on Google Maps

Post by anserkk »

TimStone wrote:The translation time for the geocode is quite long when creating a map. So I decided to get the codes and store them in the database for each address.
Obviously this will take time because google has to search its database based on the address provided by you and then return the most accurate result from a bunch of data. If your list is too long then it increases the time further. For this reason, I keep the Lat and Lng in the database. May be you can run this routine once in a while to update the Lat and Lng in your Customer address DBF/Table. For large list of address there are services from Google named Google App Scripts.

My initial example in this thread was to display a Google Map based on the available Lat and Lng. I created the sample to get the Lat and Lng based on the address when you said that your requirement was to display a Googe Map based on the Address details that you have in your database. It is just a sample to demonstrate that this is possible using FiveWin. Its my mistake that, I have not gone deep into catching the run time errors if there are no results from Google.
TimStone wrote:Thoughts on trapping hjson values that do not have an array would be appreciated.
You should add the lat long to the array only if hJson["status"] == "OK"
OR you can put a try catch

Anyway here is one of the methods to consider to gracefully control the run time error which may occur if the searched address is not found by Google.

Code: Select all

#Include "FiveWin.ch"

//-----------------------------
Function Main()
    Local aLatLng:={} 
    Local aAddress:={ {"Anser","K K"            , "just dummy so that it  ", "will not give"       ,"any results" },;
                      {"Eiffel Tower","Champ de Mars"            , "5 Avenue Anatole France", "75007 Paris"         ,"France" },;
                      {"Taj Mahal"   ,"Dharmapuri, Forest Colony", "Tajganj, Agra"          , "Uttar Pradesh 282001","India"   } }

    // This function will grab the Lat and Lng information from Google and returns an array
    aLatLng:=GetLatLng(aAddress)

    // Displays Markers on a Google Map
    ViewGoogleMap(aLatLng)
Return NIL

//------------------------------------------//
Function GetLatLng(aData)
  Local i,cName,cAddress,cCity,cState,cCountry,aLatLng:={},nLatitude,nLongitude
  Local oHttp, cURL, lNetError, cResponse,hJson
  
  For i:=1 to Len(aData)
  
    cName:=STRTRAN(ALLTRIM(aData[i][1])," ","+")
    cName:=STRTRAN(ALLTRIM(aData[i][1]),"&"," E ")
    cAddress:=STRTRAN(ALLTRIM(aData[i][2]),",","")
    cAddress:=STRTRAN(ALLTRIM(aData[i][2])," ","+")
    cCity:=STRTRAN(ALLTRIM(aData[i][3])," ","+")
    cCountry:=STRTRAN(ALLTRIM(aData[i][5])," ","+")  
    cState:=aData[i][4]
    
    oHttp:=CreateObject("Microsoft.XMLHTTP")
    cURL:="http://maps.google.com/maps/api/geocode/json?address="+cAddress+"+"+cCity+"+-+"+cState+"+"+cCountry+"&sensor=false"
    oHttp:Open("GET",cURL,.F.)
    lNetError:=.F.
    TRY
        oHttp:Send()
    CATCH oError
        lNetError:=.T.
    END TRY
    
    IF !lNetError
      cResponse := oHttp:ResponseBody
    ELSE
      // Search Error. Could not find the details on Google Maps.
      Loop
    ENDIF    

    hb_jsonDecode(cResponse,@hJson)
    IF hJson["status"] == "OK"
        nLatitude:= hJson["results"][1]["geometry"]["location"]["lat"]
        nLongitude:=hJson["results"][1]["geometry"]["location"]["lng"]    
        Aadd(aLatLng,{aData[i][1],nLatitude, nLongitude} )
    ENDIF
    
  Next
  
Return aLatLng

//-----------------------------------------------------------------------/
Function ViewGoogleMap(aData)
   Local cMapFile:="D:\GMaps.htm", cHtmlContent1,cHtmlContent2, oOle, i
   Local cAppendStr:="var locations = ["+CRLF
   
   If Len(aData) == 0
      MsgInfo("Location data not available in the list")
      Return
   Endif
   
   For i:=1 to Len(aData)
       cAppendStr+=Space(4)+"['" +aData[i][1] +"',"+Ltrim(Str(aData[i][2]))+","+ Ltrim(Str(aData[i][3]))+ If( i < Len(aData), "],", "]") +CRLF
   Next
   cAppendStr+="];"+CRLF

TEXT INTO cHtmlContent1
    
    <html>
    <head>
      
      <title>Google Maps Multiple Markers</title>
      <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
    </head>
    <body>
      <div id="map" style="height: 100%; width: 100%;">
    </div>
    <script type="text/javascript">
    
ENDTEXT
    
    
TEXT INTO cHtmlContent2    
        
        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 0,           
          mapTypeId: google.maps.MapTypeId.ROADMAP
        });
        var bounds = new google.maps.LatLngBounds();
        var infowindow = new google.maps.InfoWindow();
    
        var marker, i;
    
        for (i = 0; i < locations.length; i++) { 
         var position = new google.maps.LatLng(locations[i][1], locations[i][2]);
            bounds.extend(position);
          marker = new google.maps.Marker({
            position: new google.maps.LatLng(locations[i][1], locations[i][2]),        
            map: map
          });
    
          google.maps.event.addListener(marker, 'click', (function(marker, i) {
            return function() {
              infowindow.setContent(locations[i][0]);
              infowindow.open(map, marker);
            }
          })(marker, i));

          // Automatically center the map fitting all markers on the screen
          map.fitBounds(bounds);
         
        }
      </script>
    </body>
    </html>
    
ENDTEXT

     MEMOWRIT( cMapFile, cHtmlContent1+cAppendStr+cHtmlContent2 )

     Shellexecute( NIL, "open", cMapFile )     
   
Return
User avatar
nageswaragunupudi
Posts: 8017
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Contact:

Re: Plotting locations on Google Maps

Post by nageswaragunupudi »

May be you can run this routine once in a while to update the Lat and Lng in your Customer address DBF/Table.
It is a good idea to find latlong and save it in database when adding a contact or modifying the address of a contact.
Regards

G. N. Rao.
Hyderabad, India
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Re: Plotting locations on Google Maps

Post by anserkk »

nageswaragunupudi wrote:
May be you can run this routine once in a while to update the Lat and Lng in your Customer address DBF/Table.
It is a good idea to find latlong and save it in database when adding a contact or modifying the address of a contact.
.
Yes. you are right. That's the right way to do.
User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

Re: Plotting locations on Google Maps

Post by TimStone »

As I noted previously, I have been doing exactly what was suggested ... and that is to get the coordinates and save them to the database. I did find a way yesterday to trap no data found responses, but apparently there are other types of responses also so I will be working more on this today.

What I am trying to do is build a map that shows where clients come from over a period of time. Hidden deeply inside the Google documents, however, I found that you the API apparently only allows for 15 markers. That is strange because I see applications frequently that show far more than 15 points. I suppose I will have to work on that issue.

The reason for the maps is that they are often used in marketing programs to show areas that yield the best results from communications by businesses.

Thanks for the ideas ... they are being incorporated ... and my goal will to ultimately build a class that allows us greater use of Google Maps from within FWH.

Tim
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
cnavarro
Posts: 5792
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Plotting locations on Google Maps

Post by cnavarro »

The most important thing is that: I consider that the Anserkk example is the best way to do this work
But, I have another way of getting this data (latitude and longitude)
Then you can apply the function to draw the map

Code: Select all


#include "FiveWin.ch"

Static cUrl     := ""

Function Main()

   SET 3DLOOK OFF
   VerMapa2( "", "Calle Gran Via", "17", "Madrid", "Madrid", "Spain" )
   VerMapa2( "75007", "Avenue Anatole France", "5", "", "Paris", "France" )

   
Return nil

//----------------------------------------------------------------------------//

Function VerMapa2( cPostal_Code, cStreet, cNumber, cLocality, cState, cNation )
   
   Local cWeb  := "http://maps.google.es/maps/place/"
   local cMap
   local cRet  := ""
   local oOle
   local nPos1
   local nPos2
   local aCoor := { 0, 0, 0 }
   cPostal_Code := StrTran( AllTrim( cPostal_Code ), ' ', '+' )
   cStreet      := StrTran( AllTrim( cStreet ), ' ', '+' )
   cNumber      := StrTran( AllTrim( cNumber ), ' ', '+' )
   cLocality    := StrTran( AllTrim( cLocality ), ' ', '+' )
   cState       := StrTran( AllTrim( cState ), ' ', '+' )
   cNation      := StrTran( AllTrim( cNation ), ' ', '+' )
   cMap     :=  AllTrim( cPostal_Code ) + "+" + AllTrim( cStreet ) + "+" + ;
                AllTrim( cNumber ) + "+" + AllTrim( cLocality ) + "+" + ;
                AllTrim( cState ) + "+" + AllTrim( cNation )
   oOle  := CreateObject("Winhttp.WinHttpRequest.5.1")
   oOle:Open( "GET", cWeb + AllTrim( cMap ), .F. )
   oOle:Send()
   cURL := oOle:ResponseText

   nPos1  := At( "cacheResponse([[[", Left( cURL, 2048 ) )
   if !Empty( nPos1 )
      cRet   := Substr( Left( cURL, 1024 ), nPos1 + 17, 2048 - nPos1 )
      nPos2  := At( "]", cRet )
      if !Empty( nPos2 )
         cRet   := Left( cRet, nPos2 - 1 )
         aCoor  := hb_ATokens( cRet, "," )
      endif
   endif
   XBrowse( aCoor )

Return aCoor

//----------------------------------------------------------------------------//
 
C. Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
Si alguien te dice que algo no se puede hacer, recuerda que esta hablando de sus limitaciones, no de las tuyas.
User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

Re: Plotting locations on Google Maps

Post by TimStone »

A few observations:

1) I built a utility to do just the geocode, and save the result to the database. GOOGLE LIMITS ACTIVITY - a) You need a key ( free ), and b) you still have a limit of the number of searches you can do in a 24 hour period. Google says the key lets you do 25,000, but I find it only allows 2500. I have to run the routine over several days before I can get results for the whole database.

2) It is very common to add to an address. For example, 241 South St. Apt 6 Anytown, NY is submitted as 241+South+St.+Apt+6+Anytown,+NY and because of the apartment and number, this will not decode. Make sure you use only the street number and name.

3) I wanted to plot many locations on the map to show where customers live. I see this done a lot, but Google Maps has a limit of 15 points we can plot at one time. They do have an alternative for clustering locations which shows one pin in an area.

Mapping is very popular now, and Google seems to be the main resource people use.
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
cnavarro
Posts: 5792
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Plotting locations on Google Maps

Post by cnavarro »

My son, has recommended this lib

http://leafletjs.com/index.html

This is a sample
If you have the length and latitude, you do not need to run the function VerMapa2()

Code: Select all


#include "FiveWin.ch"

Static cUrl     := ""

Function Main()

   Local aDatas := {}
   SET 3DLOOK OFF

   AAdd( aDatas, VerMapa2( "28850", "Calle Manuel Sandoval", "1", "Torrejon de Ardoz", "Madrid", "Spain" ) )
   AAdd( aDatas, VerMapa2( "28850", "Calle Buenos Aires", "1", "Torrejon de Ardoz", "Madrid", "Spain" ) )
   AAdd( aDatas, VerMapa2( "28850", "Calle Ferrocarril", "10", "Torrejon de Ardoz", "Madrid", "Spain" ) )
   ViewLeafLet( aDatas )

Return nil

//----------------------------------------------------------------------------//

Function VerMapa2( cPostal_Code, cStreet, cNumber, cLocality, cState, cNation )
   
   Local cWeb  := "http://maps.google.es/maps/place/"
   local cMap
   local cRet  := ""
   local oOle
   local nPos1
   local nPos2
   local aCoor := { 0, 0, 0 }
   cPostal_Code := StrTran( AllTrim( cPostal_Code ), ' ', '+' )
   cStreet      := StrTran( AllTrim( cStreet ), ' ', '+' )
   cNumber      := StrTran( AllTrim( cNumber ), ' ', '+' )
   cLocality    := StrTran( AllTrim( cLocality ), ' ', '+' )
   cState       := StrTran( AllTrim( cState ), ' ', '+' )
   cNation      := StrTran( AllTrim( cNation ), ' ', '+' )
   cMap     :=  AllTrim( cPostal_Code ) + "+" + AllTrim( cStreet ) + "+" + ;
                AllTrim( cNumber ) + "+" + AllTrim( cLocality ) + "+" + ;
                AllTrim( cState ) + "+" + AllTrim( cNation )
   oOle  := CreateObject("Winhttp.WinHttpRequest.5.1")
   oOle:Open( "GET", cWeb + AllTrim( cMap ), .F. )
   oOle:Send()
   cURL := oOle:ResponseText

   nPos1  := At( "cacheResponse([[[", Left( cURL, 2048 ) )
   if !Empty( nPos1 )
      cRet   := Substr( Left( cURL, 1024 ), nPos1 + 17, 2048 - nPos1 )
      nPos2  := At( "]", cRet )
      if !Empty( nPos2 )
         cRet   := Left( cRet, nPos2 - 1 )
         aCoor  := hb_ATokens( cRet, "," )
      endif
   endif
   //XBrowse( aCoor )

Return aCoor

//----------------------------------------------------------------------------//

Function ViewLeafLet(aData)
   
   local cMapFile   := "D:\fwh\fwhteam\samples\GMaps.htm"
   local cHtmlContent1
   local cHtmlContent2
   local cHtmlContent3
   local cInitMap   := "   var mymap = L.map('mapid').setView( [ "
   local cAppendStr := "   L.polygon([" + CRLF
   local oOle
   local i

   TEXT INTO cHtmlContent1
   
   <!DOCTYPE html>
   <html>
   <head>
       <title>Quick Start - Leaflet</title>

       <meta charset="utf-8" />
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
       <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />

       <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
       <script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
   </head>
   <body>
      <div id="mapid" style="width: 700px; height: 560px;"></div>
      <script>
   ENDTEXT

   cInitMap  += aData[ 1 ][ 3 ] + ", " + aData[ 1 ][ 2 ] + " ], 13);" + CRLF

   TEXT INTO cHtmlContent2
    L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
        maxZoom: 18,
        attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
            '<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
            'Imagery © <a href="http://mapbox.com">Mapbox</a>',
        id: 'mapbox.streets'
    }).addTo(mymap);

   ENDTEXT

   For i := 1 to Len( aData )
      cAppendStr += Space( 4 ) + "[ " + aData[ i ][ 3 ] + ", " + ;
                    Ltrim( aData[ i ][ 2 ] )
      if i < Len( aData )
         cAppendStr += "]," + CRLF
      else
         cAppendStr += "]" + CRLF      
      endif
   Next
   cAppendStr += "]).addTo(mymap).bindPopup('I am a polygon.');" + CRLF + CRLF

   For i := 1 to Len( aData )
      cAppendStr += "L.marker( "
      cAppendStr += "[ " + aData[ i ][ 3 ] + ", " + ;
                    Ltrim( aData[ i ][ 2 ] ) + " ] )."
      cAppendStr += "addTo(mymap).bindPopup('<b>Marker" + Str( i ) + " !</b><br />I am a popup.').openPopup();" + CRLF + CRLF
   Next
   
   TEXT INTO cHtmlContent3
    var popup = L.popup();

    function onMapClick(e) {
        popup
            .setLatLng(e.latlng)
            .setContent("Position is: " + e.latlng.toString())
            .openOn(mymap);
    }

   mymap.on('click', onMapClick);

   </script>

   </body>
   </html>

   ENDTEXT

   MEMOWRIT( cMapFile, cHtmlContent1 + cInitMap + cHtmlContent2 + cAppendStr + cHtmlContent3 )

   oOle := CreateObject( "InternetExplorer.Application" )
   oOle:Width     := 750
   oOle:Height    := 650
   oOle:Visible   := .T.     // Displays the Browser
   oOle:ToolBar   := .F.     // Disables the toolbar
   oOle:StatusBar := .F.     // Disables status bar
   oOle:MenuBar   := .F.     // Disables the menu bar
   oOle:Navigate( cMapFile ) // Open the Webpage
   SysRefresh()
   
Return nil

//----------------------------------------------------------------------------//

 
Last edited by cnavarro on Wed Mar 15, 2017 10:20 pm, edited 1 time in total.
C. Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
Si alguien te dice que algo no se puede hacer, recuerda que esta hablando de sus limitaciones, no de las tuyas.
User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

Re: Plotting locations on Google Maps

Post by TimStone »

Thank you. I will explore that resource.
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
vilian
Posts: 795
Joined: Wed Nov 09, 2005 2:17 am
Location: Brazil
Contact:

Re: Plotting locations on Google Maps

Post by vilian »

Guys,

Do you know if is possible show a text beside the mark for all locations plotted? Something Like tooltips.

I know if I click in the mark, the text is shown, but i would like to show the text without be necessary to click in the mark. Is it possible?
Sds,
Vilian F. Arraes
vilian@vfatec.com.br
Belém-Pa-Brazil
User avatar
cnavarro
Posts: 5792
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Plotting locations on Google Maps

Post by cnavarro »

Look, Is that something you need?

http://leafletjs.com/examples/choropleth/
C. Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
Si alguien te dice que algo no se puede hacer, recuerda que esta hablando de sus limitaciones, no de las tuyas.
User avatar
vilian
Posts: 795
Joined: Wed Nov 09, 2005 2:17 am
Location: Brazil
Contact:

Re: Plotting locations on Google Maps

Post by vilian »

Cnavarro,

No, is something like this:
Image

But for to be shown for all points, without be necessary to do a click over them.
Sds,
Vilian F. Arraes
vilian@vfatec.com.br
Belém-Pa-Brazil
User avatar
cnavarro
Posts: 5792
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Plotting locations on Google Maps

Post by cnavarro »

Yes, but I think you can not define popup and tooltip to the same marker

Image

In my previous sample, replace

Code: Select all

   For i := 1 to Len( aData )
      cAppendStr += "L.marker( "
      cAppendStr += "[ " + aData[ i ][ 3 ] + ", " + ;
                    Ltrim( aData[ i ][ 2 ] ) + " ] )."
      cAppendStr += "addTo(mymap).bindPopup('<b>Marker" + Str( i ) + " !</b><br />I am a popup.').openPopup();" + CRLF + CRLF
   Next
 
with

Code: Select all


   For i := 1 to Len( aData )
      cAppendStr += "L.marker( "
      cAppendStr += "[ " + aData[ i ][ 3 ] + ", " + ;
                    Ltrim( aData[ i ][ 2 ] ) + " ] ).addTo(mymap).bindTooltip('my tooltip text').openTooltip();" + CRLF + CRLF
   Next

 
C. Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
Si alguien te dice que algo no se puede hacer, recuerda que esta hablando de sus limitaciones, no de las tuyas.
User avatar
cnavarro
Posts: 5792
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Plotting locations on Google Maps

Post by cnavarro »

Change images for markers

Image

Code: Select all


   For i := 1 to Len( aData )
      cAppendStr += "L.marker( "
      cAppendStr += "[ " + aData[ i ][ 3 ] + ", " + ;
                    Ltrim( aData[ i ][ 2 ] ) + " ], {icon: greenIcon} )."
      cAppendStr += "addTo(mymap).bindPopup('<b>Marker" + Str( i ) + " !</b><br />I am a popup.').openPopup();" + CRLF + CRLF
   Next

 
C. Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
Si alguien te dice que algo no se puede hacer, recuerda que esta hablando de sus limitaciones, no de las tuyas.
User avatar
vilian
Posts: 795
Joined: Wed Nov 09, 2005 2:17 am
Location: Brazil
Contact:

Re: Plotting locations on Google Maps

Post by vilian »

Cnavarro,

You are creating the markers trough its address, isn't it ?
What i need to change for to do this trough lat/lng?
Sds,
Vilian F. Arraes
vilian@vfatec.com.br
Belém-Pa-Brazil
User avatar
cnavarro
Posts: 5792
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Plotting locations on Google Maps

Post by cnavarro »

Sorry, I do not understand your question and your needs
C. Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
Si alguien te dice que algo no se puede hacer, recuerda que esta hablando de sus limitaciones, no de las tuyas.
Post Reply