Search code examples
javascriptcsvgoogle-mapsd3.jsasync-await

Values in array read in from d3.csv are undefined outside of function despite global variable declaration


Thank you in advance for your help! I have declared four arrays globally in my code. Then, in the function to read the data from the csv, I assign the data values to array elements. However, the array elements are undefined outside of this function, and I can't seem to find the issue... I am using d3 version 7 () and Google Maps Javascript API.

My CSV file is formatted Project_Name, Artist, Lat, Long - with around 300 values.

// Request needed libraries.
const { Map, InfoWindow } = await google.maps.importLibrary("maps");
const { LatLng } = await google.maps.importLibrary("core");
const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker");

//Global Vars
let map;
let projectName = [];
let artist = [];
let lat = [];
let long = [];
let markers = [];


async function data() {
  d3.csv("/data/single.csv", function(d) {
    return {
      projectName: +d.Project_Name,
      artist: +d.Artist,
      lat: +d.Latitude,
      long: +d.Longitude,
    }
  }).then(function(d) {
    for (var i = 0; i < d.length; i++) {
      projectName[i] = d[i].Project_Name;
      artist[i] = d[i].Artist;
      lat[i] = parseFloat(d[i].Latitude);
      long[i] = parseFloat(d[i].Longitude);
    }
  });
}



function createMarkers(m){
  for (var z=0; z < lat.length; z++) {
    markers[z] = new google.maps.Marker({
      position: new google.maps.LatLng(lat[z], long[z]),
      map: m,
      title: projectName[z],
    });
  } 
}

async function initMap() {
  
  const map = new Map(document.getElementById("map"), {
    zoom: 11,
    center: { lat: 37.4239163, lng: -122.0947209 },
    mapId: "[MAP ID]",
    mapTypeControl: false,
  });
  const infoWindow = new google.maps.InfoWindow({
    content: "",
    disableAutoPan: true,
  });
  
  //READ CSV FILE
  data();
  
  //MARKERS
  createMarkers(map);
  
}

initMap();

I tried using await, that didn't solve the problem. Also tried to use setTimeout, which resulted in the value of NaN instead of undefined.


Solution

  • What's happening is that d3.csv is asynchronous. You got the right idea by wanting to await somewhere, but you have to await the d3.csv promise. If you want to "await" data to be filled, you have to return d3.csv promise :

    async function data() {
      return d3.csv("/data/single.csv", function(d) {
       ...
      });
    }
    

    Then await the data function before calling createMarkers(); :

    ... 
        //READ CSV FILE
        await data();
        // now your global arrays should be filled
        createMarkers();
    ...