3

I have written a JavaScript code (I just got started) which queries the Opensky REST API every 10 seconds. After I collect the data, I plot it through Leaflet.js. For each item I add a popup text box which opens when I click on the tooltip. So far the code works great!

Here is the code so you can play around:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=\, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="id=edge">
        <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="crossorigin=""/>
        <script src="https://unpkg.com/[email protected]/dist/leaflet.js"
            integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
            crossorigin="">
        </script>
        <style>
            #openskyMap { 
                height: 800px; 
                width:1200px;
            }
        </style>
        <title>
            "FETCH JSON from API and map lat lon"
        </title>
    </head>
    <body>

        <h1>Where are the flights</h1>
        <p>Last Update (UNIX time): <span id="ts"></span></p>

        <div id="openskyMap"></div>

        /*                           JAVASCRIPT CODE BEGINS HERE                             */ 
        <script>

            /* DEFINE OPENSKY API URL */
            var opensky_url = "https://opensky-network.org/api/states/all?time=TIME";

            /* INITIATE LEAFLET MAP */
            const mymap = L.map('openskyMap').setView([45, 0], 3);
            const attribution = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreatMap</a> contributors'
            const tileUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
            const tiles = L.tileLayer(tileUrl, {attribution});
            var layerGroup = L.layerGroup().addTo(mymap);
            tiles.addTo(mymap);

            /* CHANGE ICON SIZE BASED ON ZOOM */
            mymap.on('zoomend', function(e) {
                var currentZoom = mymap.getZoom();
                console.log("Current Zoom" + " " + currentZoom);
                if (currentZoom >= 10) {
                damsRadius = 100;
                } else {
                damsRadius = 20000;
                }
            });

            /* FUNCTION TO GET THE ICAO24 CODE. I CANNOT GET IT OUT OF HERE THOUGH! */
            function getIcao24(e) {
                var popup = e.target.getPopup();
                var content = popup.getContent();
                console.log(content)
                return content
            }

            /* INITIATE QUERY FUNCTION */
            async function getOpensky() {

                /* CALCULATE UNIX TIME TO BE PASSED TO THE URL */
                var ts = Math.round((new Date()).getTime() / 1000);
                ts = ts.toString();

                /* MAKE QUERY TO OPENSKY URL */
                const  response = await fetch(opensky_url.replace('TIME',ts));
                const data = await response.json();

                /* PLOT ITEMS TO MAP USING LEAFLET:js */
                layerGroup.clearLayers();
                for (var key in data.states) {

                    /* GET SINGLE ITEM FROM JSON */
                    const item = data.states[key];

                    try{ 

                       /* GET GEOGRAPHICAL COORDINATES*/
                        const lon = item[5];
                        const lat = item[6];

                        /* DEFINE POPUP TEXT TO BE DISPLAYED*/
                        const popupText = "<p>"+item[0] + " - " + item[1] + "<br/>Lat: " + lat.toFixed(2)+" / Lon: "+lon.toFixed(2)+"<br/>Epoch: "+ts+"</p>";

                        /* ADD ITEM TO THE MAP. CALL getICAO24 FUNCTION BUT I DON'T KNOW HOW TO SAVE THE OUTPUT*/
                        L.circle(L.latLng(
                            parseFloat(item[6]), // lon
                            parseFloat(item[5])  // lat
                        ), damsRadius).addTo(layerGroup).bindPopup(popupText).on('click', getIcao24);

                        document.getElementById('ts').textContent = ts;
                    }
                    catch (e) {}
                }               

            }
            /* CALL FUNCTION FIRST TIME*/
            getOpensky();

            /* UPDATE FUNCTION EVERY 10 SECONDS */
            setInterval(getOpensky, 10000);

        </script>
    </body>
</html>

Every time I click on an aircraft (item), the popup window opens as expected. However, I would like to keep the selected popup text open even after the refresh has occurred (setInterval every 10 seconds). This is not happening due to the fact that when I click on the tooltip, the output is only displayed on the console but not store anywhere to be somehow recognized during the next query.

I though that one possible solution is to add a function called getIcao24 which should return the popup text and get the unique icao24 code (item[0]) from the string and then check when it appears in the next iteration and set the popup box as open. However I have no clue how to get such information out of the function.

Would you be able to suggest a smart and elegant way to achieve my goal, i.e. maintain the popup box of a clicked item open even after a refresh has occurred?

1 Answer 1

3

There are probably many ways to achieve what you want, below is described one of them I usually use.

To have handy some property when you process marker event, you can 'misuse' marker object and just define this property as a new maker property, to which you can give any name as long as it does not collide with standard properties. In the example below it's _myID, which gets the value of item[0].

Then when popup is opened (more pertinent popupopen event is used), _myID property is saved in global variable idPopup.

When markers are refreshed next time, item[0] values are compared to saved id and upon match popup is opened.

There is also popupclose event processing function to clear idPopup if popup is closed by user before refresh. Since popup is closed also at the time marker removal/referesh, there is refreshInProgress variable to take care of that. popupFound variable takes care of the case when marker with the popup is not displayed upon next refresh.

So the code could the look something like this:

var idPopup = '';            

function getIcao24(e) {
  idPopup = e.target._myID;
}

function processPopupClose(e) {
  if (!refreshInProgress) {
    idPopup = '';
  }
}

async function getOpensky() {
  var ts = Math.round((new Date()).getTime() / 1000);
  ts = ts.toString();
  const  response = await fetch(opensky_url.replace('TIME',ts));
  const data = await response.json();
  refreshInProgress = true;
  layerGroup.clearLayers();
  popupFound = false;
  for (var key in data.states) {
    const item = data.states[key];
    try { 
      const lon = item[5];
      const lat = item[6];
      const popupText = "<p>"+item[0] + " - " + item[1] + "<br/>Lat: " + lat.toFixed(2)+" / Lon: "+lon.toFixed(2)+"<br/>Epoch: "+ts+"</p>";
      var marker = L.circle(L.latLng(
        parseFloat(item[6]), // lon
        parseFloat(item[5])  // lat
      ), damsRadius).addTo(layerGroup).bindPopup(popupText)
      .on('popupopen', getIcao24)
      .on('popupclose', processPopupClose);
      marker._myID = item[0];
      if (item[0] == idPopup) {
        marker.openPopup();
        popupFound = true;
      }
      document.getElementById('ts').textContent = ts;
    }
    catch (e) {}
  }               
  if (!popupFound) idPopup = '';
  refreshInProgress = false;
}
4
  • 1
    @TimazlcM Thanks for your answer! It looks it works at the begninning but after one iteration it gets stuck and everything freezes so i have to close the browser. Have you tested it on your PC as well? do you encounter the same issue? PS: I found a very bad workaround to my problem and it does't get stuck but it is not very good programming practice what I did. Mar 29, 2020 at 19:49
  • 1
    Yes, I have tested it, not with your GeoJSON, but with some random markers. Since I have ES5 environment, my code was a bit different and I might have made some errors when constructing answer for your ES6 environment. Do you get any errors in the console?
    – TomazicM
    Mar 29, 2020 at 20:08
  • 1
    I noticed an error in the code and corrected it. It should be item[0], not item[0].id
    – TomazicM
    Mar 29, 2020 at 20:10
  • 1
    Perfect! Now it is great!! :) Thanks a lot @TomazicM Mar 30, 2020 at 7:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.