Question

your help would be much appreciated with the following. I am using the JS code below to display a Google Map with a re-sizable circle overlay to output a centre point co-ordinate, radius and bounding box:

function DistanceWidget(map) {
this.set('map', map);
this.set('position', map.getCenter());
var marker = new google.maps.Marker({
draggable: true,
title: 'Drag to set centre',
icon: 'images/mapicon3.png'
});
marker.bindTo('map', this);
marker.bindTo('position', this);
var radiusWidget = new RadiusWidget();
radiusWidget.bindTo('map', this);
radiusWidget.bindTo('center', this, 'position');
this.bindTo('distance', radiusWidget);
this.bindTo('bounds', radiusWidget);
}
DistanceWidget.prototype = new google.maps.MVCObject();
function RadiusWidget() {
var circle = new google.maps.Circle({
fillColor: '#efefef',
fillOpacity: 0.5,
strokeColor: '#000',
strokeOpacity: 1.0,
strokeWeight: 2
});
this.set('distance', 5);
this.bindTo('bounds', circle);
circle.bindTo('center', this);
circle.bindTo('map', this);
circle.bindTo('radius', this);
this.addSizer_();
}
RadiusWidget.prototype = new google.maps.MVCObject();
RadiusWidget.prototype.distance_changed = function() {
this.set('radius', this.get('distance') * 1000);
};
RadiusWidget.prototype.addSizer_ = function() {
var sizer = new google.maps.Marker({
draggable: true,
title: 'Drag to expand search area',
icon: 'images/mapicon2.png'
});
sizer.bindTo('map', this);
sizer.bindTo('position', this, 'sizer_position');
var me = this;
google.maps.event.addListener(sizer, 'drag', function() {
me.setDistance();
});
};
RadiusWidget.prototype.center_changed = function() {
var bounds = this.get('bounds');
if (bounds) {
var lng = bounds.getNorthEast().lng();
var position = new google.maps.LatLng(this.get('center').lat(), lng);
this.set('sizer_position', position);
}
};
RadiusWidget.prototype.distanceBetweenPoints_ = function(p1, p2) {
if (!p1 || !p2) {
return 0;
}
var R = 6371;
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;
};
RadiusWidget.prototype.setDistance = function() {
var pos = this.get('sizer_position');
var center = this.get('center');
var distance = this.distanceBetweenPoints_(center, pos);
var distance = Math.round(distance*100)/100
this.set('distance', distance);
};
function init() {
var mapDiv = document.getElementById('map-canvas');
var map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(geoip_latitude(), geoip_longitude()), 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);
});
mapDiv.style.width = (viewportwidth)+"px";
mapDiv.style.height = (viewportheight)+"px";
}
function displayInfo(widget) {
var info = document.getElementById('info');
info.innerHTML = '<form action="/search" method="post"><input type="hidden" name="position" value="' + widget.get('position') + '" /><input type="hidden" name="distance" value="' + widget.get('distance') + '" /><input type="hidden" name="bounds" value="' + widget.get('bounds') + '" /><input type="submit" value="Submit" /></form>';
}
google.maps.event.addDomListener(window, 'load', init);

This works great, but what I can't figure out is how to add geocoding to this, so that a place name could be entered (POSTed via a form), geocoded using Google Maps API and set as the centre point in the above script, without breaking the current functionality.

As requested, there is a jsFiddle for the above here. You will see that the user can drag the markers to output position, distance and bounds; however what I want to add is the ability to enter a location in the form, which on submit is geocoded, with the resulting co-ordinates being used to reposition the centre marker.

Any help much appreciated, thanks.

Was it helpful?

Solution

If you change your marker in DistanceWidget to be a instance variable instead, and create a setPosition() method operating on that marker I think you should be able to do what you want;

