【问题标题】:Google Maps JS API - draw resizable circle with a static centerGoogle Maps JS API - 用静态中心绘制可调整大小的圆圈
【发布时间】:2016-05-20 04:43:53
【问题描述】:

我需要从给定的静态点在谷歌地图上画一个圆圈。我尝试通过如下设置圆设置center 来完成此操作,center: new google.maps.LatLng(-34.397, 150.644) 在使用DrawingManager 绘制后。

但这里的问题是圆圈从鼠标单击位置开始绘制,一旦完成,圆圈就会捕捉到给定的latlng,就像小提琴中的演示一样:http://jsfiddle.net/hjkety80/1/

我需要的是,无论我在哪里单击圆圈,都应该从给定的静态点开始绘制。如果描述含糊不清,我深表歉意,如果需要,我很乐意澄清更多。非常感谢您对此问题的任何帮助/参考。

谢谢

编辑

如果可能的话,即使圆心绑定到标记也是一个很好的解决方法

【问题讨论】:

  • 如果你想要一个固定的圆圈,你为什么要使用绘图工具?
  • 我希望用户能够绘制圆圈..但只能在地图上的标记周围..这是为了让应用程序指定商店的交付范围,因此圆圈中心位于标记:)
  • 您可以使用my answer to the question: How to style editable circle controls in Google Maps 中的DistanceWidget,但不要使圆的中心标记可拖动。

标签: javascript google-maps google-maps-api-3


【解决方案1】:

我为您创建了一个工作示例。它没有使用DrawingManager,因为它不适合您想要实现的目标,而是以编程方式更新圆的半径。

所以在这个例子中,当加载地图时,用户会看到一个指针光标,当他按下鼠标按钮时,他将开始在你的static_position 和新的radius 中绘制一个圆心circle 是根据他单击的位置确定的。

该示例包括几何库(在获取 Google 地图 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>

【讨论】:

  • 这是一个很好的解决方案,解决了我一直在寻找的问题 :) 非常感谢
【解决方案2】:

一个选项(来自我对这个问题的回答:How to style editable circle controls in Google Maps)。带有固定中心标记的 DistanceWidget。

相关问题:

代码 sn-p:

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>

【讨论】:

  • 这个答案非常有帮助,并且作为我遇到的问题的初步解决方法来找我。非常感谢
  • 因为@Matej P 的回答解决了我的问题,所以我将其标记为答案,但是 +1 因为你的回答也会帮助我
猜你喜欢
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-02
  • 2013-12-21
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
相关资源
最近更新 更多