This example queries data from CARTO, uses the geolocation API to get the user's position, and finds the nearest three features.
Note: geolocation appears blocked within bl.ocks.org.
This example queries data from CARTO, uses the geolocation API to get the user's position, and finds the nearest three features.
Note: geolocation appears blocked within bl.ocks.org.
| (function() { | |
| var zoomLevel = 4, | |
| mapCenter = [38, -101]; | |
| var options = { | |
| center: mapCenter, | |
| zoom: zoomLevel | |
| }; | |
| var map = L.map('map', options); | |
| L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', { | |
| attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="http://cartodb.com/attributions">CartoDB</a>', | |
| subdomains: 'abcd', | |
| maxZoom: 19 | |
| }).addTo(map); | |
| var sqlQuery = 'SELECT * FROM stations'; | |
| var stations, | |
| $body = $('body'), | |
| $locate = $('#locate'), | |
| $findNearest = $('#find-nearest'), | |
| $status = $('#status'); | |
| $.getJSON('https://rgdonohue.carto.com/api/v2/sql?format=GeoJSON&q=' + sqlQuery, function(data) { | |
| //$('#loader').fadeOut(); | |
| $body.addClass('loaded'); | |
| stations = L.geoJson(data, { | |
| pointToLayer : function(feature, latlng) { | |
| return L.circleMarker(latlng, { | |
| stroke : false, | |
| fillColor : 'orange', | |
| fillOpacity : 1, | |
| radius: 2 | |
| }); | |
| } | |
| }).addTo(map); | |
| $locate.fadeIn().on('click', function(e) { | |
| $status.html('finding your location'); | |
| if (!navigator.geolocation){ | |
| alert("<p>Sorry, your browser does not support Geolocation</p>"); | |
| return; | |
| } | |
| $body.removeClass('loaded'); | |
| navigator.geolocation.getCurrentPosition(success, error); | |
| $locate.fadeOut(); | |
| }); | |
| }); | |
| function success(position) { | |
| $body.addClass('loaded'); | |
| var currentPos = [position.coords.latitude,position.coords.longitude]; | |
| map.setView(currentPos, zoomLevel); | |
| var myLocation = L.marker(currentPos) | |
| .addTo(map) | |
| .bindTooltip("you are here") | |
| .openTooltip(); | |
| $findNearest.fadeIn() | |
| .on('click', function(e) { | |
| $findNearest.fadeOut(); | |
| $status.html('finding your nearest locations') | |
| queryFeatures(currentPos, 5); | |
| myLocation.unbindTooltip(); | |
| }); | |
| }; | |
| function error() { | |
| alert("Unable to retrieve your location"); | |
| }; | |
| function queryFeatures(currentPos, numResults) { | |
| var distances = []; | |
| stations.eachLayer(function(l) { | |
| var distance = L.latLng(currentPos).distanceTo(l.getLatLng())/1000; | |
| distances.push(distance); | |
| }); | |
| distances.sort(function(a, b) { | |
| return a - b; | |
| }); | |
| var stationsLayer = L.featureGroup(); | |
| stations.eachLayer(function(l) { | |
| var distance = L.latLng(currentPos).distanceTo(l.getLatLng())/1000; | |
| if(distance < distances[numResults]) { | |
| l.bindTooltip(distance.toLocaleString() + ' km from current location.'); | |
| L.polyline([currentPos, l.getLatLng()], { | |
| color : 'orange', | |
| weight : 2, | |
| opacity: 1, | |
| dashArray : "5, 10" | |
| }).addTo(stationsLayer); | |
| } | |
| }); | |
| map.flyToBounds(stationsLayer.getBounds(), {duration : 3, easeLinearity: .1 }); | |
| map.on('zoomend', function() { | |
| map.addLayer(stationsLayer); | |
| }) | |
| } | |
| })(); |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Find Nearest Points in Leaflet</title> | |
| <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" /> | |
| <link rel="stylesheet" href="styles.css"> | |
| </head> | |
| <body> | |
| <div id='map'></div> | |
| <div id='ui'> | |
| <button id='locate'> | |
| Find my location | |
| </button> | |
| <button id='find-nearest'> | |
| Find Nearest Stations | |
| </button> | |
| </div> | |
| <div id="loader-wrapper"> | |
| <div id="loader"></div> | |
| <div class="loader-section section-left"></div> | |
| <div class="loader-section section-right"></div> | |
| <p id='status'>loading vehicle recharging station data</p> | |
| </div> | |
| <script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script> | |
| <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script> | |
| <script src="app.js"></script> | |
| </body> | |
| </html> |
| body { | |
| color: #888; | |
| font-family: "Proxima Nova", sans-serif; | |
| } | |
| #loader-wrapper { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: 1000; | |
| } | |
| #status { | |
| position: absolute; | |
| text-align: center; | |
| width: 100%; | |
| margin: 100px auto; | |
| color: #3d3d3d; | |
| font-size: 1.6em; | |
| z-index: 4000; | |
| } | |
| #loader { | |
| display: block; | |
| position: relative; | |
| left: 50%; | |
| top: 50%; | |
| width: 100px; | |
| height: 100px; | |
| margin: -75px 0 0 -75px; | |
| border-radius: 50%; | |
| border: 3px solid transparent; | |
| border-top-color: #4682b4; | |
| -webkit-animation: spin 2s linear infinite; /* Chrome, Opera 15+, Safari 5+ */ | |
| animation: spin 2s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */ | |
| z-index: 1001; | |
| } | |
| #loader:before { | |
| content: ""; | |
| position: absolute; | |
| top: 5px; | |
| left: 5px; | |
| right: 5px; | |
| bottom: 5px; | |
| border-radius: 50%; | |
| border: 3px solid transparent; | |
| border-top-color: #82b446; | |
| -webkit-animation: spin 3s linear infinite; /* Chrome, Opera 15+, Safari 5+ */ | |
| animation: spin 3s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */ | |
| } | |
| #loader:after { | |
| content: ""; | |
| position: absolute; | |
| top: 15px; | |
| left: 15px; | |
| right: 15px; | |
| bottom: 15px; | |
| border-radius: 50%; | |
| border: 3px solid transparent; | |
| border-top-color: #b446b4; | |
| -webkit-animation: spin 1.5s linear infinite; /* Chrome, Opera 15+, Safari 5+ */ | |
| animation: spin 1.5s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */ | |
| } | |
| @-webkit-keyframes spin { | |
| 0% { | |
| -webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */ | |
| -ms-transform: rotate(0deg); /* IE 9 */ | |
| transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */ | |
| } | |
| 100% { | |
| -webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */ | |
| -ms-transform: rotate(360deg); /* IE 9 */ | |
| transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */ | |
| } | |
| } | |
| @keyframes spin { | |
| 0% { | |
| -webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */ | |
| -ms-transform: rotate(0deg); /* IE 9 */ | |
| transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */ | |
| } | |
| 100% { | |
| -webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */ | |
| -ms-transform: rotate(360deg); /* IE 9 */ | |
| transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */ | |
| } | |
| } | |
| #loader-wrapper .loader-section { | |
| position: fixed; | |
| top: 0; | |
| width: 50%; | |
| height: 100%; | |
| background: rgba(256,256,256,.8); | |
| z-index: 1000; | |
| -webkit-transform: translateX(0); /* Chrome, Opera 15+, Safari 3.1+ */ | |
| -ms-transform: translateX(0); /* IE 9 */ | |
| transform: translateX(0); /* Firefox 16+, IE 10+, Opera */ | |
| } | |
| #loader-wrapper .loader-section.section-left { | |
| left: 0; | |
| } | |
| #loader-wrapper .loader-section.section-right { | |
| right: 0; | |
| } | |
| .loaded #loader, .loaded #loader-wrapper { | |
| opacity: 0; | |
| display: none; | |
| -webkit-transition: all 0.3s ease-out; | |
| transition: all 0.3s ease-out; | |
| } | |
| #map { | |
| position: absolute; | |
| width: 100%; | |
| left: 0; | |
| right: 0; | |
| top: 0; | |
| bottom: 0; | |
| border: 1px solid #777; | |
| box-shadow: 2px 3px 3px 0px rgba(196,192,196,1); | |
| } | |
| button { | |
| position: absolute; | |
| top: 15px; | |
| left: 50px; | |
| padding: .5em 1em; | |
| background-color: #fff; | |
| font-size: 1.2em; | |
| border:0; | |
| box-shadow: 0 1px 5px rgba(0,0,0,0.65); | |
| border-radius: 4px; | |
| color: black; | |
| z-index: 1100; | |
| } | |
| button:hover { | |
| cursor: pointer; | |
| } | |
| #locate { | |
| display: none; | |
| } | |
| #find-nearest { | |
| display: none; | |
| } |