41

我遇到了一个在这些论坛中讨论得很好的问题,但似乎没有一个建议对我有用,所以我正在寻找一些在保存为 html 文件时可以工作的完整 javascript。

问题是我在尝试使用 Javascript 调用的 V3 API 对 Google 地图上 > 11 个位置进行地理编码时不断遇到 OVER_QUERY_LIMIT 错误。我知道调用地理编码器的速率是有限制的(以及总交易量的每日限制),所以我需要在数组中的每个结果之间引入一个暂停。

非常感谢任何帮助。

这是我的代码:

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var geocoder;
var map;
var wait = false;


  function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(51.32, 0.5);



var myOptions = {
  zoom: 8,
  center: latlng,
  mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
codeAddress('KT16 8LA' + ', UK');
codeAddress('LS8 2LQ' + ', UK');
codeAddress('NE13 8AF' + ', UK');
codeAddress('KT12 2BE' + ', UK');
codeAddress('W1W 8AN' + ', UK');
codeAddress('EC3N 2LS' + ', UK');
codeAddress('BS9 3BH' + ', UK');
codeAddress('KA10 6LZ' + ', UK');
codeAddress('EC1V 9BW' + ', UK');
codeAddress('WD18 8YN' + ', UK');
codeAddress('HA3 6DQ' + ', UK');
codeAddress('W1U 3PL' + ', UK');
codeAddress('W1T 7QL' + ', UK');
codeAddress('W1S 1TD' + ', UK');
codeAddress('SW1X 8NX' + ', UK');
codeAddress('LE2 8ET' + ', UK');
codeAddress('BA3 4BH' + ', UK');
codeAddress('AL3 8JP' + ', UK');
codeAddress('DE55 4QJ' + ', UK');
codeAddress('W6 0QT' + ', UK');
codeAddress('LA1 1PP' + ', UK');
codeAddress('SW16 4DH' + ', UK');
codeAddress('WC2N 6DF' + ', UK');
codeAddress('RM6 6LS' + ', UK');
codeAddress('S25 3QZ' + ', UK');
codeAddress('WC2H 7LR' + ', UK');
codeAddress('BH24 1DW' + ', UK');
codeAddress('EC2N 6AR' + ', UK');
codeAddress('W1U 2FA' + ', UK');
codeAddress('B60 3DX' + ', UK');    
}

  function codeAddress(vPostCode) {
if (geocoder) {
  geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
          map: map, 
          position: results[0].geometry.location
      });
    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
}
}

</script>
<body style="margin:0px; padding:0px;" onload="initialize()">
<div id="map_canvas" style="width:100%; height:90%"></div>
</body>

编辑:这是我试图让它在相关部分暂停/等待,但它没有做任何事情:

function codeAddress(vPostCode) {
    if (geocoder) {
    while (wait) { /* Just wait. */ };
      geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map.setCenter(results[0].geometry.location);
          var marker = new google.maps.Marker({
              map: map, 
              position: results[0].geometry.location
          });
        /* When geocoding "fails", see if it was because of over quota error: */
        } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { 
        wait = true;
        setTimeout("wait = true", 2000);
        //alert("OQL: " + status);
        } else {
          alert("Geocode was not successful for the following reason: " + status);
        }
      });
    }
  }
4

6 回答 6

43

Mike Williams 的教程中没有出现类似这两行的内容:

    wait = true;
    setTimeout("wait = true", 2000);

这是一个版本 3 的端口:

http://acleach.me.uk/gmaps/v3/plotaddresses.htm

相关的代码是

  // ====== Geocoding ======
  function getAddress(search, next) {
    geo.geocode({address:search}, function (results,status)
      { 
        // If that was successful
        if (status == google.maps.GeocoderStatus.OK) {
          // Lets assume that the first marker is the one we want
          var p = results[0].geometry.location;
          var lat=p.lat();
          var lng=p.lng();
          // Output the data
            var msg = 'address="' + search + '" lat=' +lat+ ' lng=' +lng+ '(delay='+delay+'ms)<br>';
            document.getElementById("messages").innerHTML += msg;
          // Create a marker
          createMarker(search,lat,lng);
        }
        // ====== Decode the error status ======
        else {
          // === if we were sending the requests to fast, try this one again and increase the delay
          if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
            nextAddress--;
            delay++;
          } else {
            var reason="Code "+status;
            var msg = 'address="' + search + '" error=' +reason+ '(delay='+delay+'ms)<br>';
            document.getElementById("messages").innerHTML += msg;
          }   
        }
        next();
      }
    );
  }
