在谷歌地图V3中,只允许在特定国家/地区内拖动标记


Allow a marker to be dragged only inside a particular country in Google Maps V3

我要做的事情:

  1. 只允许在一个国家上空移动的可拖动标记。

  2. 拖动结束后,位置显示在输入文本中。

信息:将标记锁定在一个国家有效,但并不完美,当我多次快速移动标记时,甚至在允许的国家。它回到了它的立场,这种情况应该发生在其他国家之上。

两个必需的东西的每一部分都是单独工作的,当它们组合在一起作为下面的代码时,它们就不起作用了。问题一定出在(dragend)监听器上,但我找不到它是什么。

<script src="http://maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false"></script>
<script>

var map = null;
var marker = null;
var country = 'DE';  
function updateMarkerAddress(str) {
  document.getElementById('address').value = str;
}    
function initialize() {
  var startDragPosition = null;
  var mapOptions = {
    zoom: 6,
    center: new google.maps.LatLng(50.8,10.3),
    mapTypeId: google.maps.MapTypeId.TERRAIN
  };
  map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
  marker = new google.maps.Marker({
    position: new google.maps.LatLng(48.784084,9.181635),
    map: map,
    draggable: true
  });
  var myGeocoder = new google.maps.Geocoder();

  google.maps.event.addListener(marker,'dragstart',function(event) {
    startDragPosition = marker.getPosition();
  });
  google.maps.event.addListener(marker,'dragend',function(event) {
    myGeocoder.geocode({'latLng': marker.getPosition()}, function(responses,results, status) {
      if (status == google.maps.GeocoderStatus.OK && results[1]) {
        var countryMarker = addresComponent('country', results[1], true);
        if (country != countryMarker) {
          marker.setPosition(startDragPosition);
        }
       }
      else {
        marker.setPosition(startDragPosition);
      }
       if (responses && responses.length > 0) 
        {
          updateMarkerAddress(responses[0].formatted_address);
        } 
        else 
       {
          updateMarkerAddress('Cannot determine address at this location.');
       }
    });
  });
}
function addresComponent(type, geocodeResponse, shortName) {
  for(var i=0; i < geocodeResponse.address_components.length; i++) {
    for (var j=0; j < geocodeResponse.address_components[i].types.length; j++) {
      if (geocodeResponse.address_components[i].types[j] == type) {
        if (shortName) {
          return geocodeResponse.address_components[i].short_name;
        }
        else {
          return geocodeResponse.address_components[i].long_name;
        }
      }
    }
  }
  return '';
}
</script>
<style>
#map-canvas {
  height:400px;
}
</style>
<input type="text" id="address">

一般的问题是myGeocoder.geocode()的回调。该函数只返回两个变量-响应和状态。因此,下面的代码应该可以工作。

google.maps.event.addListener(marker,'dragend',function(event) {
    myGeocoder.geocode({'latLng': marker.getPosition()}, function(responses,status) {
        if (status == google.maps.GeocoderStatus.OK && responses[0]) {
            var countryMarker = addresComponent('country', responses[0], true);
            if (country != countryMarker) {
                marker.setPosition(startDragPosition);
            }
        } else {
            marker.setPosition(startDragPosition);
        }
        if (responses && responses.length > 0) {
            updateMarkerAddress(responses[0].formatted_address);
        } else {
            updateMarkerAddress('Cannot determine address at this location.');
        }
    });
});

快速多次移动标记可能会破坏代码,原因有两个。

  1. geocode()函数是异步的,因此如果您创建在短时间间隔内连续回调,完成顺序可以不同于创建顺序
  2. 谷歌地理编码器有一个速率限度如果查询过多,速度过快,它将停止工作

这两个问题都可以通过将代码重新构造成这样来解决。(注意:这部分代码使用jquery,所以您可能也必须包含它。)

//wrap the geocoder in a function.
function geocode (marker,country) {
    myGeocoder.geocode('query', function(){ ... } ); 
}
// call the geocoder with a timeout and clear the timeout everytime the geocoder is called again.
google.maps.event.addListener(marker,'dragend',function(event) {
    clearTimeout($.data(marker,'timer'));
    $(marker).data('timer', setTimeout(function(){geocode(marker,country)}, 1000));
});

上述方法将确保,无论您移动标记的速度有多快,地理编码功能都只能在它们之间的最小间隙(在上述情况下为1000ms)下触发。