UNPKG

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