于 2012-08-06T09:01:09.350 回答
9

这个问题的一般答案是:

不要在每次加载页面时对已知位置进行地理编码。对它们进行离线地理编码并使用生成的坐标在您的页面上显示标记。

限制的存在是有原因的。

如果您无法离线对位置进行地理编码,请参阅Mike Williams 的 v2 教程中的此页面(第 17 部分地理编码多个地址),该教程描述了一种方法,将其移植到 v3 API。

于 2012-08-03T09:55:04.970 回答
4

在这里,我加载了 2200 个标记。添加 2200 个位置大约需要 1 分钟。 https://jsfiddle.net/suchg/qm1pqunz/11/

//function to get random element from an array
    (function($) {
        $.rand = function(arg) {
            if ($.isArray(arg)) {
                return arg[$.rand(arg.length)];
            } else if (typeof arg === "number") {
                return Math.floor(Math.random() * arg);
            } else {
                return 4;  // chosen by fair dice roll
            }
        };
    })(jQuery);

//start code on document ready
$(document).ready(function () {
    var map;
    var elevator;
    var myOptions = {
        zoom: 0,
        center: new google.maps.LatLng(35.392738, -100.019531), 
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map($('#map_canvas')[0], myOptions);

    //get place from inputfile.js
    var placesObject = place;
    errorArray = [];

  //will fire 20 ajax request at a time and other will keep in queue
    var queuCounter = 0, setLimit = 20; 

  //keep count of added markers and update at top
  totalAddedMarkers = 0;

  //make an array of geocode keys to avoid the overlimit error
    var geoCodKeys = [
                    'AIzaSyCF82XXUtT0vzMTcEPpTXvKQPr1keMNr_4',
                    'AIzaSyAYPw6oFHktAMhQqp34PptnkDEdmXwC3s0',
                    'AIzaSyAwd0OLvubYtKkEWwMe4Fe0DQpauX0pzlk',
                    'AIzaSyDF3F09RkYcibDuTFaINrWFBOG7ilCsVL0',
                    'AIzaSyC1dyD2kzPmZPmM4-oGYnIH_0x--0hVSY8'                   
                ];

  //funciton to add marker
    var addMarkers = function(address, queKey){
        var key = jQuery.rand(geoCodKeys);
        var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false';

        var qyName = '';
        if( queKey ) {
            qyName = queKey;
        } else {
            qyName = 'MyQueue'+queuCounter;
        }

        $.ajaxq (qyName, {
            url: url,
            dataType: 'json'
        }).done(function( data ) {
                    var address = getParameterByName('address', this.url);
                    var index = errorArray.indexOf(address);
                    try{
                        var p = data.results[0].geometry.location;
                        var latlng = new google.maps.LatLng(p.lat, p.lng);
                        new google.maps.Marker({
                            position: latlng,
                            map: map
                        });
                        totalAddedMarkers ++;

            //update adde marker count
                        $("#totalAddedMarker").text(totalAddedMarkers);
                        if (index > -1) {
                            errorArray.splice(index, 1);
                        }
                    }catch(e){
                        if(data.status = 'ZERO_RESULTS')
                            return false;

            //on error call add marker function for same address
            //and keep in Error ajax queue
                        addMarkers( address, 'Errror' );
                        if (index == -1) {
                            errorArray.push( address );
                        }
                    }
        });

    //mentain ajax queue set
        queuCounter++;
        if( queuCounter == setLimit ){
            queuCounter = 0;
        }
    }

  //function get url parameter from url string
    getParameterByName = function ( name,href )
    {
      name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
      var regexS = "[\\?&]"+name+"=([^&#]*)";
      var regex = new RegExp( regexS );
      var results = regex.exec( href );
      if( results == null )
        return "";
      else
        return decodeURIComponent(results[1].replace(/\+/g, " "));
    }

  //call add marker function for each address mention in inputfile.js
    for (var x = 0; x < placesObject.length; x++) {
        var address = placesObject[x]['City'] + ', ' + placesObject[x]['State'];
        addMarkers(address);
    }
});
于 2016-11-06T11:16:48.503 回答
3

使用“setInterval”和“clearInterval”解决了这个问题:

function drawMarkers(map, markers) {
    var _this = this,
        geocoder = new google.maps.Geocoder(),
        geocode_filetrs;

    _this.key = 0;

    _this.interval = setInterval(function() {
        _this.markerData = markers[_this.key];

        geocoder.geocode({ address: _this.markerData.address }, yourCallback(_this.markerData));

        _this.key++;

        if ( ! markers[_this.key]) {
            clearInterval(_this.interval);
        }

    }, 300);
}
于 2015-03-25T10:20:45.440 回答
1

这篇文章是不久前发布的,但它提供的答案并没有解决我在迭代中达到请求限制的问题,所以我发布了这篇文章,以帮助其他没有服务的人。

我的环境发生在 Ionic 3 中。

我没有在迭代中进行“暂停”,而是产生了使用 a 进行迭代的想法timer,这个计时器具有执行将在迭代中进行的代码的特殊性,但会每隔一段时间运行一次,直到达到最大值我们要迭代的“数组”的计数。

换句话说,我们会在一定时间内查询 Google API,使其不超过允许的毫秒数限制。

// Code to start the timer
    this.count= 0;
    let loading = this.loadingCtrl.create({
      content: 'Buscando los mejores servicios...'
    });
    loading.present();
    this.interval = setInterval(() => this.getDistancias(loading), 40);
// Function that runs the timer, that is, query Google API
  getDistancias(loading){
    if(this.count>= this.datos.length){
      clearInterval(this.interval);
    } else {
      var sucursal = this.datos[this.count];
      this.calcularDistancia(this.posicion, new LatLng(parseFloat(sucursal.position.latitude),parseFloat(sucursal.position.longitude)),sucursal.codigo).then(distancia => {
    }).catch(error => {
      console.log('error');
      console.log(error);
    });
    }
    this.count += 1;
  }
  calcularDistancia(miPosicion, markerPosicion, codigo){
    return new Promise(async (resolve,reject) => {
      var service = new google.maps.DistanceMatrixService;
      var distance;
      var duration;
      service.getDistanceMatrix({
        origins: [miPosicion, 'salida'],
        destinations: [markerPosicion, 'llegada'],
        travelMode: 'DRIVING',
        unitSystem: google.maps.UnitSystem.METRIC,
        avoidHighways: false,
        avoidTolls: false
      }, function(response, status){
        if (status == 'OK') {
          var originList = response.originAddresses;
          var destinationList = response.destinationAddresses;
          try{
            if(response != null && response != undefined){
              distance = response.rows[0].elements[0].distance.value;
              duration = response.rows[0].elements[0].duration.text;
              resolve(distance);
            }
          }catch(error){
            console.log("ERROR GOOGLE");
            console.log(status);
          }
        }
      });
    });
  }

我希望这有帮助!

对不起我的英语,我希望这不是一个不便,我不得不使用谷歌翻译。

问候,莱安德罗。

于 2019-08-03T13:32:52.773 回答
0

你使用setTimeout错误的方式。(之一)函数签名是setTimeout(callback, delay). 所以你可以很容易地指定在什么延迟之后应该运行什么代码。

var codeAddress = (function() {
    var index = 0;
    var delay = 100;

    function GeocodeCallback(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            map.setCenter(results[0].geometry.location);
            new google.maps.Marker({ map: map, position: results[0].geometry.location, animation: google.maps.Animation.DROP });
            console.log(results);
        }
        else alert("Geocode was not successful for the following reason: " + status);
    };

    return function(vPostCode) {
        if (geocoder) setTimeout(geocoder.geocode.bind(geocoder, { 'address': "'" + vPostCode + "'"}, GeocodeCallback), index*delay);
        index++;
    };
})();

这样,每次codeAddress()调用都会在geocoder.geocode()上一次调用后 100 毫秒后被调用。

我还为标记添加了动画,因此您将获得一个很好的动画效果,标记被添加到一个又一个地图中。我不确定当前的 google 限制是多少,因此您可能需要增加delay变量的值。

此外,如果您每次对相同的地址进行地理编码,您应该将地理编码的结果保存到您的数据库中,下次只需使用这些(这样您将节省一些流量并且您的应用程序会更快一点)

于 2016-09-20T08:57:41.240 回答