Resize MVC Radius

706 views
Skip to first unread message

finco

unread,
Oct 17, 2011, 11:41:51 PM10/17/11
to google-map...@googlegroups.com
I've built a map where a circle can be resized by dragging the edge.  It is based on Luke Mahe's example at http://code.google.com/apis/maps/articles/mvcfun.html.  I'd like to add an input field which will resize the circle based on the value of the input.  I can do this by calling the init() function again but there must be a way to just resize the circle without reloading the map.  I thought it was going to be RadiusWidget.prototype.set('distance',the_input_value) but no success with that.

Can someone please point me in the right direction?  Thanks in advance for your help.

Martin™

unread,
Oct 18, 2011, 2:43:55 AM10/18/11
to Google Maps JavaScript API v3
Hi.

Try:

myRadiusWidget.set('distance', the_input_value)

Where myRadiusWidget is the instance of RadiusWidget that you have
created - and kept a reference to.

Martin.


On Oct 18, 4:41 am, finco <mbeck...@gmail.com> wrote:
> I've built a map where a circle can be resized by dragging the edge.  It is
> based on Luke Mahe's example athttp://code.google.com/apis/maps/articles/mvcfun.html.  I'd like to add an

finco

unread,
Oct 18, 2011, 7:40:08 AM10/18/11
to google-map...@googlegroups.com
within the keyup of my input I've added:
var myRadiusWidget=RadiusWidget();
myRadiusWidget.set('distance',8000);

I think the issue may be a scope issue. 

I can set a new radius with 
var distanceWidget = new DistanceWidget(map1);
so if I can delete the prior circle (how?), I can just create a new one.  

I think the fundamental issue is I don't know how to address the existing circle.

Thanks again.

My code  is as follows:

       * 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,
          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({
 strokeColor: "#FF0000",
 strokeOpacity: 0.8,
 strokeWeight: 2,
 fillColor: "#FF0000",
 fillOpacity: 0.05
        });

        // Set the distance property value, default to 3 mi (*km).
        this.set('distance', radiusSlider*1.609344);

        // 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!',
 icon: 'handle.png'
        });

        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 points in km.
       *
       * @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 init(targetDiv,lat,lon) {       
     var zoomLevel;
 if (bMapLoaded) 
{zoomLevel = map1.getZoom();}
 else
{zoomLevel = 12;}
 var mapDiv = document.getElementById(targetDiv);
          map1 = new google.maps.Map(mapDiv, {
            center: new google.maps.LatLng(lat,lon),
            zoom: zoomLevel,
            mapTypeId: google.maps.MapTypeId.ROADMAP
          });
        
     var distanceWidget = new DistanceWidget(map1);

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

      

      function displayInfo(widget) {
        $('#radius').val((widget.get('distance')/1.609344).toFixed(2));
      }

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

    }

Rossko

unread,
Oct 18, 2011, 7:45:58 AM10/18/11
to Google Maps JavaScript API v3
> I think the fundamental issue is I don't know how to address the existing
> circle.

Yes, I would focus on that as a scope problem. Do some homework on
javascript variable scope, example
http://econym.org.uk/gmap/scope.htm
If you want only one circle, and want to mess with at later times, a
global variable looks like a simple solution.

finco

unread,
Oct 18, 2011, 8:04:24 AM10/18/11
to google-map...@googlegroups.com
I've actually been looking at it for hours but can't seem to figure out how to declare the widgets so they are public.  I don't mean to be the slow kid in the class . . . . . but perhaps I am.   Thanks for any suggestions.

Rossko

unread,
Oct 18, 2011, 12:31:35 PM10/18/11
to Google Maps JavaScript API v3
> I've actually been looking at it for hours but can't seem to figure out how
> to declare the widgets so they are public.

function myFunction() {
var bananas = new Thingamajig(bleh);
}

You won't be able to access 'bananas' after myFunction has completed,
it is local in scope.

var bananas;
function myFunction() {
bananas = new Thingamajig(bleh);
}

An 'empty' varaible is declared in the global scope. When the
function runs, it re-uses that global variable. After the function
has finished, other functions will still be able to get at 'bananas'

You'd probably enhance the code in your case; perhaps you'd use the
same function to either create a new circle or to amend it, by testing
to see if the global is null or already a circle.

Its all standard javascript behaviour, there is nothing maps specific
here.

finco

unread,
Oct 18, 2011, 1:15:33 PM10/18/11
to google-map...@googlegroups.com
So at the end of the day, I ended up destroying the original circle (not either of the widgets which is where I had been looking) and created a new one.

so var circle;

within my keyup event

circle.setMap();  //destroy existing circle
var distanceWidget = new DistanceWidget(map1);  //create a new circle

Thanks Martin and Rossko.  I appreciate the help.
Reply all
Reply to author
Forward
0 new messages