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/leaflet@1.0.1/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/leaflet@1.0.1/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; | |
} |