pwshub.com

Building a General Purpose GeoJSON Viewer with Leaflet

Last week I shared my initial experiences with Leaflet and I thought I'd share a small demo I built with it - a general purpose GeoJSON viewer.

As I mentioned at the end of my last post, GeoJSON is a specification for encoding ad hoc geographic data. Here's an example:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "id": 0,
            "properties": {
                "Code": "FRLA",
                "Name": "Frederick Law Olmsted National Historic Site"
            },
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -71.13112956925647,
                    42.32550867371509
                ]
            }
        },
        {
            "type": "Feature",
            "id": 1,
            "properties": {
                "Code": "GLDE",
                "Name": "Gloria Dei Church National Historic Site"
            },
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -75.14358360598474,
                    39.93437740957208
                ]
            }
        },
	]
}

GeoJSON can encode points, lines, polygons, and more, and support a properties section that can have anything in it. Leaflet makes it easy to use GeoJSON. Here's the example I used in that last post:

let dataReq = await fetch('https://assets.codepen.io/74045/national-parks.geojson');
let data = await dataReq.json();
L.geoJSON(data).bindPopup(function (layer) {
		return layer.feature.properties.Name;
}).addTo(map);

That's literally it. Given how easy this, I thought I'd build a demo where the data was provided by the user.

The Application

My application is built with simple vanilla JavaScript, no Alpine even, and lets you drop a file into the browser to load the information.

The Leaflet demo

My code waits for DOMContentLoaded and then registers event handlers for dragdrop support:

document.addEventListener('dragover', e => e.preventDefault());
document.addEventListener('drop', handleDrop);

When you drop a file, I then use a bit of code to read it in.

function handleDrop(e) {
		e.preventDefault();
		let droppedFiles = e.dataTransfer.files;
		if(!droppedFiles) return;
		let myFile = droppedFiles[0];
		let ext = myFile.name.split('.').pop();
		if(ext !== 'geojson') {
			alert('Drag/drop a .geojson file only.');
			return;
		}
		let reader = new FileReader();
		reader.onload = e => {
			loadGeoJSON(JSON.parse(e.target.result));
		};
		updateStatus('Reading .geojson');
		reader.readAsText(myFile);	
}

The loadGeoJSON function handles adding the data to Leaflet:

async function loadGeoJSON(data) {
	updateStatus(`.geojson loaded with ${data.features.length} features. Adding to map now.`);
	L.geoJSON(data, {
	}).bindPopup(function (layer) {
			return `
			<p>
			<b>Properties:</b><br>
			<pre style='white-space:pre-wrap'><code>
${JSON.stringify(layer.feature.properties,null,'  ')}
			</code></pre>
			</p>
			`;
	},{minWidth:450}).addTo(map);
}

This is pretty much the same code as before, except that my popup uses a basic dump (stringify) of the properties key. Note that this will not work for all files, especially if there's a lot of data there. I could get fancier with my output there and perhaps add a max height with overflow. That being said, here is how it looks after adding America's parks to it (and clicking one feature):

The Leaflet demo - with data

You can test it out here (full screen): https://codepen.io/cfjedimaster/full/GRbxVVR

And here's the full code:

See the Pen Leaflet geojson viewer (v2) by Raymond Camden (@cfjedimaster) on CodePen.

Source: raymondcamden.com

Related stories
5 days ago - I've looked at Chrome's on-device GenAI development a few times now, and as a feature it is moving pretty fast. In fact, that first post and my follow up both don't work anymore due to the API changing. I'm fine with that as I knew it was...
3 weeks ago - Marc Olson, a long-time Amazonian, discusses the evolution of EBS, highlighting hard-won lessons in queueing theory, the importance of comprehensive instrumentation, and the value of incrementalism versus radical changes. It's an...
1 month ago - In this tutorial, you'll learn how to create and use full-featured classes in your Python code. Classes provide a great way to solve complex programming problems by approaching them through models that represent real-world objects.
1 month ago - If you've built a frontend project in the last five years, you will have likely written some components, and maybe even used a component library. Components and libraries have been an important part of the web development landscape for...
3 days ago - “Should I use pixels or rems?”. In this comprehensive blog post, we'll answer this question once and for all. You'll learn about the accessibility implications, and how to determine the best unit to use in any scenario.
Other stories
1 hour ago - Hello, everyone! It’s been an interesting week full of AWS news as usual, but also full of vibrant faces filling up the rooms in a variety of events happening this month. Let’s start by covering some of the releases that have caught my...
2 hours ago - Nitro.js is a solution in the server-side JavaScript landscape that offers features like universal deployment, auto-imports, and file-based routing. The post Nitro.js: Revolutionizing server-side JavaScript appeared first on LogRocket Blog.
2 hours ago - Information architecture isn’t just organizing content. It's about reducing clicks, creating intuitive pathways, and never making your users search for what they need. The post Information architecture: A guide for UX designers appeared...
2 hours ago - Enablement refers to the process of providing others with the means to do something that they otherwise weren’t able to do. The post The importance of enablement for business success appeared first on LogRocket Blog.
3 hours ago - Learn how to detect when a Bluetooth RFCOMM serial port is available with Web Serial.