I try to load a geojson from an URL and display it in a map with leaflet:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/[email protected]/dist/leaflet.css"/>
<script src="/[email protected]/dist/leaflet.js"></script>
</head>
<body>
<div id="my_map" style="height: 600px"></div>
<script>
const map = L.map('my_map')
L.tileLayer('https://{s}.tile.openstreetmap/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = '.geojson';
let shape_obj = await (await fetch(url)).json();
return shape_obj
}
L.geoJson(load_shapefile()).addTo(map);
</script>
</body>
</html>
I get on the JS Console:
Uncaught Error: Invalid GeoJSON object.
at De (GeoJSON.js:221)
at i.addData (GeoJSON.js:117)
at initialize (GeoJSON.js:92)
at new i (Class.js:22)
at Object.Ke (GeoJSON.js:439)
at leaflet.html:21
If possible, I would like to not use jQuery. Thanks for any input!
EDIT: I replaced the url with an actual GeoJSON file, thanks @IvanSanchez!
I try to load a geojson from an URL and display it in a map with leaflet:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="https://unpkg./[email protected]/dist/leaflet.css"/>
<script src="https://unpkg./[email protected]/dist/leaflet.js"></script>
</head>
<body>
<div id="my_map" style="height: 600px"></div>
<script>
const map = L.map('my_map')
L.tileLayer('https://{s}.tile.openstreetmap/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = 'https://raw.githubusercontent./shawnbot/topogram/master/data/us-states.geojson';
let shape_obj = await (await fetch(url)).json();
return shape_obj
}
L.geoJson(load_shapefile()).addTo(map);
</script>
</body>
</html>
I get on the JS Console:
Uncaught Error: Invalid GeoJSON object.
at De (GeoJSON.js:221)
at i.addData (GeoJSON.js:117)
at initialize (GeoJSON.js:92)
at new i (Class.js:22)
at Object.Ke (GeoJSON.js:439)
at leaflet.html:21
If possible, I would like to not use jQuery. Thanks for any input!
EDIT: I replaced the url with an actual GeoJSON file, thanks @IvanSanchez!
Share Improve this question edited Feb 25, 2021 at 10:07 Kilian Röhner asked Feb 24, 2021 at 16:50 Kilian RöhnerKilian Röhner 3852 silver badges10 bronze badges 2- 1 This is an XY problem. The JSON is not GeoJSON (and is not a shapefile as well), but it looks like it's TopoJSON instead. – IvanSanchez Commented Feb 24, 2021 at 16:55
- Thank you @IvanSanchez! I replaced the url with a proper GeoJSON. Unfortunately, the problem persists. – Kilian Röhner Commented Feb 25, 2021 at 10:08
2 Answers
Reset to default 5If you want to extract the geojson and use it later you need to create another function to await the result as the operation is asynchornous:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="https://unpkg./[email protected]/dist/leaflet.css" />
<script src="https://unpkg./[email protected]/dist/leaflet.js"></script>
</head>
<body>
<div id="my_map" style="height: 600px"></div>
<script>
const map = L.map('my_map')
L.tileLayer('https://{s}.tile.openstreetmap/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = 'https://raw.githubusercontent./shawnbot/topogram/master/data/us-states.geojson';
const response = await fetch(url)
const shape_obj = await response.json();
console.log(shape_obj);
return shape_obj;
}
async function main() {
const json = await load_shapefile();
L.geoJson(json).addTo(map);
}
main();
</script>
</body>
</html>
Otherwise if you do not want to use the geojson instance further use then
to fetch the data and immediately use them.
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="https://unpkg./[email protected]/dist/leaflet.css" />
<script src="https://unpkg./[email protected]/dist/leaflet.js"></script>
</head>
<body>
<div id="my_map" style="height: 600px"></div>
<script>
const map = L.map('my_map')
L.tileLayer('https://{s}.tile.openstreetmap/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
let url = 'https://raw.githubusercontent./shawnbot/topogram/master/data/us-states.geojson';
const response = fetch(url).then(response => response.json()).then(response => {
L.geoJson(response).addTo(map);
})
</script>
</body>
</html>
@kboul's answer already points out how to fix it, but doesn't explain why it fails in the first place.
The original code is failing because async function
s return an instance of Promise
, and the L.GeoJSON
constructor expects a static data structure.
So instead of
async function load_shapefile() {
let url = 'https://raw.githubusercontent./shawnbot/topogram/master/data/us-states.geojson';
let shape_obj = await (await fetch(url)).json();
return shape_obj
}
L.geoJson(load_shapefile()).addTo(map);
You can do
load_shapefile().then(function(geojsonData){
L.geoJson(load_shapefile()).addTo(map);
});
And abusing the syntax of .then()
a bit to pass function references only:
load_shapefile().then(L.geoJson).then(map.addLayer.bind(map));
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="https://unpkg./[email protected]/dist/leaflet.css" />
<script src="https://unpkg./[email protected]/dist/leaflet.js"></script>
</head>
<body>
<div id="my_map" style="height: 600px"></div>
<script>
const map = L.map('my_map')
L.tileLayer('https://{s}.tile.openstreetmap/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = 'https://raw.githubusercontent./shawnbot/topogram/master/data/us-states.geojson';
const response = await fetch(url)
const shape_obj = await response.json();
console.log(shape_obj);
return shape_obj;
}
load_shapefile().then(L.geoJson).then(map.addLayer.bind(map));
</script>
</body>
</html>