Google地图JS API - 绘制具有静态中心的可调整大小圆形

6
我有一个需求,需要在给定的静态点上绘制一个圆形地图。我尝试通过设置圆形设置center来实现这一点,如下所示:center: new google.maps.LatLng(-34.397, 150.644),在使用DrawingManager绘制之后。
但是问题在于,圆圈始于鼠标点击位置,完成后圆圈会以给定的latlng为中心捕捉,如fiddle演示所示:http://jsfiddle.net/hjkety80/1/ 我需要的是,无论我在哪里点击,圆圈都应该从给定的静态点开始绘制。如果描述不清楚,我很抱歉,并乐意在需要时进行澄清。任何关于此事的帮助/参考都将不胜感激。
谢谢
编辑
即使圆形中心绑定到标记也可以是一个好的解决方法,如果可能的话。

如果你想要一个固定的圆,为什么要使用绘图工具呢? - geocodezip
我希望用户能够在地图上的标记周围绘制圆圈。这是为了应用程序指定商店的交付范围,因此圆圈中心位于标记上 :) - Hasitha Shan
你可以使用我在如何在Google地图中样式化可编辑圆形控件的问题中的答案中提到的DistanceWidget,但不要使圆形的中心标记可拖动。 - geocodezip
2个回答

10

我为您创建了一个可工作的示例。它没有使用DrawingManager,因为它不适合您想要实现的内容,而是通过编程更新圆的半径。

因此,在这个示例中,加载地图后,用户会看到一个指针光标,当他按下鼠标按钮时,他将开始在以您的static_position为中心画一个圆,新circleradius基于他单击的位置确定。

该示例包括几何库(注意在获取Google Maps API时的&libraries=geometry),并利用其google.maps.geometry.spherical.computeDistanceBetween()函数计算您的中心与用户刚刚点击的位置之间的距离(以米为单位)以获得半径。如果用户不立即释放按钮,而是移动鼠标,圆将根据用户光标的移动自动调整其半径。用户释放鼠标后,可以拖动地图,并且圆仍然可编辑以进行调整。

示例(只需在地图上按左键开始绘制即可。为了获得更好的体验,请在full page模式下运行):

var map = null;

function initialize(){
 
  var static_position = new google.maps.LatLng(-34.397, 150.644);
  var the_circle = null;
 
  map = new google.maps.Map(document.getElementById('map-canvas'), {
      center: static_position,
      zoom: 8,
      draggable: false,
      draggableCursor:'pointer'
  });
  
  var mousemove_handler;
  
  google.maps.event.addListener(map, 'mouseup', function(e) {            
      if(mousemove_handler) google.maps.event.removeListener(mousemove_handler);
      map.setOptions({draggable:true, draggableCursor:''}); //allow map dragging after the circle was already created 
      the_circle.setOptions({clickable:true});
  });
  
  google.maps.event.addListenerOnce(map, 'mousedown', function (mousedown_event) {
   var radius = google.maps.geometry.spherical.computeDistanceBetween(static_position, mousedown_event.latLng); //get distance in meters between our static position and clicked position, which is the radius of the circle
   the_circle = createCircle(static_position, radius); //create circle with center in our static position and our radius
   mousemove_handler = google.maps.event.addListener(map, 'mousemove', function(mousemove_event) { //if after mousedown user starts dragging mouse, let's update the radius of the new circle
    var new_radius = google.maps.geometry.spherical.computeDistanceBetween(static_position, mousemove_event.latLng);
    console.log(new_radius);
    the_circle.setOptions({radius:new_radius}); 
   });
  });
  
}

google.maps.event.addDomListener(window, 'load', initialize);

function createCircle(center, radius) {

    var circle = new google.maps.Circle({
        fillColor: '#ffffff',
        fillOpacity: .6,
        strokeWeight: 1,
        strokeColor: '#ff0000',
        draggable: false,
        editable: true,
        map: map,
        center: center,
        radius: radius,
        clickable:false
    });

    google.maps.event.addListener(circle, 'radius_changed', function (event) {
        console.log('circle radius changed');
    });

    google.maps.event.addListener(circle, 'center_changed', function (event) {
        if(circle.getCenter().toString() !== center.toString()) circle.setCenter(center);
    });
 
    return circle;
}
<script src="//maps.google.com/maps/api/js?sensor=false&libraries=geometry&dummy=.js"></script>
<body style="margin:0px; padding:0px;">
  <div id="map-canvas" style="height:400px; width:500px;"></div> 
</body>


这是一个非常好的解决方案,正好满足了我所需要的 :) 非常感谢。 - Hasitha Shan

1

一个选项(来自我对这个问题的回答:如何在Google Maps中为可编辑圆形控件设置样式)。带有固定中心标记的DistanceWidget。

相关问题:

代码片段:

function init() {
  var mapDiv = document.getElementById('map-canvas');
  var map = new google.maps.Map(mapDiv, {
    center: new google.maps.LatLng(-34.397, 150.644),
    zoom: 8,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  });
  var distanceWidget = new DistanceWidget(map);
  google.maps.event.addListener(distanceWidget, 'distance_changed', function() {
    displayInfo(distanceWidget);
  });

  google.maps.event.addListener(distanceWidget, 'position_changed', function() {
    displayInfo(distanceWidget);
  });
}

