Page 2 of 4
Re: Plotting locations on Google Maps
Posted: Fri Mar 10, 2017 4:22 am
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 | Expand
#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
Re: Plotting locations on Google Maps
Posted: Fri Mar 10, 2017 5:14 am
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.
Re: Plotting locations on Google Maps
Posted: Fri Mar 10, 2017 5:44 am
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.
Re: Plotting locations on Google Maps
Posted: Fri Mar 10, 2017 5:41 pm
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
Re: Plotting locations on Google Maps
Posted: Fri Mar 10, 2017 6:28 pm
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 | Expand
#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
//----------------------------------------------------------------------------//
Re: Plotting locations on Google Maps
Posted: Wed Mar 15, 2017 5:08 pm
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.
Re: Plotting locations on Google Maps
Posted: Wed Mar 15, 2017 9:16 pm
by cnavarro
My son, has recommended this lib
http://leafletjs.com/index.htmlThis is a sample
If you have the length and latitude, you do not need to run the function
VerMapa2()Code: Select all | Expand
#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 © <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
//----------------------------------------------------------------------------//
Re: Plotting locations on Google Maps
Posted: Wed Mar 15, 2017 9:28 pm
by TimStone
Thank you. I will explore that resource.
Re: Plotting locations on Google Maps
Posted: Thu Mar 16, 2017 12:22 pm
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?
Re: Plotting locations on Google Maps
Posted: Thu Mar 16, 2017 1:35 pm
by cnavarro
Re: Plotting locations on Google Maps
Posted: Thu Mar 16, 2017 2:39 pm
by vilian
Cnavarro,
No, is something like this:

But for to be shown for all points, without be necessary to do a click over them.
Re: Plotting locations on Google Maps
Posted: Thu Mar 16, 2017 3:14 pm
by cnavarro
Yes, but I think you can not define popup and tooltip to the same marker

In my previous sample, replace
Code: Select all | Expand
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 | Expand
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
Re: Plotting locations on Google Maps
Posted: Thu Mar 16, 2017 3:55 pm
by cnavarro
Change images for markers

Code: Select all | Expand
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
Re: Plotting locations on Google Maps
Posted: Fri Mar 17, 2017 11:27 am
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?
Re: Plotting locations on Google Maps
Posted: Fri Mar 17, 2017 1:41 pm
by cnavarro
Sorry, I do not understand your question and your needs