Things Near Me – Find & Learn About Landmarks Nearby

Back in 2012, I was planning to build a location-aware app that would tell me about interesting sights & news-worthy facts about places that fall in the way of a train journey.

I discovered that Web Dev guru Chris Heilmann (@codepo8) had built a nifty app on a similar theme and shared the JavaScript code under the BSD license. Things Around You used the browser's geolocation feature to find Wikipedia articles on nearby landmarks via the GeoNames API & list them with a brief description.

For a Windows 8 app hackathon, I utilized the Geolocation detection idea to build a little app that I called GeoBuzz & posted it on the Windows 8 App Store.

It's been on the back of my mind to extend it with more features. Now that GitHub Copilot is here, there was no need to procrastinate.

I had a friendly chat with GitHub Copilot (Gemini Flash model). In under an hour, I customized @codepo8's original sample to include a map directly on the web page instead of linking to a Google Map. GitHub Copilot suggested using Leaflet. It also helped me with the code to create a map with numbered markers corresponding to the numbered list of landmarks.

What's special about the generated code? It uses modern JavaScript so there is no need for a JavaScript helper library like jQuery. The CSS for the modified UI of the HTML5 web page that now includes a map was all in place so that with just minor changes I was able to run it almost immediately!

While testing the app, I found that the Geonames API returns the value for the parameter wikipediaUrl like "en.wikipedia.org/wiki/Raj_Bhavan%2C_Hyderabad" - without the protocol prefix. I had to fix this oddity through code.

I tweaked the CSS & JavaScript code a bit to customize the functionality to my liking. As the Geonames API requires a username, I had to replace it with mine at the placeholder on line 186 in the AI co-created code that I've shared as a GitHub Gist. It is also listed at the end of this post. Check it out and let me know what you think of it.

To get the app to work you have to allow the Geolocation feature in your browser. The accuracy of your current location may vary as every browser has its own way of fetching the location coordinates after Geolocation is enabled.

