【问题标题】:Return mapbox geocode results to Delphi from Javascript从 Javascript 将 mapbox 地理编码结果返回到 Delphi
【发布时间】:2020-04-26 16:36:07
【问题描述】:

编辑:我已经实现了我可能的解决方案 1,但它可以工作,但是如上所述,它不是最好的解决方案,所以我仍然会对其他建议感兴趣。

我有一个 delphi VCL 应用程序,可以将 mapbox 地图加载到 Twebbrowser 组件中。我使用地图作为输入来获取 GPS 坐标和街道地址。
javascript使您可以单击地图以放置标记,也可以将其拖动等。 我有一个 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 过程在单击按钮以确认位置时调用。
问题是 geolocate 需要一段时间才能返回结果,并且当它返回时,我的程序已经记录了最后一个标记位置的信息。

如何确保从当前标记位置获取地址?

可能的解决方案:

1) 如果我在每次移动标记时调用定位函数,那么地理定位应该在用户单击确认按钮之前完成。然而,这似乎是一个相当 hacky 可能不可靠的解决方案,而且它可能使用比必要更多的地理定位请求(这对我来说不是问题,因为它只是一个学校项目,不会超过我的 100 000 限制,但是我喜欢实施最好的解决方案。

2) 在返回结果时在 javaScript 中创建一个标志,在我的 Delphi 代码中我可以使用计时器来检查该标志是否为真,然后请求结果。

这是完整的 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>

【问题讨论】:

  • 干得好。但是就像您的建议一样,我认为您可以在移动标记时将 streetAddress 设为空,这样在 geolocate 函数返回之前它不会显示地址。
  • @R.Hoek 我不确定这对我有什么帮助,我需要我的 Delphi 程序知道函数何时返回
  • 嗯,最好编辑你的问题,因为现在的问题是“知道函数是否返回”,在这种情况下,我的想法(或你的标志想法)就足够了。但是想要“在函数返回时在 delphi 中得到通知”(就像一个事件)-对吗?
  • @OliverHope 如果你想要一些类似事件的东西,也许这个线程可以帮助javascript.developreference.com/article/20717415/…

标签: javascript html delphi mapbox vcl


【解决方案1】:

您似乎在此处设置变量gpsCoords

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

调用delphiLocate 函数后,您在Delphi 脚本中访问它。因此应该更新 JS 中的gpsCoords 变量。然而,在您的 Delphi 脚本中,您仍然在访问在调用 delphiLocate 之前已加载的 doc 对象。这个对象应该仍然有旧的gpsCoords

你能在调用delphiLocate之后尝试重新加载doc对象吗?

  doc := WebBrowser1.document;

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

【讨论】:

  • 这听起来是对的,也许这是一种更安全的方法,但是当我不重新加载它时,它似乎不会引起问题。我的问题是街道地址,而不是 GPS 坐标,因为 javascript 必须联系地图框服务并获得结果,这需要时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-10
  • 2013-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多