function DistanceWidget(map) {
    this.set('map', map);
    this.set('position', map.getCenter());

    this.marker = new google.maps.Marker({
        draggable: true,
        title: 'Drag to set centre',
        icon: 'images/mapicon3.png'
    });
    this.marker.bindTo('map', this);
    this.marker.bindTo('position', this);

    var radiusWidget = new RadiusWidget();
    radiusWidget.bindTo('map', this);
    radiusWidget.bindTo('center', this, 'position');
    this.bindTo('distance', radiusWidget);
    this.bindTo('bounds', radiusWidget);
}
DistanceWidget.prototype = new google.maps.MVCObject();
/* Add the `setMarkerPosition` method to this class */
DistanceWidget.prototype.setMarkerPosition = function(position) {
    this.marker.setPosition(position);
}

And your init()-function becomes;

function init() {
    var mapDiv = document.getElementById('map-canvas');
    var map = new google.maps.Map(mapDiv, {
        center: new google.maps.LatLng(geoip_latitude(), geoip_longitude()), zoom: 11,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    var distanceWidget = new DistanceWidget(map);

    /* Set up geo-functionality */
    var geo = new google.maps.Geocoder();
    geo.geocode({address: 'Piccadilly Circus, London'}, function(results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
            distanceWidget.setMarkerPosition(results[0].geometry.location);
            map.setCenter(results[0].geometry.location);
        }
    });
    ...

DISCLAIMER: This is just from the top of my head, not tested plus I've never worked with these classes.

OTHER TIPS

Here is the JSFiddle Demo: and type in zipcode (30084) to test it:

Here is the initial markup of the HTML:

    <div id="map-canvas"></div>
    <div id="info">
    </div>
    <div id='geocode'>
         <input name="q" type="text" id="q" /><br />
         <input type="submit" value="Submit" id="geosubmit" />
    </div>

Here is how you can get the Geocode information based on the input, and within the callback function of your geocode you can set the center of your DistanceWidget. The responseResult would give you lat by calling responses[0].geometry.location.lat() and lng by responses[0].geometry.location.lng():

function init() {
    var mapDiv = document.getElementById('map-canvas');
    var geocoder = new google.maps.Geocoder();
    var map = new google.maps.Map(mapDiv, {
        center: new google.maps.LatLng(51.5001524, -0.1262362),
        zoom: 11,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    var distanceWidget = new DistanceWidget(map);

    //Geocoder input section and logic
    var mySubmit = document.getElementById('geosubmit');
    var myGeoInfo = document.getElementById('q');
    mySubmit.onclick = function() {
        geocoder.geocode({
            address: myGeoInfo.value
        }, function(responses) {
            if (responses && responses.length > 0) {
                var newMarkerPos = new google.maps.LatLng(responses[0].geometry.location.lat(), responses[0].geometry.location.lng());
                distanceWidget.set('position', newMarkerPos); //sets the new position of marker
                distanceWidget.map.setCenter(newMarkerPos); //sets map's center
            } else {
                //response failed output error message
                alert('error getting geocode');
            }
        });
    }

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

    mapDiv.style.width = "500px";
    mapDiv.style.height = "300px";
}

Update. Please check the JSFiddle demo and type in zipcode (30084) to test it:

To set your current RadiusWidget and google map marker here is the modified code. You don't need to modify the prototype of your current widget to complicate things. You can just call the MVCObject's set option and access the map by using the instantiated distancewidget:

geocoder.geocode({
    address: myGeoInfo.value
}, function(responses) {
    if (responses && responses.length > 0) {
        var newMarkerPos = new google.maps.LatLng(responses[0].geometry.location.lat(), responses[0].geometry.location.lng());
        distanceWidget.set('position', newMarkerPos); //sets the new position of marker
        distanceWidget.map.setCenter(newMarkerPos); //sets map's center
    } else {
        //response failed output error message
        alert('error getting geocode');
    }
});

There is a tutorial here that shows how to get geocoding and reverse geocoding working with Google Maps v3 and Jquery

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top