How can I get the latitude and longitude of a place clicked by a user on the map.
Thanks in advance
Get latitude and longitude
Re: Get latitude and longitude
Please try the following code.
Remember Google has changed its policies last July. Now, to use maps, Google requires you to register with them and then obtain an API key from them. You should use your Google Maps Javascript API key in your code to view the Map.
Once you have the API key with you, the following code will work. I tested it here with my API key and is working fine.
The code will show the lat and lon of the place when you move your mouse, if you click on a point on the map, it will place a marker where you have clicked. It will also show the lat and lon of the last clicked place above the Map window
You may modify the code to suit your requirements
Remember Google has changed its policies last July. Now, to use maps, Google requires you to register with them and then obtain an API key from them. You should use your Google Maps Javascript API key in your code to view the Map.
Once you have the API key with you, the following code will work. I tested it here with my API key and is working fine.
The code will show the lat and lon of the place when you move your mouse, if you click on a point on the map, it will place a marker where you have clicked. It will also show the lat and lon of the last clicked place above the Map window
Code: Select all
#Include "FiveWin.ch"
//-----------------------------
Function Main()
ViewGoogleMap()
Return NIL
//-----------------------------------------------------------------------/
Function ViewGoogleMap()
Local cMapFile:="D:\GMaps.htm", cHtmlContent
TEXT INTO cHtmlContent
<html>
<head>
<title>Google Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
#map {
height: 500px;
width: 900px;
}
</style>
</head>
<body>
<div id="latclicked"></div>
<div id="longclicked"></div>
<div id="latmoved"></div>
<div id="longmoved"></div>
<div style="padding:10px">
<div id="map"></div>
</div>
<script type="text/javascript">
var map;
function initMap() {
var latitude = 27.7172453; // YOUR LATITUDE VALUE
var longitude = 85.3239605; // YOUR LONGITUDE VALUE
var myLatLng = {lat: latitude, lng: longitude};
map = new google.maps.Map(document.getElementById('map'), {
center: myLatLng,
zoom: 14,
disableDoubleClickZoom: true, // disable the default map zoom on double click
});
// Update lat/long value of div when anywhere in the map is clicked
google.maps.event.addListener(map,'click',function(event) {
document.getElementById('latclicked').innerHTML = event.latLng.lat();
document.getElementById('longclicked').innerHTML = event.latLng.lng();
});
// Update lat/long value of div when you move the mouse over the map
google.maps.event.addListener(map,'mousemove',function(event) {
document.getElementById('latmoved').innerHTML = event.latLng.lat();
document.getElementById('longmoved').innerHTML = event.latLng.lng();
});
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
//title: 'Hello World'
// setting latitude & longitude as title of the marker
// title is shown when you hover over the marker
title: latitude + ', ' + longitude
});
// Update lat/long value of div when the marker is clicked
marker.addListener('click', function(event) {
document.getElementById('latclicked').innerHTML = event.latLng.lat();
document.getElementById('longclicked').innerHTML = event.latLng.lng();
});
// Create new marker on double click event on the map
google.maps.event.addListener(map,'dblclick',function(event) {
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
title: event.latLng.lat()+', '+event.latLng.lng()
});
// Update lat/long value of div when the marker is clicked
marker.addListener('click', function() {
document.getElementById('latclicked').innerHTML = event.latLng.lat();
document.getElementById('longclicked').innerHTML = event.latLng.lng();
});
});
// Create new marker on single click event on the map
google.maps.event.addListener(map,'click',function(event) {
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
title: event.latLng.lat()+', '+event.latLng.lng()
});
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=[YOUR API KEY HERE and remove the square brackets]&callback=initMap"
async defer></script>
</body>
</html>
ENDTEXT
MEMOWRIT( cMapFile, cHtmlContent )
// Opens the Map using your default internet browser. A more generic solution
Shellexecute( NIL, "open", cMapFile )
Return NIL
Re: Get latitude and longitude
Perfect. Many thanks.
Is it possible to pass the coordinates to the calling program?
Is it possible to pass the coordinates to the calling program?
Re: Get latitude and longitude
Instead ofbetoncu wrote:Perfect. Many thanks.
Is it possible to pass the coordinates to the calling program?
Code: Select all
Shellexecute( NIL, "open", cMapFile )
For eg something like
Code: Select all
oIE:=CreateObject("InternetExplorer.Application")
oIE:Document:getElementsByName("latclicked"):Item(0):Value
Re: Get latitude and longitude
Sorry but I couldn't. Anyhow, thanks for your help.
Re: Get latitude and longitude
Some time ago I did a FiveWin control that uses OpenStreetMap: http://forums.fivetechsupport.com/viewt ... =3&t=35535
here an updated code:
In this control is present the method GetCoordsFromPixel that returns {lon,lan}
And you can add put the markers with the method AddMarker.
What is necessary is replace the rendering of the markers
The only thing I ask is if you use it and improve it, share the improvement with the forum
here an updated code:
Code: Select all
#include <fivewin.ch>
********** TEST CODE **********
proc main
LOCAL oWnd, oMap
DEFINE WINDOW oWnd TITLE "3D objects"
SetWndDefault(oWnd)
oMap := TMapControl():New()
oMap:SetCenter(-4.806640,36.505522)
oMap:AddMarker(-4.806640,36.505522)
oWnd:oClient := oMap
ACTIVATE WINDOW oWnd
*******************************
/// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
class TMapControl FROM TControl
CLASSDATA lRegistered AS LOGICAL
CLASSDATA aServers AS ARRAY INIT {'https://a.tile.openstreetmap.org/{zoom}/{x}/{y}.png', ;
'https://b.tile.openstreetmap.org/{zoom}/{x}/{y}.png', ;
'https://c.tile.openstreetmap.org/{zoom}/{x}/{y}.png'}
CLASSDATA nMaxZoom AS NUMERIC INIT 19
DATA oTimer
DATA aHttps // Queue of downloading images, array of { "Msxml2.XMLHTTP.6.0", zoom, x, y, Seconds(), cUrl }
DATA nZoom, nLat, nLon // current zoom and center of the screen
DATA nServer // Last used server Id (from aServers)
DATA aMarkers AS ARRAY INIT {} // Couples of lat+lon to mark on map
DATA aImages AS ARRAY INIT {} // Array of loaded images
DATA aTopLeftTileInfo // Information about tile at top left corner { xpos, ypos, x-tile, y-tile }
DATA lastMousePos, lastRenderTime // mouse down position and seconds of last rendering
METHOD New( nRow, nCol, oWnd, nWidth, nHeight ) CONSTRUCTOR
METHOD End()
METHOD Display() INLINE ::BeginPaint(),::Paint(),::EndPaint(),0
METHOD EraseBkGnd( ) INLINE 1
METHOD Paint()
Method SetCenter(nLon,nLat)
Method AddMarker(nLon,nLat)
METHOD RButtonDown(nRow, nCol, nKeyFlags, lTouch)
METHOD LButtonDown(nRow, nCol, nKeyFlags, lTouch)
METHOD MouseMove( nRow, nCol, nKeyFlags )
METHOD MouseWheel( nKey, nDelta, nXPos, nYPos )
METHOD TimerEvent()
METHOD GetImage(x,y,zoom,lQueue) HIDDEN
METHOD GetTileNumber(lon,lat,zoom)
METHOD GetCoordsFromTile(x,y,zoom)
METHOD GetCoordsFromPixel(x,y)
METHOD PaintTile(hDCMem,hDCBmp,l,t,tx,ty,zoom)
endclass
METHOD New( nRow, nCol, oWnd, nWidth, nHeight ) CLASS TMapControl
DEFAULT nRow := 10, nCol := 10, oWnd := GetWndDefault()
DEFAULT nWidth := 500
DEFAULT nHeight := 300
::nZoom := 15
::nLon := 0
::nLat := 0
::nServer := 1
::aMarkers := {}
::oWnd := oWnd
::nId := ::GetNewId()
::nStyle := nOR( WS_CHILD, WS_VISIBLE, WS_TABSTOP, WS_BORDER )
::nTop := nRow
::nLeft := nCol
::nBottom := ::nTop + nHeight - 1
::nRight := ::nLeft + nWidth
::aHttps := {}
::Register( nOR( CS_VREDRAW, CS_HREDRAW ) )
if ! Empty( oWnd:hWnd )
::Create( )
oWnd:AddControl( Self )
else
oWnd:DefControl( Self )
endif
DEFINE TIMER ::oTimer OF SELF INTERVAL 0.1 ACTION ::TimerEvent()
::oTimer:Activate()
return Self
METHOD End() class TMapControl
if .not. empty(::oTimer)
::oTimer:Deactivate()
::oTimer:End()
endif
return ::Super:End()
Method SetCenter(nLon,nLat) class TMapControl
local r := {::nLon,::nLat}
::nLon := nLon
::nLat := nLat
return r
Method AddMarker(nLon,nLat) class TMapControl
return aAdd(::aMarkers, {nLon,nLat})
#define SRCCOPY 13369376
METHOD Paint() class TMapControl
LOCAL x,y, img, ix,iy, top, left, sx,sy, hBmpMem
LOCAL w := ::nWidth, h := ::nHeight, hDCMem, hDCBmp
hDCMem = CreateCompatibleDC( ::hDC )
hBmpMem = CreateCompatibleBitmap( ::hDC, w, h )
SelectObject( hDCMem, hBmpMem )
FillRect( hDCMem, {0,0,h,w}, ::oBrush:hBrush )
// get tile of center
x := ::GetTileNumber(::nLon,::nLat)
y := x[2]
x := x[1]
// move the desired pixel in the centre of canvas
sx := floor(x)
sy := floor(y)
top := h/2 - int((y-sy)*256)
left := w/2 - int((x-sx)*256)
// check for fill all area
do while top>0
sy-=1
top-=256
enddo
do while left>0
sx-=1
left-=256
enddo
// draw the map
::lastRenderTime := Seconds()
hDCBmp := CreateCompatibleDC( ::hDC )
for iy:=0 to ceiling((h-top)/256)
for ix:=0 to ceiling((w-left)/256)
::PaintTile(hDCMem,hDCBmp,left+ix*256,top+iy*256 ,sx+ix,sy+iy,::nZoom)
next
next
DeleteDC( hDCBmp )
// draw the markers
for ix:=1 to len(::aMarkers)
x := ::GetTileNumber(::aMarkers[ix,1],::aMarkers[ix,2])
y := (x[2] - sy) * 256 + top
x := (x[1] - sx) * 256 + left
MoveTo(hDCMem,x-5,y-5)
LineTo(hDCMem,x+5,y+5)
MoveTo(hDCMem,x-5,y+5)
LineTo(hDCMem,x+5,y-5)
next
// save these infos
::aTopLeftTileInfo := {top,left,sx,sy}
//img := "Queue len: " + alltrim(str(len(::aHttps)))
//TextOut( hDCMem, 4, 4, img, Len( img ) )
BitBlt( ::hDC, 0,0, w, h, hDCMem, 0,0, SRCCOPY )
DeleteDC(hDCMem)
return nil
METHOD PaintTile(hDCMem,hDCBmp,l,t,tx,ty,zoom)
LOCAL img, sx,sy, ix, iy, n
img := ::GetImage(tx,ty,zoom)
if .not. empty(img)
SelectObject(hDCBmp, img)
BitBlt( hDCMem, l,t, 256, 256, hDCBmp, 0,0, SRCCOPY )
return nil
endif
// try less zoomed images (if they are not in cache it are not downloaded)
img := ::GetImage(hb_bitShift(tx,-1),hb_bitShift(ty,-1),zoom-1,.F.)
if .not. empty(img)
SelectObject(hDCBmp, img)
StretchBlt( hDCMem, l,t, 256, 256, hDCBmp, hb_bitAnd(tx,1)*128,hb_bitAnd(ty,1)*128,128,128, SRCCOPY )
return nil
endif
sx := hb_bitShift(tx,1)
sy := hb_bitShift(ty,1)
for iy:=0 to 1
for ix:=0 to 1
img := ::GetImage(sx+ix,sy+iy,zoom+1,.F.)
if .not. empty(img)
SelectObject(hDCBmp, img)
StretchBlt( hDCMem, l+ix*128,t+iy*128, 128, 128, hDCBmp, 0,0,255,255, SRCCOPY )
endif
next
next
return nil
METHOD TimerEvent() class TMapControl
LOCAL lRedraw := .F., oHttp, img, idx
for idx:=1 to len(::aHttps)
oHttp := ::aHttps[idx]
if oHttp[1]:readyState = 4
// downloaded a missing image!
img := GDIP_ImageFromStr(oHttp[1]:ResponseBody(), .t., .f.)
if .not. empty(img) // correctly created
lRedraw := .T.
aAdd(::aImages, { img, oHttp[2], oHttp[3], oHttp[4] })
endif
hb_ADel(::aHttps,idx,.t.)
else
// stop the unfinisched download that are not relative of current view
if oHttp[5]<::lastRenderTime
oHttp[1]:abort()
hb_ADel(::aHttps,idx,.t.)
endif
endif
next
if lRedraw
::Refresh()
endif
return nil
// directly from OpenStreetMap wiki
METHOD GetTileNumber(lon,lat,zoom) class TMapControl
LOCAL x,y,n, latRad
DEFAULT zoom := ::nZoom
n := hb_bitShift(1, zoom)
latRad := lat * PI() / 180
x := n * (lon + 180) / 360
y := n * (1-(log(tan(latRad) + 1/cos(latRad)) / PI())) / 2
do while(x<0)
x+=n
enddo
do while(x>=n)
x-=n
enddo
if y<0
y:=0
endif
if y>=n
y:=n-1
endif
return {x,y}
// directly from OpenStreetMap wiki
METHOD GetCoordsFromTile(x,y,zoom) class TMapControl
LOCAL lon, lat, n, lat_rad
DEFAULT zoom := ::nZoom
n := hb_bitShift(1, zoom)
lon = x / n * 360.0 - 180.0
lat_rad = atan(sinh(PI() * (1 - 2 * y / n)))
lat = lat_rad * 180.0 / PI()
return {lon,lat}
// screen to tile, with decimal, using aTopLeftTileInfo
METHOD GetCoordsFromPixel(x,y) class TMapControl
LOCAL top := ::aTopLeftTileInfo[1]
LOCAL left := ::aTopLeftTileInfo[2]
LOCAL sx := ::aTopLeftTileInfo[3]
LOCAL sy := ::aTopLeftTileInfo[4]
return ::GetCoordsFromTile(sx+(x-left)/256,sy+(y-top)/256)
METHOD LButtonDown(nRow, nCol, nKeyFlags, lTouch) class TMapControl
::lastMousePos := {nRow,nCol}
return ::Super:LButtonDown( nRow, nCol, nKeyFlags, lTouch )
METHOD RButtonDown(nRow, nCol, nKeyFlags, lTouch) class TMapControl
::lastMousePos := {nRow,nCol}
return ::Super:RButtonDown( nRow, nCol, nKeyFlags, lTouch )
METHOD MouseMove( nRow, nCol, nKeyFlags ) class TMapControl
LOCAL oldMouseCoords,newMouseCoords
if (nKeyFlags<>1 .and. nKeyFlags<>2) .or. empty(::lastMousePos)
return 0
endif
oldMouseCoords := ::GetCoordsFromPixel(::lastMousePos[2],::lastMousePos[1])
newMouseCoords := ::GetCoordsFromPixel(nCol,nRow)
::nLon += oldMouseCoords[1] - newMouseCoords[1]
::nLat += oldMouseCoords[2] - newMouseCoords[2]
::lastMousePos := {nRow,nCol}
::Refresh()
return ::Super:MouseMove( nRow, nCol, nKeyFlags )
METHOD MouseWheel( nKey, nDelta, nXPos, nYPos ) class TMapControl
if nDelta>0 .and. ::nZoom<::nMaxZoom
::nZoom+=1
endif
if nDelta<0 .and. ::nZoom>0
::nZoom-=1
endif
::Refresh()
return ::Super:MouseWheel( nKey, nDelta, nXPos, nYPos )
METHOD GetImage(x,y,zoom,lQueue) class TMapControl
local n, cUrl, img
LOCAL oHttp
DEFAULT zoom := ::nZoom
DEFAULT lQueue := .T.
x:=int(x)
y:=int(y)
// looking for the image in the "cache"
n:= aScan(::aImages, {|v| v[2]=zoom .and. v[3]=x .and. v[4]=y })
if n>0
// move the last returned image on top of cache
img := ::aImages[n][1]
//aDel(::aImages,n)
//::aImages[len(::aImages)] := img
return img
endif
if .not. lQueue
return nil
endif
// TODO: Limit cache size
cUrl := ::aServers[::nServer]
::nServer++
if ::nServer>len(::aServers)
::nServer:=1
endif
cUrl := StrTran(cUrl,"{zoom}", allTrim(str(zoom)))
cUrl := StrTran(cUrl,"{x}", allTrim(str(x)))
cUrl := StrTran(cUrl,"{y}", allTrim(str(y)))
if (n:=aScan(::aHttps, {|v| v[2] = zoom .and. v[3] = x .and. v[4] = y})) > 0
// already in download, update last query time
::aHttps[n,5]:=Seconds()
return nil
endif
begin sequence
oHttp := win_oleCreateObject( "Msxml2.XMLHTTP.6.0" )
oHttp:Open("GET", cUrl, .T. )
oHttp:Send()
if oHttp:readyState <> 4
if oHttp:readyState=1 .or. oHttp:readyState=3
aAdd(::aHttps,{ oHttp, zoom, x, y, Seconds(), cUrl })
endif
else
img := GDIP_ImageFromStr(oHttp:ResponseBody(), .t., .f.)
if .not. empty(img)
aAdd(::aImages, { img, zoom, x, y })
endif
endif
end sequence
return img
And you can add put the markers with the method AddMarker.
What is necessary is replace the rendering of the markers
The only thing I ask is if you use it and improve it, share the improvement with the forum