<- Back

Self updating departure monitor with prediction delays.

Show the next departures on a station with predicted delays. In this example we auto-update the HTML-List and append, update or remove automatically the elements that has to change. The result is a self updating departure monitor that permanently shows you the current departures with delays.

Demo

Code excerpt

          
            jQuery(function($){
  const mobilitybox_access_token = 'aaddf669-8b4b-44ff-a2a3-ae70841e75fb';
  const mobilitybox = new Mobilitybox(mobilitybox_access_token);
  const departures_update_time_in_seconds = 10;

  mobilitybox.get_attributions().then((attributions)=>{
    $(".attributions").html(attributions.html);
  })

  mobilitybox.find_stations_by_name({query: "Hamburg-Dammtor"}).then((stations)=>{
    var station = stations[0];
    StationHTML(station).appendTo($(".departures"));

    init_fetch_departures_loop(station, departures_update_time_in_seconds);
  });
});

function init_fetch_departures_loop(station, departures_update_time_in_seconds){
  fetch_departures_and_update_list(station);
  setInterval(function(){
    fetch_departures_and_update_list(station);
  }, departures_update_time_in_seconds * 1000);
}

function fetch_departures_and_update_list(station){
  station.get_next_departures().then((departures)=>{
    add_or_update_departures_in_list(departures);
    remove_old_departures_from_list(departures);
  });
}

function add_or_update_departures_in_list(departures){
  departures.map((departure)=>{
    const $departure_html = DepartureHTML(departure);

    if (jQuery('#'+departure.id).length > 0){
      jQuery('#'+departure.id).replaceWith($departure_html)
    }else{
      $departure_html.appendTo(jQuery('.departures'));
    }
  })
}

function remove_old_departures_from_list(departures){
  const received_departure_ids = departures.map((departure)=>{
    return departure.id
  });

  jQuery('.departure').not('#'+received_departure_ids.join(', #')).remove();
}


function StationHTML(station){
  return jQuery(
    '<a href="#" class="list-group-item list-group-item-action active">'+
      '<div class="d-flex w-100 justify-content-between">'+
        '<h5 class="mb-1">'+station.name+'</h5>'+
      '</div>'+
    '</a>'
  )
}

function DepartureHTML(departure){
  const prediction_delay = (!departure.departure_time.predicted_at)?(0):(departure.departure_time.predicted_at-departure.departure_time.scheduled_at);
  const delay_minutes = Math.floor(prediction_delay / (1000*60 /*miliseconds*/));;
  const prediction_status_color = (delay_minutes >= 5)?'text-danger':'text-success';

  const prediction_delay_formatted = (!departure.departure_time.predicted_at)?'':(
    ((prediction_delay < 0)?'-':'+')+Math.abs(delay_minutes)
  );

  return jQuery(
    '<a href="#" class="departure list-group-item list-group-item-action" id="'+departure.id+'">'+
        '<div class="d-flex w-100 justify-content-between">'+
          '<div class="d-flex flex-column">'+
            '<h5 class="mb-1">'+departure.headsign+'</h5>'+
            '<p class="mb-1">'+departure.line_name+'</p>'+
            '<small>'+departure.provider+'</small>'+
          '</div>'+
          '<div class="d-flex flex-column">'+
            '<bold>'+departure.departure_time.scheduled_at_formatted()+'</bold>'+
            '<bold class="pl-1 '+prediction_status_color+'">'+prediction_delay_formatted+'</bold>'+
          '</div>'+
        '</div>'+
      '</a>'
  )
}
          
        

Full HTML-Code


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Self updating departure monitor with prediction delays.</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <!-- CSS only -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    
    <!-- JS, Popper.js, and jQuery -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/mobilitybox/dist/mobilitybox.min.js"></script>

    <style>
      body {
        background-color: silver;
      }
      
      .attributions {
        border-radius: 0 3px 0 0;
        background-color: white;
        border-left: 0;
        border-bottom: 0;
        padding: 5px;
        font-size: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-sm">
          <br />
          <div class="list-group departures"></div>
        </div>
      </div>
    </div>
    <span class="fixed-bottom">
      <span class="attributions border text-muted font-weight-light"></span>
    </span>

    <script type="text/javascript">
      jQuery(function($){
        const mobilitybox_access_token = 'aaddf669-8b4b-44ff-a2a3-ae70841e75fb';
        const mobilitybox = new Mobilitybox(mobilitybox_access_token);
        const departures_update_time_in_seconds = 10;
      
        mobilitybox.get_attributions().then((attributions)=>{
          $(".attributions").html(attributions.html);
        })
      
        mobilitybox.find_stations_by_name({query: "Hamburg-Dammtor"}).then((stations)=>{
          var station = stations[0];
          StationHTML(station).appendTo($(".departures"));
      
          init_fetch_departures_loop(station, departures_update_time_in_seconds);
        });
      });
      
      function init_fetch_departures_loop(station, departures_update_time_in_seconds){
        fetch_departures_and_update_list(station);
        setInterval(function(){
          fetch_departures_and_update_list(station);
        }, departures_update_time_in_seconds * 1000);
      }
      
      function fetch_departures_and_update_list(station){
        station.get_next_departures().then((departures)=>{
          add_or_update_departures_in_list(departures);
          remove_old_departures_from_list(departures);
        });
      }
      
      function add_or_update_departures_in_list(departures){
        departures.map((departure)=>{
          const $departure_html = DepartureHTML(departure);
      
          if (jQuery('#'+departure.id).length > 0){
            jQuery('#'+departure.id).replaceWith($departure_html)
          }else{
            $departure_html.appendTo(jQuery('.departures'));
          }
        })
      }
      
      function remove_old_departures_from_list(departures){
        const received_departure_ids = departures.map((departure)=>{
          return departure.id
        });
      
        jQuery('.departure').not('#'+received_departure_ids.join(', #')).remove();
      }
      
      
      function StationHTML(station){
        return jQuery(
          '<a href="#" class="list-group-item list-group-item-action active">'+
            '<div class="d-flex w-100 justify-content-between">'+
              '<h5 class="mb-1">'+station.name+'</h5>'+
            '</div>'+
          '</a>'
        )
      }
      
      function DepartureHTML(departure){
        const prediction_delay = (!departure.departure_time.predicted_at)?(0):(departure.departure_time.predicted_at-departure.departure_time.scheduled_at);
        const delay_minutes = Math.floor(prediction_delay / (1000*60 /*miliseconds*/));;
        const prediction_status_color = (delay_minutes >= 5)?'text-danger':'text-success';
      
        const prediction_delay_formatted = (!departure.departure_time.predicted_at)?'':(
          ((prediction_delay < 0)?'-':'+')+Math.abs(delay_minutes)
        );
      
        return jQuery(
          '<a href="#" class="departure list-group-item list-group-item-action" id="'+departure.id+'">'+
              '<div class="d-flex w-100 justify-content-between">'+
                '<div class="d-flex flex-column">'+
                  '<h5 class="mb-1">'+departure.headsign+'</h5>'+
                  '<p class="mb-1">'+departure.line_name+'</p>'+
                  '<small>'+departure.provider+'</small>'+
                '</div>'+
                '<div class="d-flex flex-column">'+
                  '<bold>'+departure.departure_time.scheduled_at_formatted()+'</bold>'+
                  '<bold class="pl-1 '+prediction_status_color+'">'+prediction_delay_formatted+'</bold>'+
                '</div>'+
              '</div>'+
            '</a>'
        )
      }
    </script>
  </body>
</html>