The key technical features of this app (that I got GitHub Copilot to document) -

  • Geolocation API: The core functionality relies on the browser's Geolocation API (navigator.geolocation.getCurrentPosition) to get the user's latitude and longitude. This API requires user permission and handles potential errors gracefully.
  • Leaflet: An open-source JavaScript library is used for displaying an interactive map. Leaflet provides tile-based map rendering, marker placement, and popup windows for displaying information about each landmark.
  • Geonames API: The application fetches nearby Wikipedia articles using the Geonames API (https://secure.geonames.org/findNearbyWikipediaJSON). This API requires a username and returns a JSON response containing article titles, summaries, and geographical coordinates.
  • Responsive Design: CSS media queries (@media (max-width: 600px)) are used to adapt the layout for different screen sizes, ensuring a consistent user experience on both desktop and mobile devices.
  • Dynamic Content Update: JavaScript is used to dynamically update the HTML document with the user's location and the list of nearby articles retrieved from the Geonames API. This involves creating and appending HTML elements to the DOM.

Adapting the original sample was quite a learning experience and I plan to modernize more of the apps I built in the past.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Things Near Me</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<style>
/* General Styles */
* {
margin: 0;
padding: 0;
font-size: 15px;
font-family: helvetica, arial, sans-serif;
box-sizing: border-box; /* Added for responsive layout */
}
html, body {
background: #000;
height: 100%; /* Required for full-height map */
}
#container {
max-width: 100%; /* Make container responsive */
margin: 0 auto;
position: relative;
background: #cfe7fa;
background: linear-gradient(top, #cfe7fa 0%, #6393c1 100%);
padding: 10px; /* Add some padding around the content */
}
/* Map Styles */
#map {
width: 100%;
height: 400px; /* Adjust as needed */
margin-bottom: 10px;
}
/* List Styles */
ul {
padding: 0.5em 1em;
list-style-type: decimal; /* Show numbers in the list */
}
output {
display: block;
margin: 1em 0;
}
li {
font-weight: bold;
padding: 5px 0;
}
li li {
padding-top: 0;
}
li span {
font-weight: normal;
}
/* Heading Styles */
h1 {
color: #101010;
text-align: center;
font-family: futura, arial, sans-serif;
text-transform: uppercase;
background: linear-gradient(top, #4c4c4c 0%, #131313 100%);
padding: 5px 0;
}
h1 a {
color: #000;
}
.numbered-marker {
background: none;
border: none;
}
.numbered-marker .marker-number {
background-color: #007bff; /* Adjust color as needed */
color: white;
width: 25px;
height: 25px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
font-weight: bold;
border: 2px solid white;
}
/* Footer Styles */
footer {
text-align: center;
padding: 10px;
font-size: 0.8em;
position: relative;
bottom: 0;
width: 100%;
}
/* Add margin to text content */
#location,
#articles {
margin: 0 10px; /* Add horizontal margin */
}
/* Responsive adjustments */
@media (max-width: 600px) {
#container {
padding: 5px;
}
h1 {
font-size: 1.2em;
}
ul {
padding: 0.5em;
list-style-type: decimal; /* Show numbers in the list */
}
li, output {
font-size: 0.9em;
}
}
</style>
</head>
<body>
<div id="container">
<h1>Things Near Me</h1>
<div id="map"></div>
<output id="location"></output>
<ul id="articles"></ul>
<footer>
<p><a href="http://wait-till-i.com/"></a>Original code</a> by
<a href="http://wait-till-i.com/">Chris Heilmann</a> -
<a href="http://twitter.com/codepo8">@codepo8</a>
</p>
<p>Customized by <a href="http://twitter.com/mvark">@mvark</a> & GitHub Copilot
</p>
</footer>
</div>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script>
var map = L.map('map').setView([0, 0], 2); // Default view
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
function geo_success(position) {
document.getElementById('location').textContent = 'Current Location - Latitude: ' + position.coords.latitude + ', Longitude: ' + position.coords.longitude;
map.setView([position.coords.latitude, position.coords.longitude], 13);
L.marker([position.coords.latitude, position.coords.longitude]).addTo(map)
.bindPopup('You are here!')
.openPopup();
// Fetch Wikipedia articles (replace with your actual Geonames API call)
fetchWikipediaArticles(position.coords.latitude, position.coords.longitude);
}
function geo_error() {
document.getElementById('location').textContent = "Sorry, no position available.";
}
var geo_options = {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000
};
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(geo_success, geo_error, geo_options);
} else {
document.getElementById('location').textContent = "Geolocation is not supported by this browser.";
}
function fetchWikipediaArticles(latitude, longitude) {
// Replace with your actual Geonames API endpoint and parameters
const geonamesApiUrl = `https://secure.geonames.org/findNearbyWikipediaJSON?lat=${latitude}&lng=${longitude}&radius=10&maxRows=10&username=YOUR_GEONAMES_USERNAME`;
fetch(geonamesApiUrl)
.then(response => response.json())
.then(data => {
const articlesList = document.getElementById('articles');
articlesList.innerHTML = ''; // Clear existing articles
if (data.geonames && data.geonames.length > 0) {
data.geonames.forEach((article, index) => { // Added index
const listItem = document.createElement('li');
// Display distance
const distance = parseFloat(article.distance).toFixed(2);
listItem.innerHTML = `<a href="https://${article.wikipediaUrl}" target="_blank">${article.title}</a> (${distance} km) - <span>${article.summary}</span>`;
articlesList.appendChild(listItem);
// Create numbered marker
const numberedIcon = L.divIcon({
className: 'numbered-marker',
html: `<div class="marker-number">${index + 1}</div>`
});
L.marker([article.lat, article.lng], { icon: numberedIcon }).addTo(map)
.bindPopup(`<a href="https://${article.wikipediaUrl}" target="_blank">${article.title}</a>`);
});
} else {
articlesList.innerHTML = '<li>No Landmarks found nearby.</li>';
}
})
.catch(error => {
console.error('Error fetching Wikipedia articles on Landmarks:', error);
const articlesList = document.getElementById('articles');
articlesList.innerHTML = '<li>Error fetching articles on Landmarks.</li>';
});
}
</script>
</body>
</html>

Comments

Popular posts from this blog

The Mercurial Grok AI Assistant Understands & Speaks Indian Languages

The Diet Delinquent