在中间循环数上使用最终循环值

时间:2014-02-28 17:59:36

标签: javascript google-maps loops google-maps-api-3 latitude-longitude

我希望标题甚至可以理解。我有一个比较两个值的函数,其中一个值是第一个值的平均值。

基本上,我想找到n个标记的Long,Lat和中心标记之间的距离。我有一个循环将我的“results”变量推送到一个数组,并在循环结束时找到一个平均Lat,Long创建一个中心点。问题是我想找到每个“结果”和中心点之间的距离,但是在中间循环中,平均标记尚未最终确定。

更难解释而不是展示;我在这里设置了一个演示;要查看我的意思,请单击结果窗格中的“更新”按钮:http://jsfiddle.net/Cory2711/m55Ef/。你会看到的 从加利福尼亚发出的圆圈是正确的,因为它是最后一个圆圈(找到了完整的平均点)。来自纽约的圆圈是在中环,因此有一个不完整的平均标记来测量。

我的Javascript(问题集中在“标记”部分:

//GLOBAL VARIABLES
var gMapAPIKey = 'AIzaSyBUlnM6c7LqCR79UM9mTKvSNK6V7gzKsmE';
var namearray = document.getElementsByName("name");
var form = document.getElementById("addressform");
var addBtn = document.getElementById("addperson");


//GOOGLE MAPS API SCRIPTS
var streetarray = document.getElementsByName("street");
var cityarray = document.getElementsByName("city");
var geocoder;
var map;
var results;
var mapArray = new Array();
var AvgLat = 0;
var AvgLng = 0;
var j;
var newLatLng;
var dynamicRadius;




function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
    zoom: 3,
    //centered on Carrollton, Texas -- Change lat,long values to change initial map area
    center: new google.maps.LatLng(32.999173, -96.897413)
}
//change Id reference to the div/container that contains the google map
map = new google.maps.Map(document.getElementById('map'), mapOptions);
}

function codeAddress() {
//Loop through and concate street and city values to find long,lat values for all fields
for (var cName = 0; cName < namearray.length; cName++) {
    var address = streetarray[cName].value + cityarray[cName].value;

    //start geocode copy  & paste text from API reference
    geocoder.geocode({
        'address': address
    }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            var results = results[0].geometry.location;
            map.setCenter(results);
            console.log(results);
            var marker = new google.maps.Marker({
                map: map,
                position: results,

            });
            //Push lng/lat locations to the mapArray and find AvgLat/Lngs
            mapArray.push(results);
            var j = mapArray.length;
            AvgLat = (AvgLat + results.lat());
            AvgLng = (AvgLng + results.lng());

            console.log(mapArray, AvgLat, AvgLng, j)

            //Begin Marker Scripts

            var markerCircle = new google.maps.Circle({
                center: results,
                radius: 15000,
                strokeColor: "#0000FF",
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: "#0000FF",
                fillOpacity: 0.4


            })
            var centerLocation = {
                    lat: AvgLat / j,
                    lng: AvgLng / j,
                }

           var newLatLng = new google.maps.LatLng(centerLocation.lat,     centerLocation.lng);
           var dynamicRadius = google.maps.geometry.spherical.computeDistanceBetween     (results, newLatLng);
            if (j == namearray.length) {

            markerCircle.setRadius(dynamicRadius*1.15)                    
                map.setCenter(newLatLng);
                var centerMarker = new google.maps.Marker({
                    position: newLatLng,
                    map: map,
                    title: "Center Marker",
                })
                var centerCircle = new google.maps.Circle({
                    center: newLatLng,
                    radius: 15000,
                    strokeColor: "#0000FF",
                    strokeOpacity: 0.8,
                    strokeWeight: 2,
                    fillColor: "#0000FF",
                    fillOpacity: 0.4,
                    map: map,
                })


            }
            markerCircle.setRadius(dynamicRadius*1.15)
            markerCircle.setMap(map);


        } else {
            alert('Geocode was not successful for the following reason: ' + status);
        }
    });


}
}

