vasturiano / globe.gl

UI component for Globe Data Visualization using ThreeJS/WebGL
https://vasturiano.github.io/globe.gl/example/world-population/
MIT License
2.03k stars 301 forks source link

Question: Reverse Engineer air traffic example #12

Open LukeCole96 opened 4 years ago

LukeCole96 commented 4 years ago

Hi,

I hope you are keeping well, and a great project.

I'm trying to use the air traffic example as it best fits my experiment. I am trying to build a map that connects people to their closest datacenter (All mocked data, was learning how to build a web api and thought I'd try to expand it more and came across this project).

I want to replace the fetching of the airport data and use an endpoint that exposes the following json:

[ { "metricName": "concurrentPlays", "proposition": "peacock", "state": "wi", "stateLongLat": { "destLat": "38.5284223", "destLong": "-77.7938668", "lat": "46.01222384063236", "long": "-90.5712890625" } }, { "metricName": "concurrentPlays", "proposition": "peacock", "state": "wi", "stateLongLat": { "destLat": "38.5284223", "destLong": "-77.7938668", "lat": "45.583289756006316", "long": "-89.40673828125" } } ];

I have a way to extract this data, but I want to parse the lat and longs (dest being destination, or end in your example equivalent) but I'm struggling to understand how to use the API specified, it seems there's a lot going on and removing bits of code seems to break the project.

If you're able to assist, will definitely donate more than just a coffee. :)

I tried manually passing in an array of lat/longs but it doesn't seem to work like this; .arcStartLat(["38.42777351132902", "38.5284223"]) .arcStartLng(["-81.34277343750001", "-77.7938668"]) .arcEndLat(["38.5284223", "44.1757946"]) .arcEndLng(["-77.7938668", "-121.9088563"])

It does work if I give it one item for each as below: .arcStartLat(["38.42777351132902"]) .arcStartLng(["-81.34277343750001"]) .arcEndLat(["38.5284223"]) .arcEndLng(["-77.7938668"])

I am using this as a alternative to the fetch example in the air traffic solution:

` const airportParse = ([metricName, proposition, state, startLat, startLng, endLat, endLng]) => ({ metricName, proposition, state, startLat, startLng, endLat, endLng });

var x; Promise.all([ fetch('http://localhost:8080/update') .then(res => res.json()) .then((out) => { var i; for (i = 0; i < out.length; i++) { //this works and gets every bit of data i need... var index = out[i] x = [...Array(300).keys()].map(() => ( [ // metricName = index.metricName, proposition = index.proposition, state = index.state, startLat = index.stateLongLat.lat, startLng = index.stateLongLat.long, endLat = index.stateLongLat.destLat, endLng = index.stateLongLat.destLong startLat = index.stateLongLat.lat, startLng = index.stateLongLat.long, endLat = index.stateLongLat.destLat, endLng = index.stateLongLat.destLong ] )) console.log(x) } myGlobe .pointsData(x) .arcsData(x); }) ]);`

Again, any help will be greatly appreciated. Happy to supply the code if necessary :) A massive thank you in advance

vasturiano commented 4 years ago

@LukeCole96 thanks for reaching out.

Basically the arcStartLat et al methods are a way to specify how the lat,lng values can be extracted from the arc data objects. These are so called accessor methods and can be specified in a few different ways. The most typical being a string that indicates the name of the data object attribute that holds the desired value. Or a custom function that receives an arcData object and knows how to return the intended value (f.e.: arcStartLat(arcData => arcData.srcLat)).

So, in your case it appears the structure of your input arc objects is:

{ 
  "metricName": "concurrentPlays", 
  "proposition": "peacock", 
  "state": "wi", 
  "stateLongLat": { 
    "destLat": "38.5284223", 
    "destLong": "-77.7938668", 
    "lat": "46.01222384063236", 
    "long": "-90.5712890625"
   }
}

You can then setup your coordinates accessor as such:

.arcStartLat(arc => +arc.stateLongLat.lat)
.arcStartLng(arc => +arc.stateLongLat.long)
.arcEndLat(arc => +arc.stateLongLat.destLat)
.arcEndLng(arc => +arc.stateLongLat.destLong)

The + sign is for coercion of the value to a number.

Let me know if this works out for you.

LukeCole96 commented 4 years ago

@vasturiano thanks for getting in touch.

I'll be having a try on those suggestions over the weekend - massive thanks for clarifying!

Another question would be, is this globe capable of updating in real time? If the json was to change, would I be able to remove the curves drawn to re-apply a new set without restarting the server?

Thanks again.

vasturiano commented 4 years ago

@LukeCole96 yes, it can do that.

It behaves like you describe. Whenever a new data set is given, it will diff the two and identify the elements that needs adding, updating or removing. The comparison is done by object reference, so if some of your arcs remain the same make sure to pass the exact same object, not a cloned one, to indicate to the component that the object remains.

Further, the adding/removing/updating transitions are animated into position. You can control the animation time using arcsTransitionDuration.

lslzl3000 commented 4 years ago

@LukeCole96 to update data in realtime, just fetch your data from your server every 60s or anytime your want, then recall .arcsData()

e.g.

var arcData =[{},{},...] // old data 

setInterval(()=>{
    // fetch your data from your server or any other api
    fetch(xxx).then(res => res.json()).then(data=>{
         // process your raw data
         // for better performance, you may want to use your old Array object and replace some of the lines with new data
         // e.g. loop the arcData, and remove old ones and insert new ones
         // ....
         // or you can just simply reset arcData = data, which is not good but it's ok to do~

         // then recall your data with arcsData, the Globe would update the view automatically
         myGlobe.arcsData(arcData)
    })
}, 60 * 1000)