Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Maps v3 setting a circle with editable radius but not center

Tags:

google-maps

I have managed to put a circle on a map and make it editable:

var circle = new google.maps.Circle({
          map: map,
          radius: 1609.344, // 1 mile
          editable: true,
          fillOpacity: 0.25
        });


circle.bindTo('center', marker, 'position');

However, this makes both the radius, and center editable. I only want the radius to be editable. I can't see a way to have that level of control via google.maps.Circle.

What I am after, is pretty much what is here:

http://www.freemaptools.com/radius-around-point.htm

However I can't see how it is done as their code looks obfuscated.

like image 889
Newmania Avatar asked Aug 10 '12 08:08

Newmania


People also ask

Can you add a radius circle on Google Maps?

Click on the map and create a popup marker to select the point. From there, opt for the “Draw Radius.” Choose the proximity distance from the given address found within the radius options in the software. Once settings are entered, a map will show the highlighted parameters on the map.


2 Answers

You can try listening for the center_changed event and when it fires reposition the center, for example:

Global variables:

    var centerPoint = new G.LatLng(45.5, -100.5);
    var ignore = false;
    var poly;
//position the map where the circle is so we can see it.
    map.setCenter(centerPoint);
    map.setZoom(11);

and then:

poly = new google.maps.Circle({
    map: map,
    center:centerPoint,
    radius: 1609.344, // 1 mile
    editable: true,
    fillOpacity: 0.25
});

G.event.addListener(poly,'center_changed',function(){
    if (ignore){
        ignore = false;
        return;
    }
    poly.setEditable(false);
    ignore = true;
    poly.setCenter(centerPoint);
    poly.setEditable(true);
});

The only problem is that the center marker may be misleading to the user.

like image 120
Marcelo Avatar answered Nov 01 '22 03:11

Marcelo


See this article from the documentation (before editable objects). If you take the step 6 and don't make the center marker draggable, I think it is what you want.

fiddle containing original code from link

code snippet:

/**
 * 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 to attach to.
 *
 * @constructor
 */
function DistanceWidget(map) {
  this.set('map', map);
  this.set('position', map.getCenter());

  var marker = new google.maps.Marker({
    // draggable: true,  // <-- change to make so position doesn't move
    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 10km.
  this.set('distance', 10);

  // 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);

  // Add the sizer marker
  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,
    title: 'Drag me!'
  });

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

  var me = this;
  google.maps.event.addListener(sizer, 'drag', 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 min = 0.5;
    var max = 15;
    var pos = me.get('sizer_position');
    var center = me.get('center');
    var distance = google.maps.geometry.spherical.computeDistanceBetween(center, pos) / 1000;
    if (distance < min) {
      me.set('sizer_position', google.maps.geometry.spherical.computeOffset(center, min * 1000, google.maps.geometry.spherical.computeHeading(center, pos)));
    } else if (distance > max) {
      me.set('sizer_position', google.maps.geometry.spherical.computeOffset(center, max * 1000, google.maps.geometry.spherical.computeHeading(center, pos)));
    }
    // 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);
  }
};


/**
 * 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 = google.maps.geometry.spherical.computeDistanceBetween(center, pos) / 1000;

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


function init() {
  var mapDiv = document.getElementById('map-canvas');
  var map = new google.maps.Map(mapDiv, {
    center: new google.maps.LatLng(37.790234970864, -122.39031314844),
    zoom: 11,
    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);
  });
}

function displayInfo(widget) {
  var info = document.getElementById('info');
  info.innerHTML = 'Position: ' + widget.get('position') + ', distance: ' +
    widget.get('distance');
}

google.maps.event.addDomListener(window, 'load', init);
#map-canvas {
  height: 500px;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="info"></div>
<div id="map-canvas"></div>

original article (link now dead)

like image 43
geocodezip Avatar answered Nov 01 '22 02:11

geocodezip