EDIT: I have implemented my possible solution 1, it works however as mentioned it is not the best solution so I would still be interested in other suggestions.
I have a delphi VCL application that loads a mapbox map into a Twebbrowser component. I am using the map as input to get GPS coords and a street address.
The javascript enables you to click on the map to place a marker, you can also drag it around etc.
I have a javascript function that performs the reverse geocode on the markers position and saves the address to a variable.
function getAddress(err, data){
var center = data.features[0].center;
streetAddress = data.features[0].place_name;
myMarker.setPopupContent("Position: <br /> lat = " + center[0] + "<br /> long = " + center[1] + "<br /> Address: " + streetAddress);
}
function delphiLocate(){
geocoder.reverseQuery(myMarker.getLatLng(), getAddress);
gpsCoords = myMarker.getLatLng().toString();
}
This function can be called by clicking on the marker or through my Delphi program.
My delphi code can also read the address variable from the javascript.
procedure TfrmCreateSpot.getSpotPos;
var
doc: OleVariant;
begin
doc := WebBrowser1.document;
doc.parentwindow.execScript('delphiLocate()', 'JavaScript');
sGpsCoords := doc.parentwindow.gpsCoords;
sGpsCoords := copy(sGpsCoords, Pos('(', sGpsCoords) + 1);
delete(sGpsCoords, Pos(')', sGpsCoords), 1);
sStreetAddress := doc.parentwindow.streetAddress;
end;
This getSpotPos procedure is called on a button click to confirm the location.
The problem is the geolocate takes a while to return a result and by the time it returns my program has already recorded the information from the last marker position.
How can I ensure that I get the address from the current marker position?
Possible solutions:
1) If I call the locate function every time the marker is moved then the geolocate should have finished before the user clicks the confirm button. However, this seems like a rather hacky possibly unreliable solution plus it could use a lot more geolocate requests than necessary(This isn't a problem for me as its only a school project and won't be going over my 100 000 limit, but id like to implement the best solution.
2) Create a flag in the javaScript that is made true when the results are returned, in my Delphi code I could use a timer to check if this flag is true and then request the results.
Here is the complete Html script
<title>Map</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox.js/v3.3.0/mapbox.js'></script>
<link href='https://api.mapbox.com/mapbox.js/v3.3.0/mapbox.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; width : 100%; }
#map {position : absolute; top:0; bottom:0; width: 100%; }
</style>
</head>
<body>
<div id='map'></div>
<script>
function mapClick(e){
if (!locked){
myMarker.setLatLng(e.latlng);
}
}
function locate(e) {
geocoder.reverseQuery(e.latlng, getAddress);
gpsCoords = e.latlng.toString();
}
function getAddress(err, data){
var center = data.features[0].center;
streetAddress = data.features[0].place_name;
myMarker.setPopupContent("Position: <br /> lat = " + center[0] + "<br /> long = " + center[1] + "<br /> Address: " + streetAddress);
}
function centerMarker(e){
if (!locked){
var coords = e.feature.geometry.coordinates;
myMarker.setLatLng([coords[1],coords[0]]);// lat lng are swapped
}
}
function delphiLocate(){
geocoder.reverseQuery(myMarker.getLatLng(), getAddress);
gpsCoords = myMarker.getLatLng().toString();
}
var locked = false;
function toggleLock(){
if (!locked) {
myMarker.setIcon(redIcon);
myMarker.dragging.disable();
locked = true;
} else {
myMarker.setIcon(blueIcon);
myMarker.dragging.enable();
locked = false;
}
}
L.mapbox.accessToken = 'pk.eyJ1IjoiZ3JlZW5vbGl2ZSIsImEiOiJjazk4N3hpcngwMDU0M2VvMGhydGw2Z2YxIn0.wvwQzgwsaujmkNOX7Bs47A';
var map = L.mapbox.map('map')
.setView([-30.487,23.181], 6)
.addLayer(L.mapbox.styleLayer('mapbox://styles/greenolive/ck9fi6dbk3hag1itg5aem2ypi'));
var geocoderControl = L.mapbox.geocoderControl('mapbox.places',{autocomplete : true}).addTo(map);
var geocoder = L.mapbox.geocoder('mapbox.places');
var blueIcon = L.icon({
iconUrl: 'blueMarker.png',
iconSize: [40, 40], // size of the icon
iconAnchor: [20, 40], // point of the icon which will correspond to marker's location
popupAnchor: [0, -40] // point from which the popup should open relative to the iconAnchor
});
var redIcon = L.icon({
iconUrl: 'redMarker.png',
iconSize: [40, 40], // size of the icon
iconAnchor: [20, 40], // point of the icon which will correspond to marker's location
popupAnchor: [0, -40] // point from which the popup should open relative to the iconAnchor
});
var myMarker = L.marker(map.getCenter(), { draggable : true, icon : blueIcon}).addTo(map).bindPopup("Position: <br /> lat = " + map.getCenter().lat + "<br /> long = " + map.getCenter().lng+ "<br /> Address: ");
var gpsCoords;
var streetAddress;
map.on('click',mapClick);
myMarker.on('click', locate);
geocoderControl.on('select', centerMarker);
</script>
</body>
</html>