commit dac77d5a7e471ec963f570753877bc6e7de60bb6 Author: s.meijer Date: Mon Dec 24 02:19:55 2012 +0100 initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..412eeda7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5ebd21a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,163 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store diff --git a/example/esri.html b/example/esri.html new file mode 100644 index 00000000..0dae3fbe --- /dev/null +++ b/example/esri.html @@ -0,0 +1,36 @@ + + + + Leaflet.GeoSearch / Esri Provider + + + + + + + + + + + + + +
+ + + + diff --git a/example/google.html b/example/google.html new file mode 100644 index 00000000..b0cc5fc1 --- /dev/null +++ b/example/google.html @@ -0,0 +1,37 @@ + + + + Leaflet.GeoSearch / Google Provider + + + + + + + + + + + + + + +
+ + + + diff --git a/example/openstreetmap.html b/example/openstreetmap.html new file mode 100644 index 00000000..0966b5a4 --- /dev/null +++ b/example/openstreetmap.html @@ -0,0 +1,37 @@ + + + + Leaflet.GeoSearch / OSM Provider + + + + + + + + + + + + + + +
+ + + + diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..0c06f3b8 --- /dev/null +++ b/readme.md @@ -0,0 +1,43 @@ +#Leaflet.GeoSearch +Adds support for address lookup (a.k.a. geocoding / geoseaching) to Leaflet. + +Check out the [demo](http://smeijer.github.com/GeoSearch/) + +#About the control +The control uses so called providers to take care of building the correct service url and parsing the retrieved data into an uniformal format. Thanks to this split-up, it is pretty easy to write your own providers, so you can use your own geocoding service(s). + +The control comes with an default set of three providers: + + - L.GeoSearch.Provider.Esri + - L.GeoSearch.Provider.Google + - L.GeoSearch.Provider.OpenStreetMap + +Using these are pretty simple. + +#Using the control + +For example, to use the Esri provider: + +```` +new L.Control.GeoSearch({ + provider: new L.GeoSearch.Provider.Esri() +}).addTo(map); +```` + +Or if you prefer using Google + +```` +new L.Control.GeoSearch({ + provider: new L.GeoSearch.Provider.Google() +}).addTo(map); +```` + +Some people are really loving open source and by that openstreetmap + +```` +new L.Control.GeoSearch({ + provider: new L.GeoSearch.Provider.OpenStreetMap() +}).addTo(map); +```` + +I really can't make it any harder. Checkout the providers to see how easy it is to write your own. \ No newline at end of file diff --git a/src/css/l.geosearch.css b/src/css/l.geosearch.css new file mode 100644 index 00000000..ac186647 --- /dev/null +++ b/src/css/l.geosearch.css @@ -0,0 +1,38 @@ +.leaflet-center { + width: 40%; + margin-left: auto; + margin-right: auto; + position: relative; +} +.leaflet-control-geosearch, .leaflet-control-geosearch ul { + border-radius: 7px; + background: none repeat scroll 0 0 rgba(0, 0, 0, 0.25); + margin: 10px 0 0 0; + padding: 5px; + width: 100%; + height: auto; +} +.leaflet-control-geosearch-msg ul { + list-style: none; + display: none; + height: auto; + background: none; + padding: 0; +} +.leaflet-control-geosearch ul li { + background: none repeat scroll 0 0 rgba(255, 255, 255, 0.75); + border-radius: 4px; + margin: 2px 0; + padding: 4px; + font: 12px arial; + text-indent: 4px; +} +.leaflet-container .leaflet-control-geosearch input { + width: 100%; + height: 28px; + padding: 0; + text-indent: 8px; + background: rgba(255, 255, 255, 0.75); + border-radius: 4px; + border: none; +} \ No newline at end of file diff --git a/src/js/l.control.geosearch.js b/src/js/l.control.geosearch.js new file mode 100644 index 00000000..c1f941f9 --- /dev/null +++ b/src/js/l.control.geosearch.js @@ -0,0 +1,126 @@ +/* + * L.Control.GeoSearch - search for an address and zoom to it's location + * https://github.com/smeijer/leaflet.control.geosearch + */ + +L.GeoSearch = {}; +L.GeoSearch.Provider = {}; + +L.GeoSearch.Result = function (x, y, label) { + this.X = x; + this.Y = y; + this.Label = label; +}; + +L.Control.GeoSearch = L.Control.extend({ + options: { + position: 'topcenter' + }, + + initialize: function (options) { + this._config = {}; + this.setConfig(options); + }, + + setConfig: function (options) { + this._config = { + 'country': options.country || '', + 'provider': options.provider, + + 'searchLabel': options.searchLabel || 'search for address...', + 'notFoundMessage' : options.notFoundMessage || 'Sorry, that address could not be found.', + 'messageHideDelay': options.messageHideDelay || 3000, + 'zoomLevel': options.zoomLevel || 18, + }; + }, + + onAdd: function (map) { + var $controlContainer = $(map._controlContainer); + + if ($controlContainer.children('.leaflet-top.leaflet-center').length == 0) { + $controlContainer.append('
'); + map._controlCorners.topcenter = $controlContainer.children('.leaflet-top.leaflet-center').first()[0]; + } + + this._map = map; + this._container = L.DomUtil.create('div', 'leaflet-control-geosearch'); + + var searchbox = document.createElement('input'); + searchbox.id = 'leaflet-control-geosearch-qry'; + searchbox.type = 'text'; + searchbox.placeholder = this._config.searchLabel; + this._searchbox = searchbox; + + var msgbox = document.createElement('div'); + msgbox.id = 'leaflet-control-geosearch-msg'; + msgbox.className = 'leaflet-control-geosearch-msg'; + this._msgbox = msgbox; + + var resultslist = document.createElement('ul'); + resultslist.id = 'leaflet-control-geosearch-results'; + this._resultslist = resultslist; + + $(this._msgbox).append(this._resultslist); + $(this._container).append(this._searchbox, this._msgbox); + + L.DomEvent + .addListener(this._container, 'click', L.DomEvent.stop) + .addListener(this._container, 'keypress', this._onKeyUp, this); + + L.DomEvent.disableClickPropagation(this._container); + + return this._container; + }, + + geosearch: function (qry) { + try { + var provider = this._config.provider; + var url = provider.GetServiceUrl(qry); + + $.getJSON(url, function (data) { + try { + var results = provider.ParseJSON(data); + if (results.length == 0) + throw this._config.notFoundMessage; + + this._showLocation(results[0].X, results[0].Y); + } + catch (error) { + this._printError(error); + } + }.bind(this)); + } + catch (error) { + this._printError(error); + } + }, + + _showLocation: function (x, y) { + if (typeof this._positionMarker === 'undefined') + this._positionMarker = L.marker([y, x]).addTo(this._map); + else + this._positionMarker.setLatLng([y, x]); + + this._map.setView([y, x], this._config.zoomLevel, false); + }, + + _printError: function(message) { + $(this._resultslist) + .html('
  • '+message+'
  • ') + .fadeIn('slow').delay(this._config.messageHideDelay).fadeOut('slow', + function () { $(this).html(''); }); + }, + + _onKeyUp: function (e) { + var escapeKey = 27; + var enterKey = 13; + + if (e.keyCode === escapeKey) { + $('#leaflet-control-geosearch-qry').val(''); + $(this._map._container).focus(); + } + else if (e.keyCode === enterKey) { + this.geosearch($('#leaflet-control-geosearch-qry').val()); + } + } +}); \ No newline at end of file diff --git a/src/js/l.geosearch.provider.esri.js b/src/js/l.geosearch.provider.esri.js new file mode 100644 index 00000000..016d66ab --- /dev/null +++ b/src/js/l.geosearch.provider.esri.js @@ -0,0 +1,27 @@ +/** + * L.Control.GeoSearch - search for an address and zoom to it's location + * L.GeoSearch.Provider.Esri uses arcgis geocoding service + * https://github.com/smeijer/leaflet.control.geosearch + */ + +L.GeoSearch.Provider.Esri = function (options) { + + this._config = options || {}; + var self = this; + + this.GetServiceUrl = function (qry) { + var country = self._config.country || ''; + return 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find?text=' + qry + '&sourceCountry=' + country + '&f=json'; + }; + + this.ParseJSON = function (data) { + if (data.locations.length == 0) + return []; + + var results = []; + for (var i = 0; i < data.locations.length; i++) + results.push(new L.GeoSearch.Result(data.locations[i].feature.geometry.x, data.locations[i].feature.geometry.y, data.locations[i].name)); + + return results; + }; +}; \ No newline at end of file diff --git a/src/js/l.geosearch.provider.google.js b/src/js/l.geosearch.provider.google.js new file mode 100644 index 00000000..fac48e4d --- /dev/null +++ b/src/js/l.geosearch.provider.google.js @@ -0,0 +1,27 @@ +/** + * L.Control.GeoSearch - search for an address and zoom to it's location + * L.GeoSearch.Provider.Google uses google geocoding service + * https://github.com/smeijer/leaflet.control.geosearch + */ + +L.GeoSearch.Provider.Google = function (options) { + + this._config = options || {}; + var self = this; + + this.GetServiceUrl = function (qry) { + var sensor = self._config.sensor || false; + return 'http://maps.googleapis.com/maps/api/geocode/json?address='+qry+'&sensor='+ sensor; + }; + + this.ParseJSON = function (data) { + if (data.results.length == 0) + return []; + + var results = []; + for (var i = 0; i < data.results.length; i++) + results.push(new L.GeoSearch.Result(data.results[i].geometry.location.lng, data.results[i].geometry.location.lat, data.results[i].formatted_address)); + + return results; + }; +}; \ No newline at end of file diff --git a/src/js/l.geosearch.provider.openstreetmap.js b/src/js/l.geosearch.provider.openstreetmap.js new file mode 100644 index 00000000..b6b33e5c --- /dev/null +++ b/src/js/l.geosearch.provider.openstreetmap.js @@ -0,0 +1,27 @@ +/** + * L.Control.GeoSearch - search for an address and zoom to it's location + * L.GeoSearch.Provider.OpenStreetMap uses openstreetmap geocoding service + * https://github.com/smeijer/leaflet.control.geosearch + */ + +L.GeoSearch.Provider.OpenStreetMap = function (options) { + + this._config = options || {}; + var self = this; + + this.GetServiceUrl = function (qry) { + var countryCode = self._config.countryCode || ''; + return 'http://nominatim.openstreetmap.org/search/?q=' + qry + '&format=json&countrycodes='+countryCode; + }; + + this.ParseJSON = function (data) { + if (data.length == 0) + return []; + + var results = []; + for (var i = 0; i < data.length; i++) + results.push(new L.GeoSearch.Result(data[i].lon, data[i].lat, data[i].display_name)); + + return results; + }; +}; \ No newline at end of file