How can I get the latitude and longitude of a place clicked by a user on the map.
Thanks in advance
#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
betoncu wrote:Perfect. Many thanks.
Is it possible to pass the coordinates to the calling program?
Shellexecute( NIL, "open", cMapFile )
oIE:=CreateObject("InternetExplorer.Application")
oIE:Document:getElementsByName("latclicked"):Item(0):Value
#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/Sli ... _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
Return to FiveWin for Harbour/xHarbour
Users browsing this forum: No registered users and 22 guests