jquery-locationpicker
Version:
This plug-in allows to easily find and select a location on the Google map. Along with a single point selection, it allows to choose an area by providing its center and the radius. All the data can be saved to any HTML input element automatically as well
357 lines (345 loc) • 15.6 kB
JavaScript
(function ( $ ) {
/**
* Holds google map object and related utility entities.
* @constructor
*/
function GMapContext(domElement, options) {
var _map = new google.maps.Map(domElement, options);
var _marker = new google.maps.Marker({
position: new google.maps.LatLng(54.19335, -3.92695),
map: _map,
title: "Drag Me",
draggable: options.draggable
});
return {
map: _map,
marker: _marker,
circle: null,
location: _marker.position,
radius: options.radius,
locationName: options.locationName,
addressComponents: {
formatted_address: null,
addressLine1: null,
addressLine2: null,
streetName: null,
streetNumber: null,
city: null,
district: null,
state: null,
stateOrProvince: null
},
settings: options.settings,
domContainer: domElement,
geodecoder: new google.maps.Geocoder()
}
}
// Utility functions for Google Map Manipulations
var GmUtility = {
/**
* Draw a circle over the the map. Returns circle object.
* Also writes new circle object in gmapContext.
*
* @param center - LatLng of the center of the circle
* @param radius - radius in meters
* @param gmapContext - context
* @param options
*/
drawCircle: function(gmapContext, center, radius, options) {
if (gmapContext.circle != null) {
gmapContext.circle.setMap(null);
}
if (radius > 0) {
radius *= 1;
options = $.extend({
strokeColor: "#0000FF",
strokeOpacity: 0.35,
strokeWeight: 2,
fillColor: "#0000FF",
fillOpacity: 0.20
}, options);
options.map = gmapContext.map;
options.radius = radius;
options.center = center;
gmapContext.circle = new google.maps.Circle(options);
return gmapContext.circle;
}
return null;
},
/**
*
* @param gMapContext
* @param location
* @param callback
*/
setPosition: function(gMapContext, location, callback) {
gMapContext.location = location;
gMapContext.marker.setPosition(location);
gMapContext.map.panTo(location);
this.drawCircle(gMapContext, location, gMapContext.radius, {});
if (gMapContext.settings.enableReverseGeocode) {
gMapContext.geodecoder.geocode({latLng: gMapContext.location}, function(results, status){
if (status == google.maps.GeocoderStatus.OK && results.length > 0){
gMapContext.locationName = results[0].formatted_address;
gMapContext.addressComponents =
GmUtility.address_component_from_google_geocode(results[0].address_components);
}
if (callback) {
callback.call(this, gMapContext);
}
});
} else {
if (callback) {
callback.call(this, gMapContext);
}
}
},
locationFromLatLng: function(lnlg) {
return {latitude: lnlg.lat(), longitude: lnlg.lng()}
},
address_component_from_google_geocode: function(address_components) {
var result = {};
for (var i = address_components.length-1; i>=0; i--) {
var component = address_components[i];
// Postal code
if (component.types.indexOf('postal_code') >= 0) {
result.postalCode = component.short_name;
}
// Street number
else if (component.types.indexOf('street_number') >= 0) {
result.streetNumber = component.short_name;
}
// Street name
else if (component.types.indexOf('route') >= 0) {
result.streetName = component.short_name;
}
// City
else if (component.types.indexOf('locality') >= 0) {
result.city = component.short_name;
}
// District
else if (component.types.indexOf('sublocality') >= 0) {
result.district = component.short_name;
}
// State \ Province
else if (component.types.indexOf('administrative_area_level_1') >= 0) {
result.stateOrProvince = component.short_name;
}
// State \ Province
else if (component.types.indexOf('country') >= 0) {
result.country = component.short_name;
}
}
result.addressLine1 = [result.streetNumber, result.streetName].join(' ').trim();
result.addressLine2 = '';
return result;
}
};
function isPluginApplied(domObj) {
return getContextForElement(domObj) != undefined;
}
function getContextForElement(domObj) {
return $(domObj).data("locationpicker");
}
function updateInputValues(inputBinding, gmapContext){
if (!inputBinding) return;
var currentLocation = GmUtility.locationFromLatLng(gmapContext.location);
if (inputBinding.latitudeInput) {
inputBinding.latitudeInput.val(currentLocation.latitude).change();
}
if (inputBinding.longitudeInput) {
inputBinding.longitudeInput.val(currentLocation.longitude).change();
}
if (inputBinding.radiusInput) {
inputBinding.radiusInput.val(gmapContext.radius).change();
}
if (inputBinding.locationNameInput) {
inputBinding.locationNameInput.val(gmapContext.locationName).change();
}
}
function setupInputListenersInput(inputBinding, gmapContext) {
if (inputBinding) {
if (inputBinding.radiusInput){
inputBinding.radiusInput.on("change", function(e) {
if (!e.originalEvent) { return }
gmapContext.radius = $(this).val();
GmUtility.setPosition(gmapContext, gmapContext.location, function(context){
context.settings.onchanged.apply(gmapContext.domContainer,
[GmUtility.locationFromLatLng(context.location), context.radius, false]);
});
});
}
if (inputBinding.locationNameInput && gmapContext.settings.enableAutocomplete) {
gmapContext.autocomplete = new google.maps.places.Autocomplete(inputBinding.locationNameInput.get(0));
google.maps.event.addListener(gmapContext.autocomplete, 'place_changed', function() {
var place = gmapContext.autocomplete.getPlace();
if (!place.geometry) {
gmapContext.settings.onlocationnotfound(place.name);
return;
}
GmUtility.setPosition(gmapContext, place.geometry.location, function(context) {
updateInputValues(inputBinding, context);
context.settings.onchanged.apply(gmapContext.domContainer,
[GmUtility.locationFromLatLng(context.location), context.radius, false]);
});
});
}
if (inputBinding.latitudeInput) {
inputBinding.latitudeInput.on("change", function(e) {
if (!e.originalEvent) { return }
GmUtility.setPosition(gmapContext, new google.maps.LatLng($(this).val(), gmapContext.location.lng()), function(context){
context.settings.onchanged.apply(gmapContext.domContainer,
[GmUtility.locationFromLatLng(context.location), context.radius, false]);
});
});
}
if (inputBinding.longitudeInput) {
inputBinding.longitudeInput.on("change", function(e) {
if (!e.originalEvent) { return }
GmUtility.setPosition(gmapContext, new google.maps.LatLng(gmapContext.location.lat(), $(this).val()), function(context){
context.settings.onchanged.apply(gmapContext.domContainer,
[GmUtility.locationFromLatLng(context.location), context.radius, false]);
});
});
}
}
}
function autosize(gmapContext) {
google.maps.event.trigger(gmapContext.map, 'resize');
setTimeout(function() {
gmapContext.map.setCenter(gmapContext.marker.position);
}, 300);
}
/**
* Initialization:
* $("#myMap").locationpicker(options);
* @param options
* @param params
* @returns {*}
*/
$.fn.locationpicker = function( options, params ) {
if (typeof options == 'string') { // Command provided
var _targetDomElement = this.get(0);
// Plug-in is not applied - nothing to do.
if (!isPluginApplied(_targetDomElement)) return;
var gmapContext = getContextForElement(_targetDomElement);
switch (options) {
case "location":
if (params == undefined) { // Getter
var location = GmUtility.locationFromLatLng(gmapContext.location);
location.radius = gmapContext.radius;
location.name = gmapContext.locationName;
return location;
} else { // Setter
if (params.radius) {
gmapContext.radius = params.radius;
}
GmUtility.setPosition(gmapContext, new google.maps.LatLng(params.latitude, params.longitude), function(gmapContext) {
updateInputValues(gmapContext.settings.inputBinding, gmapContext);
});
}
break;
case "subscribe":
/**
* Provides interface for subscribing for GoogleMap events.
* See Google API documentation for details.
* Parameters:
* - event: string, name of the event
* - callback: function, callback function to be invoked
*/
if (params == undefined) { // Getter is not available
return null;
} else {
var event = params.event;
var callback = params.callback;
if (!event || ! callback) {
console.error("LocationPicker: Invalid arguments for method \"subscribe\"")
return null;
}
google.maps.event.addListener(gmapContext.map, event, callback);
}
break;
case "map":
/**
* Returns object which allows access actual google widget and marker paced on it.
* Structure: {
* map: Instance of the google map widget
* marker: marker placed on map
* }
*/
if (params == undefined) { // Getter
var locationObj = GmUtility.locationFromLatLng(gmapContext.location);
locationObj.formattedAddress = gmapContext.locationName;
locationObj.addressComponents = gmapContext.addressComponents;
return {
map: gmapContext.map,
marker: gmapContext.marker,
location: locationObj
}
} else { // Setter is not available
return null;
}
case "autosize":
autosize(gmapContext);
return this;
}
return null;
}
return this.each(function() {
var $target = $(this);
// If plug-in hasn't been applied before - initialize, otherwise - skip
if (isPluginApplied(this)) return;
// Plug-in initialization is required
// Defaults
var settings = $.extend({}, $.fn.locationpicker.defaults, options );
// Initialize
var gmapContext = new GMapContext(this, {
zoom: settings.zoom,
center: new google.maps.LatLng(settings.location.latitude, settings.location.longitude),
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: false,
disableDoubleClickZoom: false,
scrollwheel: settings.scrollwheel,
streetViewControl: false,
radius: settings.radius,
locationName: settings.locationName,
settings: settings,
draggable: settings.draggable
});
$target.data("locationpicker", gmapContext);
// Subscribe GMap events
google.maps.event.addListener(gmapContext.marker, "dragend", function(event) {
GmUtility.setPosition(gmapContext, gmapContext.marker.position, function(context){
var currentLocation = GmUtility.locationFromLatLng(gmapContext.location);
context.settings.onchanged.apply(gmapContext.domContainer, [currentLocation, context.radius, true]);
updateInputValues(gmapContext.settings.inputBinding, gmapContext);
});
});
GmUtility.setPosition(gmapContext, new google.maps.LatLng(settings.location.latitude, settings.location.longitude), function(context){
updateInputValues(settings.inputBinding, gmapContext);
// Set up input bindings if needed
setupInputListenersInput(settings.inputBinding, gmapContext);
context.settings.oninitialized($target);
});
});
};
$.fn.locationpicker.defaults = {
location: {latitude: 40.7324319, longitude: -73.82480799999996},
locationName: "",
radius: 500,
zoom: 15,
scrollwheel: true,
inputBinding: {
latitudeInput: null,
longitudeInput: null,
radiusInput: null,
locationNameInput: null
},
enableAutocomplete: false,
enableReverseGeocode: true,
draggable: true,
onchanged: function(currentLocation, radius, isMarkerDropped) {},
onlocationnotfound: function(locationName) {},
oninitialized: function (component) {}
}
}( jQuery ));