google.maps.event.addDomListener(window, 'load', init);

/** 
 * A distance widget that will display a circle that can be resized and will
 * provide the radius in km.
 *
 * @param {google.maps.Map} map The map on which to attach the distance widget.
 *
 * @constructor
 */
function DistanceWidget(map) {
  this.set('map', map);
  this.set('position', map.getCenter());

  var marker = new google.maps.Marker({
    draggable: false,
    icon: {
      url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle_blue.png",
      size: new google.maps.Size(7, 7),
      anchor: new google.maps.Point(4, 4)
    },
    title: 'Move me!'
  });

  // Bind the marker map property to the DistanceWidget map property 
  marker.bindTo('map', this);

  // Bind the marker position property to the DistanceWidget position 
  // property 
  marker.bindTo('position', this);

  // Create a new radius widget 
  var radiusWidget = new RadiusWidget();

  // Bind the radiusWidget map to the DistanceWidget map 
  radiusWidget.bindTo('map', this);

  // Bind the radiusWidget center to the DistanceWidget position 
  radiusWidget.bindTo('center', this, 'position');

  // Bind to the radiusWidgets' distance property 
  this.bindTo('distance', radiusWidget);

  // Bind to the radiusWidgets' bounds property 
  this.bindTo('bounds', radiusWidget);
}
DistanceWidget.prototype = new google.maps.MVCObject();

/** 
 * A radius widget that add a circle to a map and centers on a marker.
 *
 * @constructor
 */
function RadiusWidget() {
  var circle = new google.maps.Circle({
    strokeWeight: 2
  });

  // Set the distance property value, default to 50km. 
  this.set('distance', 50);

  // Bind the RadiusWidget bounds property to the circle bounds property. 
  this.bindTo('bounds', circle);

  // Bind the circle center to the RadiusWidget center property 
  circle.bindTo('center', this);

  // Bind the circle map to the RadiusWidget map 
  circle.bindTo('map', this);

  // Bind the circle radius property to the RadiusWidget radius property 
  circle.bindTo('radius', this);

  this.addSizer_();
}
RadiusWidget.prototype = new google.maps.MVCObject();


/** 
 * Update the radius when the distance has changed.
 */
RadiusWidget.prototype.distance_changed = function() {
  this.set('radius', this.get('distance') * 1000);
};
/** 
 * Add the sizer marker to the map.
 *
 * @private
 */
RadiusWidget.prototype.addSizer_ = function() {
  var sizer = new google.maps.Marker({
    draggable: true,
    icon: {
      url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle_blue.png",
      size: new google.maps.Size(7, 7),
      anchor: new google.maps.Point(4, 4)
    },
    title: 'Drag me!'
  });

  sizer.bindTo('map', this);
  sizer.bindTo('position', this, 'sizer_position');

  var me = this;
  google.maps.event.addListener(sizer, 'drag', function() {
    // Set the circle distance (radius) 
    me.setDistance();
  });
};

/** 
 * Update the center of the circle and position the sizer back on the line.
 *
 * Position is bound to the DistanceWidget so this is expected to change when
 * the position of the distance widget is changed.
 */
RadiusWidget.prototype.center_changed = function() {
  var bounds = this.get('bounds');

  // Bounds might not always be set so check that it exists first. 
  if (bounds) {
    var lng = bounds.getNorthEast().lng();

    // Put the sizer at center, right on the circle. 
    var position = new google.maps.LatLng(this.get('center').lat(), lng);
    this.set('sizer_position', position);
  }
};

/** 
 * Calculates the distance between two latlng locations in km.
 * @see http://www.movable-type.co.uk/scripts/latlong.html
 *
 * @param {google.maps.LatLng} p1 The first lat lng point.
 * @param {google.maps.LatLng} p2 The second lat lng point.
 * @return {number} The distance between the two points in km.
 * @private
 */
RadiusWidget.prototype.distanceBetweenPoints_ = function(p1, p2) {
  if (!p1 || !p2) {
    return 0;
  }

  var R = 6371; // Radius of the Earth in km 
  var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
  var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  var d = R * c;
  return d;
};


/** 
 * Set the distance of the circle based on the position of the sizer.
 */
RadiusWidget.prototype.setDistance = function() {
  // As the sizer is being dragged, its position changes.  Because the 
  // RadiusWidget's sizer_position is bound to the sizer's position, it will 
  // change as well. 
  var pos = this.get('sizer_position');
  var center = this.get('center');
  var distance = this.distanceBetweenPoints_(center, pos);

  // Set the distance property for any objects that are bound to it 
  this.set('distance', distance);
};

function displayInfo(widget) {
  var info = document.getElementById('info');
  info.innerHTML = 'Position: ' + widget.get('position').toUrlValue(3) + ', distance: ' + widget.get('distance').toFixed(3);
}
html,
body,
#map-canvas {
  height: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="info"></div>
<div id="map-canvas"></div>


这个答案非常有帮助,对我来说是解决问题的一个初步解决方法。非常感谢。 - Hasitha Shan
由于@Matej P的答案直接解决了我的问题,我将其标记为答案,但是还要+1,因为您的答案也会帮助我。 - Hasitha Shan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接