gtfs-to-html 2.9.0 → 2.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config-sample.json +68 -0
- package/dist/app/index.js +2 -1
- package/dist/app/index.js.map +1 -1
- package/dist/bin/gtfs-to-html.js +16 -9
- package/dist/bin/gtfs-to-html.js.map +1 -1
- package/dist/index.js +16 -9
- package/dist/index.js.map +1 -1
- package/docker/Dockerfile +14 -0
- package/docker/README.md +5 -0
- package/docker/config.json +21 -0
- package/docker/docker-compose.yml +10 -0
- package/examples/stop_attributes.txt +6 -0
- package/examples/timetable_notes.txt +8 -0
- package/examples/timetable_notes_references.txt +8 -0
- package/examples/timetable_pages.txt +3 -0
- package/examples/timetable_stop_order.txt +16 -0
- package/examples/timetables.txt +9 -0
- package/package.json +8 -3
- package/views/default/css/overview_styles.css +198 -0
- package/views/default/css/timetable_pdf_styles.css +69 -0
- package/views/default/css/timetable_styles.css +522 -0
- package/views/default/formatting_functions.pug +104 -0
- package/views/default/js/system-map.js +594 -0
- package/views/default/js/timetable-map.js +753 -0
- package/views/default/js/timetable-menu.js +57 -0
- package/views/default/layout.pug +11 -0
- package/views/default/overview.pug +27 -0
- package/views/default/overview_full.pug +16 -0
- package/views/default/timetable_continuation_as.pug +7 -0
- package/views/default/timetable_continuation_from.pug +7 -0
- package/views/default/timetable_horizontal.pug +42 -0
- package/views/default/timetable_hourly.pug +30 -0
- package/views/default/timetable_map.pug +15 -0
- package/views/default/timetable_menu.pug +48 -0
- package/views/default/timetable_note_symbol.pug +5 -0
- package/views/default/timetable_stop_name.pug +13 -0
- package/views/default/timetable_stoptime.pug +17 -0
- package/views/default/timetable_vertical.pug +67 -0
- package/views/default/timetablepage.pug +64 -0
- package/views/default/timetablepage_full.pug +25 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* global window, document, $, maps */
|
|
2
|
+
/* eslint no-unused-vars: "off" */
|
|
3
|
+
|
|
4
|
+
$(() => {
|
|
5
|
+
showSelectedTimetable();
|
|
6
|
+
|
|
7
|
+
$('#day_list_selector input[name="dayList"]').change(() => {
|
|
8
|
+
showSelectedTimetable();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
$('#direction_name_selector input[name="directionName"]').change(() => {
|
|
12
|
+
showSelectedTimetable();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function showSelectedTimetable() {
|
|
16
|
+
if ($('.timetable').length === 1) {
|
|
17
|
+
showTimetable($('.timetable').data('timetable-id'));
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
$('#day_list_selector input[name="dayList"]').each((index, element) => {
|
|
22
|
+
$(element)
|
|
23
|
+
.parents('label')
|
|
24
|
+
.toggleClass('btn-blue', $(element).is(':checked'));
|
|
25
|
+
$(element)
|
|
26
|
+
.parents('label')
|
|
27
|
+
.toggleClass('btn-gray', $(element).is(':not(:checked)'));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
$('#direction_name_selector input[name="directionName"]').each(
|
|
31
|
+
(index, element) => {
|
|
32
|
+
$(element)
|
|
33
|
+
.parents('label')
|
|
34
|
+
.toggleClass('btn-blue', $(element).is(':checked'));
|
|
35
|
+
$(element)
|
|
36
|
+
.parents('label')
|
|
37
|
+
.toggleClass('btn-gray', $(element).is(':not(:checked)'));
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const dayList = $('#day_list_selector input[name="dayList"]:checked').val();
|
|
42
|
+
const directionName = $(
|
|
43
|
+
'#direction_name_selector input[name="directionName"]:checked',
|
|
44
|
+
).val();
|
|
45
|
+
|
|
46
|
+
$('.timetable').hide();
|
|
47
|
+
const id = $(
|
|
48
|
+
`.timetable[data-day-list="${dayList}"][data-direction-name="${directionName}"]`,
|
|
49
|
+
).data('timetable-id');
|
|
50
|
+
showTimetable(id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function showTimetable(id) {
|
|
54
|
+
$(`#timetable_id_${id}`).show();
|
|
55
|
+
toggleMap(id);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
include formatting_functions.pug
|
|
2
|
+
|
|
3
|
+
.timetable-overview
|
|
4
|
+
if !timetablePages || !timetablePages.length
|
|
5
|
+
h1 No timetables found
|
|
6
|
+
else
|
|
7
|
+
.overview-list
|
|
8
|
+
each timetablePageGroup in getAgencyTimetableGroups(timetablePages, agencies)
|
|
9
|
+
h1= `${!agency || !agency.agency_name ? '' : agency.agency_name} Routes`
|
|
10
|
+
each timetablePage in timetablePageGroup.timetablePages
|
|
11
|
+
if config.allowEmptyTimetables || timetablePage.consolidatedTimetables.length > 0
|
|
12
|
+
a.timetable-page-link(href=`${timetablePage.relativePath}` data-route-ids=`${timetablePage.route_ids ? timetablePage.route_ids.join(',') : ''}`)
|
|
13
|
+
- const timetableRouteList = _.uniqBy(_.flatMap(timetablePage.consolidatedTimetables, timetable => timetable.routes), 'route_id')
|
|
14
|
+
each route in timetableRouteList
|
|
15
|
+
.route-color-swatch-large(style=`background-color: ${formatRouteColor(route)}; color: ${formatRouteTextColor(route)};`)= route.route_short_name || ''
|
|
16
|
+
div
|
|
17
|
+
.timetable-page-label= timetablePage.timetable_page_label || timetableRouteList.map(route => formatRouteName(route)).join(' and ')
|
|
18
|
+
.badge-gray= timetablePage.dayList
|
|
19
|
+
if config.showMap
|
|
20
|
+
#system_map.overview-map
|
|
21
|
+
|
|
22
|
+
//- Use !{variable} format to inject values from pug to client side js
|
|
23
|
+
script.
|
|
24
|
+
(function() {
|
|
25
|
+
const geojson = !{JSON.stringify(geojson) || '\'\''};
|
|
26
|
+
createSystemMap('system_map', geojson);
|
|
27
|
+
})();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
extends layout
|
|
2
|
+
block content
|
|
3
|
+
include overview.pug
|
|
4
|
+
|
|
5
|
+
block extraHeader
|
|
6
|
+
if config.showMap
|
|
7
|
+
script(src="https://unpkg.com/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous")
|
|
8
|
+
script(src="https://unpkg.com/lodash@4.17.21/lodash.min.js" crossorigin="anonymous")
|
|
9
|
+
script(src="https://api.mapbox.com/mapbox-gl-js/v3.6.0/mapbox-gl.js")
|
|
10
|
+
script.
|
|
11
|
+
mapboxgl.accessToken = '#{config.mapboxAccessToken}';
|
|
12
|
+
script(src=`${config.assetPath}js/system-map.js`)
|
|
13
|
+
|
|
14
|
+
link(href="https://api.mapbox.com/mapbox-gl-js/v3.6.0/mapbox-gl.css" rel="stylesheet")
|
|
15
|
+
|
|
16
|
+
link(rel="stylesheet" href=`${config.assetPath}css/overview_styles.css`)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
- const routeColorCss = trip.continues_as_route ? getRouteColorsAsCss(trip.continues_as_route.route) : ''
|
|
2
|
+
td.run-footer(style=routeColorCss)
|
|
3
|
+
if trip.continues_as_route
|
|
4
|
+
if trip.continues_as_route.route.route_url
|
|
5
|
+
a.continues-as-route(href=`${trip.continues_as_route.route.route_url}` style=routeColorCss data-trip-id=trip.continues_as_route.trip_id)= trip.continues_as_route.route.route_short_name
|
|
6
|
+
else
|
|
7
|
+
.continues-as-route(data-trip-id=trip.continues_as_route.trip_id)= trip.continues_as_route.route.route_short_name
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
- const routeColorCss = trip.continues_from_route ? getRouteColorsAsCss(trip.continues_from_route.route) : ''
|
|
2
|
+
td.run-footer(style=routeColorCss)
|
|
3
|
+
if trip.continues_from_route
|
|
4
|
+
if trip.continues_from_route.route.route_url
|
|
5
|
+
a.continues-from-route(href=`${trip.continues_from_route.route.route_url}` style=routeColorCss data-trip-id=trip.continues_from_route.trip_id)= trip.continues_from_route.route.route_short_name
|
|
6
|
+
else
|
|
7
|
+
.continues-from-route(data-trip-id=trip.continues_from_route.trip_id)= trip.continues_from_route.route.route_short_name
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.table-container
|
|
2
|
+
table.table-horizontal(summary=`This table shows schedules for a selection of key stops on the route for ${timetable.timetable_label} ${timetable.dayList}. Schedule times are listed in rows, starting with the stop name in the first cell of the row.` data-orientation="horizontal")
|
|
3
|
+
caption.sr-only= `${timetable.timetable_label} | ${timetable.dayList}`
|
|
4
|
+
colgroup
|
|
5
|
+
col
|
|
6
|
+
each trip, idx in timetable.orderedTrips
|
|
7
|
+
col(id=`trip_id_${formatHtmlId(trip.trip_id)}` class=`run_${idx} ${(trip.trip_short_name) ? 'trip_short_name_' + trip.trip_short_name : ''}`)
|
|
8
|
+
thead
|
|
9
|
+
tr
|
|
10
|
+
th.stop-header(scope="col") Stop
|
|
11
|
+
each trip, idx in timetable.orderedTrips
|
|
12
|
+
th.run-header(scope="col")= formatTripName(trip, idx, timetable)
|
|
13
|
+
each note in getNotesForTrip(timetable.notes, trip)
|
|
14
|
+
include timetable_note_symbol.pug
|
|
15
|
+
if timetable.frequencies && !timetable.frequencyExactTimes
|
|
16
|
+
tr.trip-row
|
|
17
|
+
td.trip-frequency(colspan=`${timetable.orderedTrips.length + 1}`)!= formatFrequencyWarning(timetable.frequencies)
|
|
18
|
+
tbody
|
|
19
|
+
if timetable.has_continues_from_route
|
|
20
|
+
tr.continues-from-row
|
|
21
|
+
th Continues from route
|
|
22
|
+
each trip in timetable.orderedTrips
|
|
23
|
+
include timetable_continuation_from.pug
|
|
24
|
+
- let previousCity = null;
|
|
25
|
+
each stop in timetable.stops
|
|
26
|
+
if stop.stop_city !== '' && previousCity !== stop.stop_city && config.showStopCity
|
|
27
|
+
tr.city-row
|
|
28
|
+
th(scope="row" colspan=`${stop.trips.length + 1}`)= stop.stop_city
|
|
29
|
+
- previousCity = stop.stop_city
|
|
30
|
+
|
|
31
|
+
tr.stop-row(id=`stop_id_${formatHtmlId(stop.stop_id)}` data-stop-id=`${stop.stop_id}` data-is-timepoint=`${stop.is_timepoint}`)
|
|
32
|
+
th.stop-name-container(scope="row")
|
|
33
|
+
include timetable_stop_name.pug
|
|
34
|
+
|
|
35
|
+
each stoptime in stop.trips
|
|
36
|
+
include timetable_stoptime.pug
|
|
37
|
+
|
|
38
|
+
if timetable.has_continues_as_route
|
|
39
|
+
tr.continues-as-row
|
|
40
|
+
th Continues as route
|
|
41
|
+
each trip in timetable.orderedTrips
|
|
42
|
+
include timetable_continuation_as.pug
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.table-container
|
|
2
|
+
table.table-hourly(summary=`This table shows schedules for a selection of key stops on the route for ${timetable.timetable_label} ${timetable.dayList}. Schedule times are listed in rows, starting with the stop name in the first cell of the row and the minutes after the hour in the second row.` data-orientation="hourly")
|
|
3
|
+
caption.sr-only= `${timetable.timetable_label} | ${timetable.dayList}`
|
|
4
|
+
thead
|
|
5
|
+
tr
|
|
6
|
+
th.stop-header(scope="col") Stop
|
|
7
|
+
th(scope="col") Minutes after the hour
|
|
8
|
+
|
|
9
|
+
tbody
|
|
10
|
+
if timetable.frequencies && !timetable.frequencyExactTimes
|
|
11
|
+
tr.trip-row
|
|
12
|
+
td.trip-frequency(colspan="2")!= formatFrequencyWarning(timetable.frequencies)
|
|
13
|
+
- let previousCity
|
|
14
|
+
each stop in timetable.stops
|
|
15
|
+
if previousCity !== stop.stop_city && config.showStopCity
|
|
16
|
+
tr.city-row
|
|
17
|
+
th(scope="row" colspan="2")= stop.stop_city
|
|
18
|
+
- previousCity = stop.stop_city
|
|
19
|
+
|
|
20
|
+
tr.stop-row(id=`stop_id_${formatHtmlId(stop.stop_id)}` data-stop-id=`${stop.stop_id}`)
|
|
21
|
+
th.stop-name-container(scope="row")
|
|
22
|
+
include timetable_stop_name.pug
|
|
23
|
+
|
|
24
|
+
td.stop-time= stop.hourlyTimes.join(', ')
|
|
25
|
+
|
|
26
|
+
- const firstStop = timetable.stops[0]
|
|
27
|
+
- const firstTripStartTime = firstStop.trips[0]
|
|
28
|
+
- const lastStop = timetable.stops[timetable.stops.length - 1]
|
|
29
|
+
- const lastTripEndTime = lastStop.trips[lastStop.trips.length - 1]
|
|
30
|
+
.table-hourly-notes!= `Service begins at ${firstStop.stop_name} at ${firstTripStartTime.formatted_time} and ends at ${lastStop.stop_name} at ${lastTripEndTime.formatted_time}.`
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.map-container
|
|
2
|
+
.map(id=`map_timetable_id_${formatHtmlId(timetable.timetable_id)}`)
|
|
3
|
+
.map-legend
|
|
4
|
+
.legend-item
|
|
5
|
+
.legend-icon
|
|
6
|
+
.stop-marker
|
|
7
|
+
.legend-text
|
|
8
|
+
<b>Stops</b>
|
|
9
|
+
.legend-item.vehicle-legend-item(style="display: none;")
|
|
10
|
+
.legend-icon
|
|
11
|
+
.vehicle-marker
|
|
12
|
+
.vehicle-marker-arrow
|
|
13
|
+
.legend-text
|
|
14
|
+
<b>Current Vehicle Locations</b><br />
|
|
15
|
+
<small>Hover or tap to see arrival times.</small>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
if timetablePage.consolidatedTimetables.length > 1
|
|
2
|
+
if config.menuType === 'simple'
|
|
3
|
+
ul.timetable-simple-menu
|
|
4
|
+
- const showTimetableLabel = timetablePageHasDifferentLabels(timetablePage);
|
|
5
|
+
- const showDayList = timetablePageHasDifferentDays(timetablePage);
|
|
6
|
+
each timetable in timetablePage.consolidatedTimetables
|
|
7
|
+
li
|
|
8
|
+
a(href=`#timetable_id_${timetable.timetable_id}`)
|
|
9
|
+
if showTimetableLabel
|
|
10
|
+
span= timetable.timetable_label
|
|
11
|
+
if showTimetableLabel && showDayList
|
|
12
|
+
span |
|
|
13
|
+
if showDayList
|
|
14
|
+
span= timetable.dayListLong
|
|
15
|
+
|
|
16
|
+
if config.menuType === 'jump'
|
|
17
|
+
-
|
|
18
|
+
const groupedTimetables = timetablePage.consolidatedTimetables.reduce((memo, timetable) => {
|
|
19
|
+
if (!memo.hasOwnProperty(timetable.dayList)) {
|
|
20
|
+
memo[timetable.dayList] = []
|
|
21
|
+
}
|
|
22
|
+
memo[timetable.dayList].push(timetable);
|
|
23
|
+
return memo;
|
|
24
|
+
}, {});
|
|
25
|
+
.timetable-jump-menu
|
|
26
|
+
each group, dayList in groupedTimetables
|
|
27
|
+
div
|
|
28
|
+
h3= dayList
|
|
29
|
+
each timetable in group
|
|
30
|
+
a.btn-blue(href=`#timetable_id_${timetable.timetable_id}`)= timetable.timetable_label
|
|
31
|
+
|
|
32
|
+
if config.menuType === 'radio'
|
|
33
|
+
.timetable-radio-menu
|
|
34
|
+
-const directionNames = _.uniq(timetablePage.consolidatedTimetables.map(timetable => timetable.direction_name));
|
|
35
|
+
div(hidden=directionNames.length <= 1)
|
|
36
|
+
#direction_name_selector
|
|
37
|
+
h3 Service Direction
|
|
38
|
+
each directionName, idx in directionNames
|
|
39
|
+
label(class=idx === 0 ? 'btn-blue' : 'btn-gray')
|
|
40
|
+
input.hidden(type="radio" name="directionName" autocomplete="off" value=directionName checked=(idx === 0))
|
|
41
|
+
span= directionName
|
|
42
|
+
div(hidden=timetablePage.dayLists.length <= 1)
|
|
43
|
+
#day_list_selector
|
|
44
|
+
h3 Day of Week
|
|
45
|
+
each dayList, idx in timetablePage.dayLists
|
|
46
|
+
label(class=idx === 0 ? 'btn-blue' : 'btn-gray')
|
|
47
|
+
input.hidden(type="radio" name="dayList" autocomplete="off" value=dayList checked=(idx === 0))
|
|
48
|
+
span= dayList
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
- const stopName = `${stop.stop_name}${stop.type === 'arrival' ? ' (Arrival)' : stop.type === 'departure' ? ' (Departure)' : ''}`;
|
|
2
|
+
|
|
3
|
+
if config.linkStopUrls && stop.stop_url
|
|
4
|
+
a.stop-name(href=`${stop.stop_url}`)= stopName
|
|
5
|
+
each note in getNotesForStop(timetable.notes, stop)
|
|
6
|
+
include timetable_note_symbol.pug
|
|
7
|
+
else
|
|
8
|
+
.stop-name= stopName
|
|
9
|
+
each note in getNotesForStop(timetable.notes, stop)
|
|
10
|
+
include timetable_note_symbol.pug
|
|
11
|
+
.stop-code= stop.stop_code
|
|
12
|
+
if config.showStopDescription
|
|
13
|
+
.stop-description= stop.stop_desc
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
td.stop-time(class=`${stoptime.classes.join(' ')}`)
|
|
2
|
+
if config.showStoptimesForRequestStops || (!stoptime.requestDropoff && !stoptime.requestPickup)
|
|
3
|
+
span.stop-time-text!= stoptime.formatted_time
|
|
4
|
+
if stoptime.skipped && timetable.noServiceSymbol !== null
|
|
5
|
+
a(href=`#note-${timetable.timetable_id}-no-service`).symbol= timetable.noServiceSymbol
|
|
6
|
+
if stoptime.interpolated && timetable.interpolatedStopSymbol !== null
|
|
7
|
+
a(href=`#note-${timetable.timetable_id}-interpolated-stop`).symbol= timetable.interpolatedStopSymbol
|
|
8
|
+
if stoptime.requestPickup && timetable.requestPickupSymbol !== null
|
|
9
|
+
a(href=`#note-${timetable.timetable_id}-request-pickup`).symbol= timetable.requestPickupSymbol
|
|
10
|
+
if stoptime.noPickup && timetable.noPickupSymbol !== null
|
|
11
|
+
a(href=`#note-${timetable.timetable_id}-no-pickup`).symbol= timetable.noPickupSymbol
|
|
12
|
+
if stoptime.requestDropoff && timetable.requestDropoffSymbol !== null
|
|
13
|
+
a(href=`#note-${timetable.timetable_id}-request-dropoff`).symbol= timetable.requestDropoffSymbol
|
|
14
|
+
if stoptime.noDropoff && timetable.noDropoffSymbol !== null
|
|
15
|
+
a(href=`#note-${timetable.timetable_id}-no-dropoff`).symbol= timetable.noDropoffSymbol
|
|
16
|
+
each note in getNotesForStoptime(timetable.notes, stoptime)
|
|
17
|
+
include timetable_note_symbol.pug
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
- let columnCount = timetable.stops.length;
|
|
2
|
+
- if (config.showStopCity) {
|
|
3
|
+
- columnCount += timetable.stops.reduce((memo, stop, index) => {
|
|
4
|
+
- if (index === 0 || stop.stop_city !== timetable.stops[index - 1].stop_city) {
|
|
5
|
+
- memo += 1;
|
|
6
|
+
- }
|
|
7
|
+
- return memo;
|
|
8
|
+
- }, 0);
|
|
9
|
+
- }
|
|
10
|
+
- const timetableHasTripNotes = timetable.orderedTrips.flatMap(trip => getNotesForTrip(timetable.notes, trip)).length > 0;
|
|
11
|
+
.table-container
|
|
12
|
+
table.table-vertical(summary=`This table shows schedules for a selection of key stops on the route for ${timetable.timetable_label} ${timetable.dayList}. Stops and their schedule times are listed in the columns.` data-orientation="vertical")
|
|
13
|
+
caption.sr-only= `${timetable.timetable_label} | ${timetable.dayList}`
|
|
14
|
+
colgroup
|
|
15
|
+
each stop, idx in timetable.stops
|
|
16
|
+
col(id=`stop_id_${formatHtmlId(stop.stop_id)}` class=`stop-${idx}` data-stop-id=`${stop.stop_id}` data-is-timepoint=`${stop.is_timepoint}`)
|
|
17
|
+
thead
|
|
18
|
+
tr
|
|
19
|
+
if timetableHasTripNotes || timetable.routes.length > 1
|
|
20
|
+
th
|
|
21
|
+
if timetable.has_continues_from_route
|
|
22
|
+
th.stop-header.continues-from Continues from route
|
|
23
|
+
|
|
24
|
+
- let previousCity = null;
|
|
25
|
+
each stop, idx in timetable.stops
|
|
26
|
+
if stop.stop_city !== '' && previousCity !== stop.stop_city && config.showStopCity
|
|
27
|
+
th.city-column= stop.stop_city
|
|
28
|
+
- previousCity = stop.stop_city
|
|
29
|
+
|
|
30
|
+
th.stop-header(scope="col" width=`${(100 / columnCount).toFixed(2)}%`)
|
|
31
|
+
include timetable_stop_name.pug
|
|
32
|
+
|
|
33
|
+
if timetable.has_continues_as_route
|
|
34
|
+
th.stop-header.continues-as Continues as route
|
|
35
|
+
|
|
36
|
+
tbody
|
|
37
|
+
if timetable.frequencies && !timetable.frequencyExactTimes
|
|
38
|
+
tr.trip-row
|
|
39
|
+
if timetableHasTripNotes || timetable.routes.length > 1
|
|
40
|
+
td
|
|
41
|
+
if timetable.has_continues_from_route
|
|
42
|
+
td
|
|
43
|
+
|
|
44
|
+
td.trip-frequency(colspan=`${columnCount}`)!= formatFrequencyWarning(timetable.frequencies)
|
|
45
|
+
|
|
46
|
+
if timetable.has_continues_as_route
|
|
47
|
+
td
|
|
48
|
+
each trip, idx in timetable.orderedTrips
|
|
49
|
+
tr.trip-row(id=`trip_id_${formatHtmlId(trip.trip_id)}`)
|
|
50
|
+
if timetableHasTripNotes || timetable.routes.length > 1
|
|
51
|
+
td.trip-notes= formatTripName(trip, idx, timetable)
|
|
52
|
+
each note in getNotesForTrip(timetable.notes, trip)
|
|
53
|
+
include timetable_note_symbol.pug
|
|
54
|
+
if timetable.has_continues_from_route
|
|
55
|
+
include timetable_continuation_from.pug
|
|
56
|
+
|
|
57
|
+
- let previousCity = null;
|
|
58
|
+
each stop in timetable.stops
|
|
59
|
+
if stop.stop_city !== '' && previousCity !== stop.stop_city && config.showStopCity
|
|
60
|
+
td
|
|
61
|
+
- previousCity = stop.stop_city
|
|
62
|
+
|
|
63
|
+
- stoptime = stop.trips[idx]
|
|
64
|
+
include timetable_stoptime.pug
|
|
65
|
+
|
|
66
|
+
if timetable.has_continues_as_route
|
|
67
|
+
include timetable_continuation_as.pug
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
include formatting_functions.pug
|
|
2
|
+
|
|
3
|
+
<!-- Timetable generated on #{new Date().toISOString()} using GTFS-to-HTML version #{config.gtfsToHtmlVersion} -->
|
|
4
|
+
.timetable-page(class=`menu-type-${config.menuType}`)
|
|
5
|
+
if config.showRouteTitle
|
|
6
|
+
- const timetableRouteList = _.uniqBy(_.flatMap(timetablePage.consolidatedTimetables, timetable => timetable.routes), 'route_id')
|
|
7
|
+
h1
|
|
8
|
+
each route in timetableRouteList
|
|
9
|
+
.route-color-swatch-large(style=`background-color: ${formatRouteColor(route)}; color: ${formatRouteTextColor(route)};`)= route.route_short_name || ''
|
|
10
|
+
div= timetablePage.timetable_page_label || timetableRouteList.map(route => formatRouteName(route)).join(' and ')
|
|
11
|
+
if config.effectiveDate
|
|
12
|
+
.effective-date= `Effective ${config.effectiveDate}`
|
|
13
|
+
|
|
14
|
+
include timetable_menu.pug
|
|
15
|
+
|
|
16
|
+
each timetable in timetablePage.consolidatedTimetables
|
|
17
|
+
.timetable(id=`timetable_id_${formatHtmlId(timetable.timetable_id)}` data-day-list=timetable.dayList data-direction-name=timetable.direction_name data-timetable-id=timetable.timetable_id data-direction-id=timetable.direction_id data-route-id=timetable.route_ids.join('_'))
|
|
18
|
+
if config.showRouteTitle
|
|
19
|
+
.timetable-label
|
|
20
|
+
h2= `${timetable.timetable_label} | ${timetable.dayListLong}`
|
|
21
|
+
each note in getNotesForTimetableLabel(timetable.notes)
|
|
22
|
+
include timetable_note_symbol.pug
|
|
23
|
+
if timetable.service_notes !== null
|
|
24
|
+
.timetable-service-notes= timetable.service_notes
|
|
25
|
+
|
|
26
|
+
if config.showMap
|
|
27
|
+
include timetable_map.pug
|
|
28
|
+
if timetable.orientation === 'horizontal'
|
|
29
|
+
include timetable_horizontal.pug
|
|
30
|
+
else if timetable.orientation === 'hourly'
|
|
31
|
+
include timetable_hourly.pug
|
|
32
|
+
else if timetable.orientation === 'vertical'
|
|
33
|
+
include timetable_vertical.pug
|
|
34
|
+
|
|
35
|
+
.timetable-footer
|
|
36
|
+
if hasNotesOrNotices(timetable)
|
|
37
|
+
.notes
|
|
38
|
+
if timetable.requestPickupSymbolUsed
|
|
39
|
+
.note(id=`note-${timetable.timetable_id}-request-pickup`)= `${config.requestPickupSymbol} = ${config.requestPickupText}`
|
|
40
|
+
if timetable.noPickupSymbolUsed
|
|
41
|
+
.note(id=`note-${timetable.timetable_id}-no-pickup`)= `${config.noPickupSymbol} = ${config.noPickupText}`
|
|
42
|
+
if timetable.requestDropoffSymbolUsed
|
|
43
|
+
.note(id=`note-${timetable.timetable_id}-request-dropoff`)= `${config.requestDropoffSymbol} = ${config.requestDropoffText}`
|
|
44
|
+
if timetable.noDropoffSymbolUsed
|
|
45
|
+
.note(id=`note-${timetable.timetable_id}-no-dropoff`)= `${config.noDropoffSymbol} = ${config.noDropoffText}`
|
|
46
|
+
if timetable.noServiceSymbolUsed
|
|
47
|
+
.note(id=`note-${timetable.timetable_id}-no-service`)= `${config.noServiceSymbol} = ${config.noServiceText}`
|
|
48
|
+
if timetable.interpolatedStopSymbolUsed
|
|
49
|
+
.note(id=`note-${timetable.timetable_id}-interpolated-stop`)= `${config.interpolatedStopSymbol} = ${config.interpolatedStopText}`
|
|
50
|
+
each note in _.uniqBy(timetable.notes, 'note_id')
|
|
51
|
+
.note(id=`note-${timetable.timetable_id}-${note.note_id}`)
|
|
52
|
+
span= note.symbol
|
|
53
|
+
span =
|
|
54
|
+
span!= md(note.note)
|
|
55
|
+
|
|
56
|
+
if config.showCalendarExceptions && timetable.calendarDates.includedDates.length
|
|
57
|
+
.included-dates= `${config.serviceProvidedOnText}: ${timetable.calendarDates.includedDates.join(', ')}`
|
|
58
|
+
|
|
59
|
+
if config.showCalendarExceptions && timetable.calendarDates.excludedDates.length
|
|
60
|
+
.excluded-dates= `${config.serviceNotProvidedOnText}: ${timetable.calendarDates.excludedDates.join(', ')}`
|
|
61
|
+
|
|
62
|
+
script.
|
|
63
|
+
const { geojsons, tripIds, routes, stops, gtfsRealtimeUrls } = !{JSON.stringify(prepareMapData(timetablePage, config))};
|
|
64
|
+
createMaps();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
extends layout
|
|
2
|
+
block content
|
|
3
|
+
include timetablepage.pug
|
|
4
|
+
|
|
5
|
+
block extraHeader
|
|
6
|
+
script(src="https://unpkg.com/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous")
|
|
7
|
+
|
|
8
|
+
if config.menuType === 'radio'
|
|
9
|
+
script(src=`${config.assetPath}js/timetable-menu.js`)
|
|
10
|
+
|
|
11
|
+
if config.showMap
|
|
12
|
+
if config.hasGtfsRealtime
|
|
13
|
+
script(src=`${config.assetPath}js/pbf.js`)
|
|
14
|
+
script(src=`${config.assetPath}js/gtfs-realtime.browser.proto.js`)
|
|
15
|
+
script(src="https://api.mapbox.com/mapbox-gl-js/v3.6.0/mapbox-gl.js")
|
|
16
|
+
script.
|
|
17
|
+
mapboxgl.accessToken = '#{config.mapboxAccessToken}';
|
|
18
|
+
script(src=`${config.assetPath}js/timetable-map.js`)
|
|
19
|
+
|
|
20
|
+
link(href="https://api.mapbox.com/mapbox-gl-js/v3.6.0/mapbox-gl.css" rel="stylesheet")
|
|
21
|
+
|
|
22
|
+
link(rel="stylesheet" href=`${config.assetPath}css/timetable_styles.css`)
|
|
23
|
+
if config.outputFormat === 'pdf'
|
|
24
|
+
link(rel="stylesheet" href=`${config.assetPath}css/timetable_pdf_styles.css`)
|
|
25
|
+
|