From 7789f8202f60f69ce015b1bc34eb0c076d7545b5 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Sun, 24 May 2020 18:38:08 +0200 Subject: animate train position in map --- lib/DBInfoscreen.pm | 1 + lib/DBInfoscreen/Controller/Map.pm | 475 +++++++++++++++++++++++++----------- public/static/js/map-refresh.js | 81 ++++++ public/static/js/map-refresh.min.js | 1 + templates/_error.html.ep | 5 + templates/_map_infobox.html.ep | 61 +++++ templates/layouts/app.html.ep | 1 + templates/route_map.html.ep | 59 +---- 8 files changed, 480 insertions(+), 204 deletions(-) create mode 100644 public/static/js/map-refresh.js create mode 100644 public/static/js/map-refresh.min.js create mode 100644 templates/_error.html.ep create mode 100644 templates/_map_infobox.html.ep diff --git a/lib/DBInfoscreen.pm b/lib/DBInfoscreen.pm index 1828737..e49ce70 100644 --- a/lib/DBInfoscreen.pm +++ b/lib/DBInfoscreen.pm @@ -315,6 +315,7 @@ sub startup { $r->get('/_wr/:train/:departure')->to('wagenreihung#wagenreihung'); + $r->get('/_ajax_mapinfo/:tripid/:lineno')->to('map#ajax_route'); $r->get('/map/:tripid/:lineno')->to('map#route'); $self->defaults( layout => 'app' ); diff --git a/lib/DBInfoscreen/Controller/Map.pm b/lib/DBInfoscreen/Controller/Map.pm index d618e8c..7013b63 100644 --- a/lib/DBInfoscreen/Controller/Map.pm +++ b/lib/DBInfoscreen/Controller/Map.pm @@ -10,8 +10,17 @@ use Geo::Distance; my $dbf_version = qx{git describe --dirty} || 'experimental'; +my $strp = DateTime::Format::Strptime->new( + pattern => '%Y-%m-%dT%H:%M:%S.000%z', + time_zone => 'Europe/Berlin', +); + chomp $dbf_version; +# Input: (HAFAS TripID, line number) +# Output: Promise returning a +# https://github.com/public-transport/hafas-client/blob/4/docs/trip.md instance +# on success sub get_hafas_polyline_p { my ( $self, $trip_id, $line ) = @_; @@ -63,7 +72,19 @@ sub get_hafas_polyline_p { return $promise; } -sub estimate_train_position { +# Input: +# now: DateTime +# from: current/previous stop +# {dep => DateTime, name => str, lat => float, lon => float} +# to: next stop +# {arr => DateTime, name => str, lat => float, lon => float} +# features: https://github.com/public-transport/hafas-client/blob/4/docs/trip.md features array +# Output: list of estimated train positions in [lat, lon] format. +# - current position +# - position 2 seconds from now +# - position 4 seconds from now +# - ... +sub estimate_train_positions { my (%opt) = @_; my $now = $opt{now}; @@ -74,8 +95,13 @@ sub estimate_train_position { my $to_name = $opt{to}{name}; my $features = $opt{features}; - my $route_part_completion_ratio - = ( $now->epoch - $from_dt->epoch ) / ( $to_dt->epoch - $from_dt->epoch ); + my @train_positions; + + my $time_complete = $now->epoch - $from_dt->epoch; + my $time_total = $to_dt->epoch - $from_dt->epoch; + + my @completion_ratios + = map { ( $time_complete + ( $_ * 2 ) ) / $time_total } ( 0 .. 45 ); my $geo = Geo::Distance->new; my ( $from_index, $to_index ); @@ -109,32 +135,214 @@ sub estimate_train_position { ); } } - my $marker_distance = $total_distance * $route_part_completion_ratio; + my @marker_distances = map { $total_distance * $_ } @completion_ratios; $total_distance = 0; for my $j ( $from_index + 1 .. $to_index ) { my $prev = $features->[ $j - 1 ]{geometry}{coordinates}; my $this = $features->[$j]{geometry}{coordinates}; if ( $prev and $this ) { + my $prev_distance = $total_distance; $total_distance += $geo->distance( 'kilometer', $prev->[0], $prev->[1], $this->[0], $this->[1] ); - } - if ( $total_distance > $marker_distance ) { + for my $i ( @train_positions .. $#marker_distances ) { + my $marker_distance = $marker_distances[$i]; + if ( $total_distance > $marker_distance ) { + + # completion ratio for the line between (prev, this) + my $sub_ratio = 1; + if ( $total_distance != $prev_distance ) { + $sub_ratio = ( $marker_distance - $prev_distance ) + / ( $total_distance - $prev_distance ); + } - # return (lat, lon) - return ( $this->[1], $this->[0] ); + my $lat = $prev->[1] + + ( $this->[1] - $prev->[1] ) * $sub_ratio; + my $lon = $prev->[0] + + ( $this->[0] - $prev->[0] ) * $sub_ratio; + + push( @train_positions, [ $lat, $lon ] ); + } + } + if ( @train_positions == @completion_ratios ) { + return @train_positions; + } } } + if (@train_positions) { + return @train_positions; + } } else { - my $lat = $opt{from}{lat} - + ( $opt{to}{lat} - $opt{from}{lat} ) * $route_part_completion_ratio; - my $lon = $opt{from}{lon} - + ( $opt{to}{lon} - $opt{from}{lon} ) * $route_part_completion_ratio; - return ( $lat, $lon ); + for my $ratio (@completion_ratios) { + my $lat + = $opt{from}{lat} + ( $opt{to}{lat} - $opt{from}{lat} ) * $ratio; + my $lon + = $opt{from}{lon} + ( $opt{to}{lon} - $opt{from}{lon} ) * $ratio; + push( @train_positions, [ $lat, $lon ] ); + } + return @train_positions; + } + return [ $opt{to}{lat}, $opt{to}{lon} ]; +} + +# Input: +# now: DateTime +# route: hash +# lat: float +# lon: float +# name: str +# arr: DateTime +# dep: DateTime +# features: ref to transport.rest features list +# Output: +# next_stop: {type, station} +# positions: [current position [lat, lon], 2s from now, 4s from now, ...] +sub estimate_train_positions2 { + my (%opt) = @_; + my $now = $opt{now}; + my @route = @{ $opt{route} // [] }; + + my @train_positions; + my $next_stop; + + for my $i ( 1 .. $#route ) { + if ( $route[$i]{arr} + and $route[ $i - 1 ]{dep} + and $now > $route[ $i - 1 ]{dep} + and $now < $route[$i]{arr} ) + { + + # (current position, future positons...) in 2 second steps + @train_positions = estimate_train_positions( + from => $route[ $i - 1 ], + to => $route[$i], + now => $now, + features => $opt{features}, + ); + + $next_stop = { + type => 'next', + station => $route[$i], + }; + last; + } + if ( $route[ $i - 1 ]{dep} and $now <= $route[ $i - 1 ]{dep} ) { + @train_positions + = ( [ $route[ $i - 1 ]{lat}, $route[ $i - 1 ]{lon} ] ); + $next_stop = { + type => 'present', + station => $route[ $i - 1 ], + }; + last; + } } - return ( $opt{to}{lat}, $opt{to}{lon} ); + + if ( not $next_stop ) { + @train_positions = ( [ $route[-1]{lat}, $route[-1]{lon} ] ); + $next_stop = { + type => 'present', + station => $route[-1] + }; + } + + my $position_now = shift @train_positions; + + return { + next_stop => $next_stop, + position_now => $position_now, + positions => \@train_positions, + }; +} + +sub route_to_ajax { + my (@stopovers) = @_; + + my @route_entries; + + for my $stop (@stopovers) { + my @stop_entries = ( $stop->{stop}{name} ); + my $platform; + + if ( $stop->{arrival} + and my $arr = $strp->parse_datetime( $stop->{arrival} ) ) + { + my $delay = ( $stop->{arrivalDelay} // 0 ) / 60; + $platform = $stop->{arrivalPlatform}; + + push( @stop_entries, $arr->epoch, $delay ); + } + else { + push( @stop_entries, q{}, q{} ); + } + + if ( $stop->{departure} + and my $dep = $strp->parse_datetime( $stop->{departure} ) ) + { + my $delay = ( $stop->{departureDelay} // 0 ) / 60; + $platform //= $stop->{departurePlatform} // q{}; + + push( @stop_entries, $dep->epoch, $delay, $platform ); + } + else { + push( @stop_entries, q{}, q{}, q{} ); + } + + push( @route_entries, join( ';', @stop_entries ) ); + } + + return join( '|', @route_entries ); +} + +# Input: List of transport.rest stopovers +# Output: List of preprocessed stops. Each is a hash with the following keys: +# lat: float +# lon: float +# name: str +# arr: DateTime +# dep: DateTime +# arr_delay: int +# dep_delay: int +# platform: str +sub stopovers_to_route { + my (@stopovers) = @_; + my @route; + + for my $stop (@stopovers) { + my @stop_lines = ( $stop->{stop}{name} ); + my ( $platform, $arr, $dep, $arr_delay, $dep_delay ); + + if ( $stop->{arrival} + and $arr = $strp->parse_datetime( $stop->{arrival} ) ) + { + $arr_delay = ( $stop->{arrivalDelay} // 0 ) / 60; + $platform //= $stop->{arrivalPlatform}; + } + + if ( $stop->{departure} + and $dep = $strp->parse_datetime( $stop->{departure} ) ) + { + $dep_delay = ( $stop->{departureDelay} // 0 ) / 60; + $platform //= $stop->{departurePlatform}; + } + + push( + @route, + { + lat => $stop->{stop}{location}{latitude}, + lon => $stop->{stop}{location}{longitude}, + name => $stop->{stop}{name}, + arr => $arr, + dep => $dep, + arr_delay => $arr_delay, + dep_delay => $dep_delay, + platform => $platform, + } + ); + + } + return @route; } sub route { @@ -154,17 +362,13 @@ sub route { my @polyline = @{ $pl->{polyline} }; my @line_pairs; my @station_coordinates; - my @route; my @markers; my $next_stop; - my $now = DateTime->now( time_zone => 'Europe/Berlin' ); - my $strp = DateTime::Format::Strptime->new( - pattern => '%Y-%m-%dT%H:%M:%S.000%z', - time_zone => 'Europe/Berlin', - ); + my $now = DateTime->now( time_zone => 'Europe/Berlin' ); + # @line_pairs are used to draw the train's journey on the map for my $i ( 1 .. $#polyline ) { push( @line_pairs, @@ -175,164 +379,85 @@ sub route { ); } - for my $stop ( @{ $pl->{raw}{stopovers} // [] } ) { - my @stop_lines = ( $stop->{stop}{name} ); - my ( $platform, $arr, $dep, $arr_delay, $dep_delay ); + my @route = stopovers_to_route( @{ $pl->{raw}{stopovers} // [] } ); + + # Prepare from/to markers and name/time/delay overlays for stations + for my $stop (@route) { + my @stop_lines = ( $stop->{name} ); - if ( $from_name and $stop->{stop}{name} eq $from_name ) { + if ( $from_name and $stop->{name} eq $from_name ) { push( @markers, { - lon => $stop->{stop}{location}{longitude}, - lat => $stop->{stop}{location}{latitude}, - title => $stop->{stop}{name}, + lon => $stop->{lon}, + lat => $stop->{lat}, + title => $stop->{name}, icon => 'goldIcon', } ); } - if ( $to_name and $stop->{stop}{name} eq $to_name ) { + if ( $to_name and $stop->{name} eq $to_name ) { push( @markers, { - lon => $stop->{stop}{location}{longitude}, - lat => $stop->{stop}{location}{latitude}, - title => $stop->{stop}{name}, + lon => $stop->{lon}, + lat => $stop->{lat}, + title => $stop->{name}, icon => 'greenIcon', } ); } - if ( $stop->{arrival} - and $arr = $strp->parse_datetime( $stop->{arrival} ) ) - { - $arr_delay = ( $stop->{arrivalDelay} // 0 ) / 60; - $platform //= $stop->{arrivalPlatform}; - my $arr_line = $arr->strftime('Ankunft: %H:%M'); - if ($arr_delay) { - $arr_line .= sprintf( ' (%+d)', $arr_delay ); + if ( $stop->{platform} ) { + push( @stop_lines, 'Gleis ' . $stop->{platform} ); + } + if ( $stop->{arr} ) { + my $arr_line = $stop->{arr}->strftime('Ankunft: %H:%M'); + if ( $stop->{arr_delay} ) { + $arr_line .= sprintf( ' (%+d)', $stop->{arr_delay} ); } push( @stop_lines, $arr_line ); } - - if ( $stop->{departure} - and $dep = $strp->parse_datetime( $stop->{departure} ) ) - { - $dep_delay = ( $stop->{departureDelay} // 0 ) / 60; - $platform //= $stop->{departurePlatform}; - my $dep_line = $dep->strftime('Abfahrt: %H:%M'); - if ($dep_delay) { - $dep_line .= sprintf( ' (%+d)', $dep_delay ); + if ( $stop->{dep} ) { + my $dep_line = $stop->{dep}->strftime('Abfahrt: %H:%M'); + if ( $stop->{dep_delay} ) { + $dep_line .= sprintf( ' (%+d)', $stop->{dep_delay} ); } push( @stop_lines, $dep_line ); } - if ($platform) { - splice( @stop_lines, 1, 0, "Gleis $platform" ); - } - - push( - @station_coordinates, - [ - [ - $stop->{stop}{location}{latitude}, - $stop->{stop}{location}{longitude} - ], - [@stop_lines], - ] - ); - push( - @route, - { - lat => $stop->{stop}{location}{latitude}, - lon => $stop->{stop}{location}{longitude}, - name => $stop->{stop}{name}, - arr => $arr, - dep => $dep, - arr_delay => $arr_delay, - dep_delay => $dep_delay, - platform => $platform, - } - ); - + push( @station_coordinates, + [ [ $stop->{lat}, $stop->{lon} ], [@stop_lines], ] ); } - for my $i ( 1 .. $#route ) { - if ( $route[$i]{arr} - and $route[ $i - 1 ]{dep} - and $now > $route[ $i - 1 ]{dep} - and $now < $route[$i]{arr} ) - { - - my $title = $pl->{name}; - if ( $route[$i]{arr_delay} ) { - $title .= sprintf( ' (%+d)', $route[$i]{arr_delay} ); - } - - my ( $train_lat, $train_lon ) = estimate_train_position( - from => $route[ $i - 1 ], - to => $route[$i], - now => $now, - features => $pl->{raw}{polyline}{features}, - ); - - push( - @markers, - { - lat => $train_lat, - lon => $train_lon, - title => $title - } - ); + my $train_pos = estimate_train_positions2( + now => $now, + route => \@route, + features => $pl->{raw}{polyline}{features}, + ); - $next_stop = { - type => 'next', - station => $route[$i], - }; - last; - } - if ( $route[ $i - 1 ]{dep} and $now <= $route[ $i - 1 ]{dep} ) { - my $title = $pl->{name}; - if ( $route[$i]{arr_delay} ) { - $title .= sprintf( ' (%+d)', $route[$i]{arr_delay} ); - } - push( - @markers, - { - lat => $route[ $i - 1 ]{lat}, - lon => $route[ $i - 1 ]{lon}, - title => $title - } - ); - $next_stop = { - type => 'present', - station => $route[ $i - 1 ], - }; - last; + push( + @markers, + { + lat => $train_pos->{position_now}[0], + lon => $train_pos->{position_now}[1], + title => $pl->{name} } - } - if ( not @markers ) { - push( - @markers, - { - lat => $route[-1]{lat}, - lon => $route[-1]{lon}, - title => $route[-1]{name} . ' - Endstation', - } - ); - $next_stop = { - type => 'present', - station => $route[-1] - }; - } + ); + $next_stop = $train_pos->{next_stop}; $self->render( 'route_map', - title => $pl->{name}, - hide_opts => 1, - with_map => 1, - origin => { + title => $pl->{name}, + hide_opts => 1, + with_map => 1, + ajax_req => "${trip_id}/${line_no}", + ajax_route => route_to_ajax( @{ $pl->{raw}{stopovers} // [] } ), + ajax_polyline => join( '|', + map { join( ';', @{$_} ) } @{ $train_pos->{positions} } ), + origin => { name => $pl->{raw}{origin}{name}, - ts => $pl->{raw}{dep_line} + ts => $pl->{raw}{departure} ? scalar $strp->parse_datetime( $pl->{raw}{departure} ) : undef, }, @@ -374,4 +499,60 @@ sub route { )->wait; } +sub ajax_route { + my ($self) = @_; + my $trip_id = $self->stash('tripid'); + my $line_no = $self->stash('lineno'); + + delete $self->stash->{layout}; + + $self->render_later; + + $self->get_hafas_polyline_p( $trip_id, $line_no )->then( + sub { + my ($pl) = @_; + + my $now = DateTime->now( time_zone => 'Europe/Berlin' ); + + my @route = stopovers_to_route( @{ $pl->{raw}{stopovers} // [] } ); + + my $train_pos = estimate_train_positions2( + now => $now, + route => \@route, + features => $pl->{raw}{polyline}{features}, + ); + + my @polyline = @{ $pl->{polyline} }; + $self->render( + '_map_infobox', + ajax_req => "${trip_id}/${line_no}", + ajax_route => route_to_ajax( @{ $pl->{raw}{stopovers} // [] } ), + ajax_polyline => join( '|', + map { join( ';', @{$_} ) } @{ $train_pos->{positions} } ), + origin => { + name => $pl->{raw}{origin}{name}, + ts => $pl->{raw}{departure} + ? scalar $strp->parse_datetime( $pl->{raw}{departure} ) + : undef, + }, + destination => { + name => $pl->{raw}{destination}{name}, + ts => $pl->{raw}{arrival} + ? scalar $strp->parse_datetime( $pl->{raw}{arrival} ) + : undef, + }, + next_stop => $train_pos->{next_stop}, + ); + } + )->catch( + sub { + my ($err) = @_; + $self->render( + '_error', + error => $err, + ); + } + )->wait; +} + 1; diff --git a/public/static/js/map-refresh.js b/public/static/js/map-refresh.js new file mode 100644 index 0000000..b1729c3 --- /dev/null +++ b/public/static/js/map-refresh.js @@ -0,0 +1,81 @@ +var j_reqid; +//var j_stops = []; +var j_positions = []; +var j_frame = []; +var j_frame_i = []; + +function dbf_map_parse() { + $('#jdata').each(function() { + j_reqid = $(this).data('req'); + /*var route_data = $(this).data('route'); + if (route_data) { + route_data = route_data.split('|'); + j_stops = []; + for (var stop_id in route_data) { + var stopdata = route_data[stop_id].split(';'); + for (var i = 1; i < 5; i++) { + stopdata[i] = parseInt(stopdata[i]); + } + j_stops.push(stopdata); + } + }*/ + var positions = $(this).data('poly'); + if (positions) { + positions = positions.split('|'); + j_positions = []; + for (var pos_id in positions) { + var posdata = positions[pos_id].split(';'); + posdata[0] = parseFloat(posdata[0]); + posdata[1] = parseFloat(posdata[1]); + j_positions.push(posdata); + } + } + }); +} + +function dbf_anim_coarse() { + if (j_positions.length) { + var pos1 = marker.getLatLng(); + var pos1lat = pos1.lat; + var pos1lon = pos1.lng; + var pos2 = j_positions.shift(); + var pos2lat = pos2[0]; + var pos2lon = pos2[1]; + + j_frame_i = 200; + j_frame = []; + + // approx 30 Hz -> 60 frames per 2 seconds + for (var i = 1; i <= 60; i++) { + var ratio = i / 60; + j_frame.push([pos1lat + ((pos2lat - pos1lat) * ratio), pos1lon + ((pos2lon - pos1lon) * ratio)]); + } + + j_frame_i = 0; + } +} + +function dbf_anim_fine() { + if (j_frame[j_frame_i]) { + marker.setLatLng(j_frame[j_frame_i++]); + } +} + +function dbf_map_reload() { + $.get('/_ajax_mapinfo/' + j_reqid, function(data) { + $('#infobox').html(data); + dbf_map_parse(); + setTimeout(dbf_map_reload, 61000); + }).fail(function() { + setTimeout(dbf_map_reload, 5000); + }); +} + +$(document).ready(function() { + if ($('#infobox').length) { + dbf_map_parse(); + setInterval(dbf_anim_coarse, 2000); + setInterval(dbf_anim_fine, 33); + setTimeout(dbf_map_reload, 61000); + } +}); diff --git a/public/static/js/map-refresh.min.js b/public/static/js/map-refresh.min.js new file mode 100644 index 0000000..802d376 --- /dev/null +++ b/public/static/js/map-refresh.min.js @@ -0,0 +1 @@ +function dbf_map_parse(){$("#jdata").each(function(){j_reqid=$(this).data("req");var a=$(this).data("poly");if(a){a=a.split("|"),j_positions=[];for(var e in a){var i=a[e].split(";");i[0]=parseFloat(i[0]),i[1]=parseFloat(i[1]),j_positions.push(i)}}})}function dbf_anim_coarse(){if(j_positions.length){var a=marker.getLatLng(),e=a.lat,i=a.lng,_=j_positions.shift(),t=_[0],r=_[1];j_frame_i=200,j_frame=[];for(var f=1;f<=60;f++){var n=f/60;j_frame.push([e+(t-e)*n,i+(r-i)*n])}j_frame_i=0}}function dbf_anim_fine(){j_frame[j_frame_i]&&marker.setLatLng(j_frame[j_frame_i++])}function dbf_map_reload(){$.get("/_ajax_mapinfo/"+j_reqid,function(a){$("#infobox").html(a),dbf_map_parse(),setTimeout(dbf_map_reload,61e3)}).fail(function(){setTimeout(dbf_map_reload,5e3)})}var j_reqid,j_positions=[],j_frame=[],j_frame_i=[];$(document).ready(function(){$("#infobox").length&&(dbf_map_parse(),setInterval(dbf_anim_coarse,2e3),setInterval(dbf_anim_fine,33),setTimeout(dbf_map_reload,61e3))}); diff --git a/templates/_error.html.ep b/templates/_error.html.ep new file mode 100644 index 0000000..4abfb4e --- /dev/null +++ b/templates/_error.html.ep @@ -0,0 +1,5 @@ +
Fehler: +
+%= $error
+
+
diff --git a/templates/_map_infobox.html.ep b/templates/_map_infobox.html.ep new file mode 100644 index 0000000..8f66a6f --- /dev/null +++ b/templates/_map_infobox.html.ep @@ -0,0 +1,61 @@ +
+
+ Fahrt + % if (stash('train_no')) { + <%= stash('train_no') %> + % } + von <%= stash('origin')->{name} %> + nach <%= stash('destination')->{name} %> +
+% if (my $next = stash('next_stop')) { +
+ % if ($next->{type} eq 'present' and $next->{station}{dep} and $next->{station}{arr}) { + Aufenthalt in <%= $next->{station}{name} %> + an Gleis <%= $next->{station}{platform} %> + bis <%= $next->{station}{dep}->strftime('%H:%M') %> + % if ($next->{station}{dep_delay}) { + %= sprintf('(%+d)', $next->{station}{dep_delay}) + % } + % } + % elsif ($next->{type} eq 'present' and $next->{station}{dep}) { + Abfahrt in <%= $next->{station}{name} %> + von Gleis <%= $next->{station}{platform} %> + um <%= $next->{station}{dep}->strftime('%H:%M') %> + % if ($next->{station}{dep_delay}) { + %= sprintf('(%+d)', $next->{station}{dep_delay}) + % } + % } + % elsif ($next->{type} eq 'present' and $next->{station}{arr}) { + Endstation erreicht um + <%= $next->{station}{arr}->strftime('%H:%M') %> + auf Gleis <%= $next->{station}{platform} %> + % if ($next->{station}{arr_delay}) { + %= sprintf('(%+d)', $next->{station}{arr_delay}) + % } + % } + % elsif ($next->{type} eq 'present') { + Zug steht in + <%= $next->{station}{arr}->strftime('%H:%M') %> + auf Gleis <%= $next->{station}{platform} %> + % } + % elsif ($next->{type} eq 'next' and $next->{station}{arr}) { + Nächster Halt: + <%= $next->{station}{name} %> + um <%= $next->{station}{arr}->strftime('%H:%M') %> + % if ($next->{station}{arr_delay}) { + %= sprintf('(%+d)', $next->{station}{arr_delay}) + % } + auf Gleis <%= $next->{station}{platform} %> + % } + % elsif ($next->{type} eq 'next') { + Nächster Halt: + <%= $next->{station}{name} %> + auf Gleis <%= $next->{station}{platform} %> + % } +
+% } +
diff --git a/templates/layouts/app.html.ep b/templates/layouts/app.html.ep index d7320de..fc81ba3 100644 --- a/templates/layouts/app.html.ep +++ b/templates/layouts/app.html.ep @@ -61,6 +61,7 @@ % if (stash('with_map')) { %= stylesheet "/static/${av}/leaflet/leaflet.css" %= javascript "/static/${av}/leaflet/leaflet.js" + %= javascript "/static/${av}/js/map-refresh.min.js", defer => undef % } diff --git a/templates/route_map.html.ep b/templates/route_map.html.ep index 6ed1b57..6f5643b 100644 --- a/templates/route_map.html.ep +++ b/templates/route_map.html.ep @@ -1,58 +1,5 @@ % if ($origin and $destination) { -
- Fahrt - % if (stash('train_no')) { - <%= stash('train_no') %> - % } - von <%= $origin->{name} %> - nach <%= $destination->{name} %> - % if (my $next = stash('next_stop')) { -
- % if ($next->{type} eq 'present' and $next->{station}{dep} and $next->{station}{arr}) { - Aufenthalt in <%= $next->{station}{name} %> - an Gleis <%= $next->{station}{platform} %> - bis <%= $next->{station}{dep}->strftime('%H:%M') %> - % if ($next->{station}{dep_delay}) { - %= sprintf('(%+d)', $next->{station}{dep_delay}) - % } - % } - % elsif ($next->{type} eq 'present' and $next->{station}{dep}) { - Abfahrt in <%= $next->{station}{name} %> - von Gleis <%= $next->{station}{platform} %> - um <%= $next->{station}{dep}->strftime('%H:%M') %> - % if ($next->{station}{dep_delay}) { - %= sprintf('(%+d)', $next->{station}{dep_delay}) - % } - % } - % elsif ($next->{type} eq 'present' and $next->{station}{arr}) { - Endstation erreicht um - <%= $next->{station}{arr}->strftime('%H:%M') %> - auf Gleis <%= $next->{station}{platform} %> - % if ($next->{station}{arr_delay}) { - %= sprintf('(%+d)', $next->{station}{arr_delay}) - % } - % } - % elsif ($next->{type} eq 'present') { - Zug steht in - <%= $next->{station}{arr}->strftime('%H:%M') %> - auf Gleis <%= $next->{station}{platform} %> - % } - % elsif ($next->{type} eq 'next' and $next->{station}{arr}) { - Nächster Halt: - <%= $next->{station}{name} %> - um <%= $next->{station}{arr}->strftime('%H:%M') %> - % if ($next->{station}{arr_delay}) { - %= sprintf('(%+d)', $next->{station}{arr_delay}) - % } - auf Gleis <%= $next->{station}{platform} %> - % } - % elsif ($next->{type} eq 'next') { - Nächster Halt: - <%= $next->{station}{name} %> - auf Gleis <%= $next->{station}{platform} %> - % } - % } -
+ %= include '_map_infobox' % }
@@ -135,9 +82,7 @@ var marker; Die eingezeichnete Route stammt aus dem HAFAS und ist im Detail oft fehlerbehaftet.
Die Zugposition auf der Karte ist eine DBF-eigene Schätzung und kann erheblich -von der tatsächlichen Position des Zugs abweichen.
-Live-Tracking mit automatischer Kartenaktualisierung wird noch nicht -unterstützt. +von den tatsächlichen Gegebenheiten abweichen.
% if (my $op = stash('operator')) { -- cgit v1.2.3