Вернуть результаты геокода mapbox в Delphi из Javascript - PullRequest
1 голос
/ 26 апреля 2020

РЕДАКТИРОВАТЬ : я реализовал свое возможное решение 1, оно работает, однако, как уже упоминалось, это не лучшее решение, поэтому мне все равно будут интересны другие предложения.

У меня есть delphi Приложение VCL, которое загружает карту mapbox в компонент Twebbrowser. Я использую карту в качестве входных данных, чтобы получить координаты GPS и адрес улицы.
javascript позволяет нажимать на карту, чтобы разместить маркер, вы также можете перетаскивать ее вокруг et c. У меня есть javascript функция, которая выполняет обратный геокод на позиции маркеров и сохраняет адрес в переменной.

        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();
        }

Эта функция может быть вызвана нажатием на маркер или с помощью моей программы Delphi.
Мой код delphi также может считывать переменную адреса из 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;

Эта процедура getSpotPos вызывается нажатием кнопки для подтверждения местоположения.
Проблема в том, что геолокация требует времени, чтобы вернуть результат, и к тому времени, когда он вернется, моя программа уже записала информация с последней позиции маркера.

Как я могу получить адрес от текущей позиции маркера?

Возможные решения:

1) Если я вызываю функцию locate при каждом перемещении маркера тогда геолокация должна была закончиться до того, как пользователь нажмет кнопку подтверждения. Тем не менее, это кажется довольно хакерским, возможно, ненадежным решением, плюс оно может использовать гораздо больше запросов геолокации, чем необходимо (для меня это не проблема, поскольку это всего лишь школьный проект, и он не превысит мой предел в 100 000, но я хотел бы реализовать лучшее решение.

2) Создайте флаг в javaScript, который становится истинным при возврате результатов, в моем коде Delphi я мог бы использовать таймер, чтобы проверить, если этот флаг true и затем запросить результаты.

Вот полный Html скрипт

<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>

1 Ответ

0 голосов
/ 29 апреля 2020

Похоже, что вы устанавливаете переменную gpsCoords здесь:

        function delphiLocate(){
        geocoder.reverseQuery(myMarker.getLatLng(), getAddress);
        gpsCoords = myMarker.getLatLng().toString();
    }

К которому вы обращаетесь в скрипте Delphi после вызова функции delphiLocate. Поэтому переменная gpsCoords в JS должна быть обновлена. Однако в вашем скрипте Delphi вы по-прежнему обращаетесь к объекту doc, который вы загрузили перед вызовом delphiLocate. Этот объект должен все еще иметь старый gpsCoords.

Можете ли вы попытаться перезагрузить объект doc после вызова delphiLocate?

  doc := WebBrowser1.document;

  doc.parentwindow.execScript('delphiLocate()', 'JavaScript');
doc := WebBrowser1.document;
  sGpsCoords := doc.parentwindow.gpsCoords;
...