Reputation: 159
I am trying to add covid Data from a URL to a leaflet map. The issue is that my map is loading and drawing before the data has fully loaded. I have a file of JSON data which I call statesData. Then, I use the p5.js loadJSON() function to grab covid data from a URL and another function to format that data.
// GET THE COVID DATA
function setup(){
loadJSON("https://disease.sh/v3/covid-19/states",gotData);
}
function gotData(data){
covid = data;
statesData.features[1].properties.casesPerOneMillion = covid[1].casesPerOneMillion;
// add covid cases to states data
for (let i = 0; i < statesData.features.length; i++) {
for (let j = 0; j < statesData.features.length; j++) {
if (statesData.features[i].properties.name === covid[j].state) {
statesData.features[i].properties.casesPerOneMillion = covid[j].casesPerOneMillion;
}
}
}
};
Here's an example of what the data looks like when I inspect the page and print it to the console:
Here is how I'm adding the color layers:
// GET CHLORO COLORS BASED ON CASES PER MIL NUM
function getColor(d) {
return d > 30000 ? '#800026' :
d > 25000 ? '#BD0026' :
d > 20000 ? '#E31A1C' :
d > 15000 ? '#FC4E2A' :
d > 5000 ? '#FD8D3C' :
d > 2000 ? '#FEB24C' :
d > 1000 ? '#FED976' :
'#FFEDA0';
}
// CREATE FUNCTION TO STYLE AND APPLY GET COLOR
function style(feature) {
return {
// apply get color
fillColor: getColor(feature.properties.casesPerOneMillion),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
}
}
// doesn't work
L.geoJson(statesData, {style: style}).addTo(map);
I know it isn't an issue with the code, because this (5000 being a random num I used just to be sure my style code was working) :
statesData.features[0].properties.casesPerOneMillion = 5000;
and it does work that way.
The problem is that my map is loading before the data has finished downloading/has gone through the gotData() function that formats it. I thought the obvious solution would be to throw the L.geoJson(statesData, {style: style}).addTo(map);
into an async function, but I guess leaflet doesn't allow you to do that? I always get the error "t.addLayer()" isn't a function when I try... Anyone know how to asynchronously add data to a leaflet map? I'm familiar with javaScript but am a novice when it comes back to async functions, callbacks, etc
Upvotes: 3
Views: 1104
Reputation: 159
With the help of answers above, I determined my original problem was that I was trying to define geo and add it to map at the same time. geo needed to be defined and added to the map outside of the gotData() function. Inside the gotData() function, the addData() function solved the problem.
geo = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature,
});
// *** GET THE COVID DATA *** //
function setup(){
loadJSON("https://disease.sh/v3/covid-19/states",gotData);
}
// *** FORMAT THE DATA *** //
// adds casesPerMillion from queried data to states data
function gotData(data){
covid = data;
statesData.features[1].properties.casesPerOneMillion = covid[1].casesPerOneMillion;
// add covid cases to states data
for (let i = 0; i < statesData.features.length; i++) {
for (let j = 0; j < statesData.features.length; j++) {
if (statesData.features[i].properties.name === covid[j].state) {
// add cases per million to statesData
statesData.features[i].properties.casesPerOneMillion = covid[j].casesPerOneMillion;
// add tests per million to statesData
statesData.features[i].properties.testsPerOneMillion = covid[j].testsPerOneMillion;
break;
}
}
}
geo.addData(statesData); // another part of the solution - addData function
};
geo.addTo(map);
Upvotes: 0
Reputation: 21364
You don't need to use async/await for asynchronous code. The default is still to use the, now somewhat old-school, callback tree. So just put your L.geoJson
call inside the gotData
callback.
This should work. I've allowed myself to replace the getColor
if-then-else monster into a lookup table. Just for style points :-)
const colorMap = {
30000: '#800026',
25000: '#BD0026',
20000: '#E31A1C',
15000: '#FC4E2A',
5000: '#FD8D3C',
2000: '#FEB24C',
1000: '#FED976',
};
// GET CHLORO COLORS BASED ON CASES PER MIL NUM
const getColor = (d) => colorMap(d) || '#FFEDA0';
// CREATE FUNCTION TO STYLE AND APPLY GET COLOR
function style(feature) {
return {
// apply get color
fillColor: getColor(feature.properties.casesPerOneMillion),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
}
}
// GET THE COVID DATA
function setup(){
loadJSON("https://disease.sh/v3/covid-19/states", gotData);
}
function gotData(statesData){
covid = statesData;
statesData.features[1].properties.casesPerOneMillion = covid[1].casesPerOneMillion;
// add covid cases to states data
for (let i = 0; i < statesData.features.length; i++) {
for (let j = 0; j < statesData.features.length; j++) {
if (statesData.features[i].properties.name === covid[j].state) {
statesData.features[i].properties.casesPerOneMillion = covid[j].casesPerOneMillion;
}
}
}
// now it should work
L.geoJson(statesData, {style: style});
};
Update: As Falke Design points out, there was another bug in gotData: data
needed to be statesData
. I changed that.
Upvotes: 3
Reputation: 11338
Your function gotData
will not work, because you never loop over data
, you loop twice over statesData.features.length
You can do this in two ways.
1. define L.geoJSON after loading data
function gotData(data) {
var covid = data;
// add covid cases to states data
for (let j = 0; j < data.length; j++) {
for (let i = 0; i < statesData.features.length; i++) {
if (statesData.features[i].properties.name === covid[j].state) {
statesData.features[i].properties.casesPerOneMillion = covid[j].casesPerOneMillion;
break; // break the loop and go to the next state (outer loop), because you have already found the correct state entry
}
}
}
L.geoJSON(statesData, {
style: style
}).addTo(map);
};
2. define L.geoJSON before and add only the loaded data
var geo = L.geoJSON(null, {
style: style
}).addTo(map);
function gotData(data) {
var covid = data;
// add covid cases to states data
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < statesData.features.length; j++) {
if (statesData.features[i].properties.name === covid[j].state) {
statesData.features[i].properties.casesPerOneMillion = covid[j].casesPerOneMillion;
break; // break the loop and go to the next state (outer loop), because you have already found the correct state entry
}
}
}
geo.addData(statesData);
};
Upvotes: 1