Leaflet: How to fetch geojson from URL and pass it to L.geoJson - javascript

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.com/leaflet#1.7.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet#1.7.1/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.org/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = 'https://raw.githubusercontent.com/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!

If 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.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/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.org/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = 'https://raw.githubusercontent.com/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.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/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.org/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
let url = 'https://raw.githubusercontent.com/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 functions 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.com/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.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/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.org/{z}/{x}/{y}.png').addTo(map);
map.setView([37.8, -96], 4);
async function load_shapefile() {
let url = 'https://raw.githubusercontent.com/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>

Related

How do you add a loading GIF spinner before AOI response in vanilla javascript?

So far I've tried using the let method make the GIF a constant and attempting to switch display type is js style function. Can someone guide me into displaying GIF image before API response and hiding it when fetch() is processed.
Html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./doggos.css">
<title>Dogs</title>
</head>
<body>
<h1>Doggos</h1>
<button class="add-doggo">Add Doggo</button>
<div class="doggos">
<div class="loader"><img src="./giphy (1).gif"></img></div>
</div>
<script src="./doggos.js"></script>
</body>
</html>
Javascript
const DOG_URL = "https://dog.ceo/api/breeds/image/random";
const doggos = document.querySelector(".doggos");
function addNewDoggo() {
const promise = fetch(DOG_URL);
promise
.then(function(response) {
const processingPromise = response.json(); //This line of code parses the API response into a usuable js object
return processingPromise; //this code returns a new promise and this process is called | PROCESS-CHAINING
})
.then(function(processedResponse) {
const img = document.createElement("img");
img.src = processedResponse.message;
img.alt = "Cute doggo";
doggos.appendChild(img);
});
}
document.querySelector(".add-doggo") .addEventListener("click", addNewDoggo)

How to loop pokemons out from the PokeAPI?

Hi I am in the process of fetching data down from the pokeapi, I can loop them out in the console, but when I send them to the div ID__Pokemon only the last index comes out, what is the best way to loop the pokemon names out in ID__Pokemon ?
let myApp = document.querySelector('#App');
const divPokemon = document.getElementById('ID__Pokemon');
const api_url = 'https://pokeapi.co/api/v2/pokemon/';
const pokemonData = async () => {
const response = await fetch(api_url);
const data = await response.json();
for (const item in data.results) {
let pokemon = data.results[item];+
console.log(pokemon.name);
divPokemon.innerHTML = `Pokemon: ${pokemon.name}`;
}
};
pokemonData();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="function.js" defer></script>
</head>
<body>
<div id="App">
<div id="ID__Pokemon"></div>
</div>
</body>
</html>
doing divPokemon.innerHTML = `Pokemon: ${pokemon.name}`; replaces the content with each iteration
Here is an edit of your code which adds a new "li" element to your list, filled with the proper text content
let myApp = document.querySelector('#App');
const divPokemon = document.getElementById('ID__Pokemon');
const api_url = 'https://pokeapi.co/api/v2/pokemon/';
const pokemonData = async () => {
const response = await fetch(api_url);
const data = await response.json();
for (const item in data.results) {
let pokemon = data.results[item];
console.log(pokemon.name);
let newPokemon = document.createElement("li");
newPokemon.innerText = `Pokemon: ${pokemon.name}`;
divPokemon.appendChild(newPokemon);
}
};
pokemonData();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="function.js" defer></script>
</head>
<body>
<div id="App">
<div id="ID__Pokemon"></div>
</div>
</body>
</html>

How do you display all images coming from the newsapi?

Hi I am trying to create a news app using the newsapi. I have managed to display the headings from the api but cant seem to manage to loop over all the images and be displayed to the screen. If you could show me how this could be done I would very much appreciate this. my code is:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/main.css">
<title>News App</title>
</head>
<body>
<h2>BBC News</h2>
<span class="newsImage"></span>
<li class = newsList></li>
<script src="js/main.js"></script>
</body>
</html>
JavaScript
const newsList = document.querySelector(".newsList")
const newsImage = document.querySelector(".newsList")
newsImage.innerHTML =''
newsList.innerHTML= ''
var url = 'https://newsapi.org/v2/top-headlines?' +
'sources=bbc-news&' +
'apiKey=**********************';
var req = new Request(url);
fetch(req)
.then(function(response) {
return response.json()
}).then((data)=>{
console.log(data)
data.articles.map(article => {
let li = document.createElement('li')
let a = document.createElement('a')
let image = document.createElement('span')
image.innerHTML = `<img src=${data.articles.urlToImage}>`
a.setAttribute('href', article.url)
a.setAttribute('target','_blank' )
a.textContent = `${article.title}`
li.appendChild(a)
newsList.appendChild(li)
newsImage.appendChild(image)
});
})

Why loadImage is not called in p5js

I am new with p5js. I am trying to load an image using loadImage().
This is my code:
function setup (img) {
classifier.classify(img, gotResult)
appendGif(img)
}
/* This code return a random tag to use in the
url.
variable tag make reference to an array I wouldn't show here.
*/
function getRandomTag () {
const randomIndex = Math.floor(Math.random() * tags.length)
return tags[randomIndex]
}
/* This function return a random gif from giphy api */
async function getRandomGif (randomTag) {
const url = `${baseURL}${gifs}${random}?api_key=${api_key}&rating=${rating}&tag=${randomTag}`
const randomResponse = await fetch(url)
const responseJSON = await randomResponse.json()
const gif = responseJSON.data.image_url
return gif
}
/* And then, this code append the random gif to an img element in my html*/
function appendGif (gif) {
const imgElement = document.createElement('img')
imgElement.src = gif
kebabElement.appendChild(imgElement)
}
/* I am using the preload function as p5js docs say
and I load the image with loadImage function */
function preload(gif) {
classifier = ml5.imageClassifier('MobileNet');
const img = loadImage(gif)
return img
}
function gotResult (error, result) {
if (error) throw error
console.info(result)
}
async function main () {
const randomTag = getRandomTag()
const gif = await getRandomGif(randomTag)
const img = await preload(gif)
return setup(img)
}
main();
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta name="keywords" content="gif, gifs, giphy" />
<meta name="description" content="An initial gif is presented on the page. Click the gif to retrieve other somewhat related gif based on AI recognition of the initial image." />
<meta name="author" content="Diesan Romero" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" />
</head>
<body>
<header>
<nav>
<div class="nav-wrapper">
GIF KEBAB
</div>
</nav>
</header>
<main>
<div id="kebab"></div>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js" integrity="sha512-gQVBYBvfC+uyor5Teonjr9nmY1bN+DlOCezkhzg4ShpC5q81ogvFsr5IV4xXAj6HEtG7M1Pb2JCha97tVFItYQ==" crossorigin="anonymous"></script>
<script src="https://unpkg.com/ml5#latest/dist/ml5.min.js"></script>
<script src="src/index.js" type="module" ></script>
</body>
</html>
but I am getting this error:
Uncaught (in promise) ReferenceError: loadImage is not defined
What I want to do here is load that auto generated gif with the loadImage() function.
In short, I am getting an error when calling the loadImage() function. How is possible to be not defined if I am loading p5js on my html?
Split the gif into frames
Then ....loadImage("gif1", "gif2" ......) and so on in the correct order.

Why does this HTTP request return array lengths rather than content?

I am working on some stuff here that includes fetching data asynchronously from an API. All is well except when I try pushing the correct answer into the incorrect answers array. All that is being returned are the respective array lengths rather than the content. What is it that I am doing wrong?
Here are the HTML and jQuery codes:
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<h3>Answers</h3>
<ol></ol>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="index.js"></script>
</body>
</html>
jQuery
$(() => {
$.ajax({
method: "GET",
url: "https://opentdb.com/api.php?amount=50&category=18",
async: true,
success: (data) => {
let results = data.results;
$.each(results, (i, difficulty, question) => {
difficulty = results[i].difficulty;
question = results[i].question;
correctAnswer = results[i].correct_answer;
answers = results[i].incorrect_answers;
$("ol").append(`
<li>${answers.push(correctAnswer)}</li>
`);
});
}
});
});
Check the docs for the push function.
Return value
The new length property of the object upon which the method was called.
Aat the end of your function you are pushing the correctAnswer to answers which returns the length of answers array and you are showing that in your html. That's perfectly natural.
Push first and then create the html tag.
Check this;
$(() => {
$.ajax({
method: "GET",
url: "https://opentdb.com/api.php?amount=50&category=18",
async: true,
success: (data) => {
let results = data.results;
$.each(results, (i, difficulty, question) => {
difficulty = results[i].difficulty;
question = results[i].question;
correctAnswer = results[i].correct_answer;
answers = results[i].incorrect_answers;
answers.push(correctAnswer)
$("ol").append(`
<li>${correctAnswer}</li>
`);
});
}
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<h3>Answers</h3>
<ol></ol>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="index.js"></script>
</body>
</html>

Categories