//Initialize the first map on load -- When form is submitted geocode addresses and   places markers on the map
google.maps.event.addDomListener(window, 'load', initialize);
form.addEventListener("submit", codeAddress, false);
 addBtn.addEventListener("click", addPerson, false);

1 个答案:

答案 0 :(得分:1)

我的第一个想法是,您不仅限于将数据循环一次。循环后数据仍然存在(除非您在此过程中更改或销毁它)。

所以,你要使用两个循环。

第一个循环计算中心点。

第二个循环计算该点的所有距离。

但是当我查看你的代码时,我发现它还有更多的东西。

在主循环中迭代namearray,循环为此数组的每个元素调用geocoder.geocode()。然后在地理编码器回调中进行工作。

有趣的是,这段代码实际上并不是主循环的一部分。它出现在该循环内部,但随后会逐渐调用它,因为地理编码响应会逐一返回。

因此,我们假设地理编码中没有错误(错误的假设,但我们将暂时运行它)。您的地理编码器回调已将每个地理编码结果推送到mapArray。所以你可以做的是让这个回调代码这样做而不做任何中心/圆计算。所以你的地理编码调用可能看起来更像这样:

    geocoder.geocode({
        'address': address
    }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            mapArray.push({ latLng: results[0].geometry.location });
            AvgLat += results.lat();
            AvgLng += results.lng();
        } else {
            mapArray.push({ error: status });
            ++nErrors;
        }

        // Might want to update a progress indicator here
        // if the geocoding takes a while?

        if( mapArray.length == namearray.length ) {
            // Everything is geocoded, now get to work
            drawMap();
        }
    });

nErrors应在使用var nErrors = 0;初始化其他变量的循环上方定义。

然后完全在当前主循环之外,添加此功能:

function drawMap() {
    if( nErrors ) {
        // complain about error
        return;
    }

    var center = {
        lat: AvgLat / j,
        lng: AvgLng / j,
    };
    map.setCenter( new google.maps.LatLng( center.lat, center.lng ) );

    for( var i = 0;  i < mapArray.length;  i++ ) {
        // Create marker and draw circle here
    }
}

所以其他几点。首先,以这种方式计算平均纬度/经度听起来不太合适。我会考虑(和测试)标记是0°和180°经线的不同侧面的情况。你可能在那里,我从不指望它!

实际上你想要的是“平均”纬度/长度吗? (可能只是问。)如果你有很多标记在彼此附近并且在某个距离上有很少的标记(例如CA中的10个标记和NY中的1个标记),则“平均”将非常接近该标记簇。这可能是你想要的,但如果没有,还有其他方法来计算各种“中心”。

例如,一种常见方法是创建一个空的LatLngBounds对象,然后使用您收到的每个位置扩展这些边界。所以在你的其他变量初始化的顶部,你要添加:

var bounds = new google.maps.LatLngBounds;

然后在每个成功的地理编码回调中,你将替换它:

            AvgLat += results.lat();
            AvgLng += results.lng();

使用:

            bounds.extend( results );

然后在drawMap()中替换它:

    var center = {
        lat: AvgLat / j,
        lng: AvgLng / j,
    };
    map.setCenter( new google.maps.LatLng( center.lat, center.lng ) );

使用:

    map.fitBounds( bounds );
    var center = bounds.getCenter();

如果您需要这些单独的值,请使用center.lat()center.lng() - 但是在您拥有newLatLng的地方,您现在可以直接使用center,因为它 一个LatLng对象。

即使您确实想要使用圆圈计算的“平均”点,您也可以使用此边界框方法进行地图居中,而不是将地图置于计算平均值的中心。

最后一点是要注意地理编码的速率限制和限制。也许您可以使用少量标记,但是您可能需要在它们之间使用时间间隔进行地理编码调用,而不是将它们全部放入硬循环中。