如何在异步访问外部 JSON 数据时向地图添加可变标记

How to add variying markers to a map when accessing external JSON data asynchronously

我有以下 markercollection.json 文件,在一个名为 features 的数组中包含多个地理对象。

{
    "features":
    [
        {
            "name": "Point A",
            "address": {
                "street": "228 Park Ave S",
                "zipcode": "10003",
                "city": "New York"
            },
            "description": "Sample description for point A",
            "iconFile": "icon-marker-iconsample-a.png",
            "filterPrimary": "hotel",
            "year": "2014"
        },
        {
            "name": "Point B",
            "address": {
                "street": "542 W. 27th Street",
                "zipcode": "10001",
                "city": "New York"
            },
            "description": "Sample description for point B",
            "iconFile": "icon-marker-iconsample-b.png",
            "filterPrimary": "pub",
            "year": "2015"
        }
    ]
}

我正在使用传单 JavaScript 库在地图上放置相应的标记。由于我没有经度和纬度,我已将对象的 address 传递给地理编码服务。为此,我目前正在使用 mapbox,但我也尝试过使用 OSM nominatim。两者都按预期工作。

mapbox geocoding API 需要传递一个回调函数来处理结果数据(即经度和纬度)。

到目前为止,我已经弄清楚了如何将地理对象传递给地理编码器,并让我的 addMarkers 回调函数将相应的标记添加到我的地图中。除此之外,我还想让我的标记具有不同的图标,具体取决于原始 JSON 文件中的 iconFile 值。

我一直无法弄清楚在哪里构建并随后添加我的自定义标记。我尝试为每个循环构建标记图标,但所有标记都使用相同的图标(请参阅我的屏幕截图)。

我假设这是因为在我的 addMarkers 函数被触发之前循环已经完成,所以 sIconFile 的值是最后一次循环迭代的值。

我是否必须链接另一个回调,如果是,最好的方法是什么?

        // Pass Mapbox access token and set initial map view
        L.mapbox.accessToken = ACCESS_TOKEN;
        var myMap = L.mapbox.map('map','mapbox.streets').setView([40.730610, -73.935242], 13);

        // 
        var promise = $.getJSON('data/markercollection.json')
            .then(function(data) {

                /**
                 * Iterate through fetched data and do something...
                 */
                for (var i = 0; i < data.features.length; i++) {

                    // Build address string for passing to geocoder
                    var sAddress = data.features[i].address.street + ', ' + data.features[i].address.zipcode + ', ' + data.features[i].address.city;

                    // Icon file string variable
                    var sIconFile = data.features[i].iconFile;

                    /**
                     * Query Mapbox geocoder with address string
                     * and pass reply to addMakers function as per
                     * mapbox geocoder API
                     */
                    L.mapbox.geocoder('mapbox.places').query(sAddress, addMarkers);

                    // Add markers to geocoded latitudes and longitudes to map 
                    function addMarkers(err, geocoderCallbackData) {
                        console.log(sIconFile); // accessing the variable here does not work :(
                        L.marker(geocoderCallbackData.latlng).addTo(myMap);
                    }
                }

            // Basic error-handling
            }, function() {
                console.log('An error has occured!');
        });

通过使用 forEach(fn) 而不是 for(...) 循环遍历 data.features,您将受益于 fn 提供的本地作用域。

因此 :

data.features.forEach(function(feature) {
    var sAddress = feature.address.street + ', ' + feature.address.zipcode + ', ' + feature.address.city;
    var sIconFile = feature.iconFile;
    L.mapbox.geocoder('mapbox.places').query(sAddress, addMarkers);
    function addMarkers(err, geocoderCallbackData) {
        console.log(sIconFile);
        L.marker(geocoderCallbackData.latlng).addTo(myMap);
    }
});