gtfs-to-html 2.6.8 → 2.6.10

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/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.6.10] - 2024-07-15
9
+
10
+ ### Updated
11
+ - Better date format in timetable comment
12
+ - favicon
13
+ - Improved timetable_page_name fallback
14
+ - Overview template formatting
15
+ - Update mapbox version
16
+
17
+ ## [2.6.9] - 2024-07-11
18
+
19
+ ### Added
20
+ - Stop popup window on map link to streetview
21
+
22
+ ### Updated
23
+ - Dependency updates
24
+
8
25
  ## [2.6.8] - 2024-06-21
9
26
 
10
27
  ### Updated
package/lib/formatters.js CHANGED
@@ -512,22 +512,16 @@ export function formatTimetablePageLabel(timetablePage) {
512
512
  timetablePage.consolidatedTimetables &&
513
513
  timetablePage.consolidatedTimetables.length > 0
514
514
  ) {
515
- if (timetablePage.consolidatedTimetables.length === 1) {
516
- // Get label from first timetable if there is only one
517
- return timetablePage.consolidatedTimetables[0].timetable_label;
518
- } else {
519
- // Otherwise, use route names from all timetables
520
- const routes = uniqBy(
521
- flatMap(
522
- timetablePage.consolidatedTimetables,
523
- (timetable) => timetable.routes,
524
- ),
525
- 'route_id',
526
- );
527
- const timetablePageLabel = routes.map((route) => formatRouteName(route));
515
+ // Use route names from all timetables
516
+ const routes = uniqBy(
517
+ flatMap(
518
+ timetablePage.consolidatedTimetables,
519
+ (timetable) => timetable.routes,
520
+ ),
521
+ 'route_id',
522
+ );
528
523
 
529
- return timetablePageLabel.join(' and ');
530
- }
524
+ return routes.map((route) => formatRouteName(route)).join(' and ');
531
525
  }
532
526
 
533
527
  return 'Unknown';
package/lib/log-utils.js CHANGED
@@ -17,7 +17,7 @@ export function generateLogText(outputStats, config) {
17
17
  const logText = [
18
18
  `Feed Version: ${feedVersion}`,
19
19
  `GTFS-to-HTML Version: ${config.gtfsToHtmlVersion}`,
20
- `Date Generated: ${new Date()}`,
20
+ `Date Generated: ${new Date().toISOString()}`,
21
21
  `Timetable Page Count: ${outputStats.timetablePages}`,
22
22
  `Timetable Count: ${outputStats.timetables}`,
23
23
  `Calendar Service ID Count: ${outputStats.calendars}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtfs-to-html",
3
- "version": "2.6.8",
3
+ "version": "2.6.10",
4
4
  "private": false,
5
5
  "description": "Build human readable transit timetables as HTML, PDF or CSV from GTFS",
6
6
  "keywords": [
@@ -42,23 +42,23 @@
42
42
  "copy-dir": "^1.3.0",
43
43
  "csv-stringify": "^6.5.0",
44
44
  "express": "^4.19.2",
45
- "gtfs": "^4.12.0",
45
+ "gtfs": "^4.13.0",
46
46
  "insane": "^2.6.2",
47
47
  "js-beautify": "^1.15.1",
48
48
  "lodash-es": "^4.17.21",
49
- "marked": "^13.0.0",
49
+ "marked": "^13.0.2",
50
50
  "moment": "^2.30.1",
51
51
  "morgan": "^1.10.0",
52
52
  "pretty-error": "^4.0.0",
53
53
  "pug": "^3.0.3",
54
- "puppeteer": "^22.12.0",
54
+ "puppeteer": "^22.13.0",
55
55
  "sanitize-filename": "^1.6.3",
56
56
  "sqlstring": "^2.3.3",
57
57
  "timer-machine": "^1.1.0",
58
58
  "toposort": "^2.0.2",
59
59
  "untildify": "^5.0.0",
60
60
  "yargs": "^17.7.2",
61
- "yoctocolors": "^2.0.2"
61
+ "yoctocolors": "^2.1.1"
62
62
  },
63
63
  "devDependencies": {
64
64
  "husky": "^9.0.11",
@@ -66,7 +66,7 @@
66
66
  "prettier": "^3.3.2"
67
67
  },
68
68
  "engines": {
69
- "node": ">= 18.0.0"
69
+ "node": ">= 20.11.0"
70
70
  },
71
71
  "release-it": {
72
72
  "github": {
@@ -186,7 +186,7 @@ a:hover {
186
186
  font-size: 20px;
187
187
  font-weight: bold;
188
188
  letter-spacing: -1px;
189
- padding: 0 8px;
189
+ padding: 0 6px;
190
190
  }
191
191
 
192
192
  @media screen and (max-width: 767px) {
@@ -60,10 +60,23 @@ function formatStopPopup(feature) {
60
60
  $('<strong>').text(feature.properties.stop_code).appendTo(html);
61
61
  }
62
62
 
63
- $('<div>').addClass('text-sm').text('Routes Served:').appendTo(html);
63
+ $('<label>').addClass('block').text('Routes Served:').appendTo(html);
64
64
 
65
65
  $(html).append(routes.map((route) => formatRoute(route)));
66
66
 
67
+ $('<a>')
68
+ .addClass(
69
+ 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-1.5 px-3 rounded inline-block hover:no-underline mt-2',
70
+ )
71
+ .prop(
72
+ 'href',
73
+ `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${feature.geometry.coordinates[1]},${feature.geometry.coordinates[0]}&heading=0&pitch=0&fov=90`,
74
+ )
75
+ .prop('target', '_blank')
76
+ .prop('rel', 'noopener noreferrer')
77
+ .html('View on Streetview')
78
+ .appendTo(html);
79
+
67
80
  return html.prop('outerHTML');
68
81
  }
69
82
 
@@ -53,10 +53,23 @@ function formatStopPopup(feature, routes) {
53
53
  $('<strong>').text(feature.properties.stop_code).appendTo(html);
54
54
  }
55
55
 
56
- $('<div>').addClass('text-sm mb-2').text('Routes Served:').appendTo(html);
56
+ $('<label>').addClass('block').text('Routes Served:').appendTo(html);
57
57
 
58
58
  $(html).append(routeIds.map((routeId) => formatRoute(routes[routeId])));
59
59
 
60
+ $('<a>')
61
+ .addClass(
62
+ 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-1.5 px-3 rounded inline-block hover:no-underline mt-2',
63
+ )
64
+ .prop(
65
+ 'href',
66
+ `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${feature.geometry.coordinates[1]},${feature.geometry.coordinates[0]}&heading=0&pitch=0&fov=90`,
67
+ )
68
+ .prop('target', '_blank')
69
+ .prop('rel', 'noopener noreferrer')
70
+ .html('View on Streetview')
71
+ .appendTo(html);
72
+
60
73
  return html.prop('outerHTML');
61
74
  }
62
75
 
@@ -11,14 +11,8 @@
11
11
  return summary;
12
12
  }
13
13
 
14
- function formatRouteName(route) {
15
- const hasLongName = route.route_long_name !== '' && route.route_long_name !== null;
16
-
17
- if (hasLongName) {
18
- return route.route_long_name;
19
- }
20
-
21
- return route.route_short_name;
14
+ function isNullOrEmpty(value) {
15
+ return value === null || value === '';
22
16
  }
23
17
 
24
18
  function formatFrequencyWarning(frequencies) {
@@ -1,28 +1,28 @@
1
1
  include formatting_functions.pug
2
2
 
3
- .container.mx-4.h-screen.items-stretch(class="md:mx-auto md:flex")
3
+ .h-screen.items-stretch(class="md:flex")
4
4
  if !timetablePages || !timetablePages.length
5
5
  .flex.justify-center
6
6
  .bg-blue-700.text-white.font-bold.rounded-lg.border.shadow-lg.text-lg.p-8(class="w-1/2") No timetables found
7
7
  else
8
- .overview-list.flex-none(class="md:overflow-y-scroll")
8
+ .overview-list.flex-none(class="md:overflow-y-scroll md:max-w-96")
9
9
  each timetablePageGroup in getAgencyTimetableGroups(timetablePages, agencies)
10
- h1.text-2xl.pt-4.pb-2= `${formatAgencyName(timetablePageGroup.agency)} Routes`
10
+ h1.text-2xl.mx-4.py-3= `${formatAgencyName(timetablePageGroup.agency)} Routes`
11
+
11
12
  each timetablePage in timetablePageGroup.timetablePages
12
13
  if config.allowEmptyTimetables || timetablePage.consolidatedTimetables.length > 0
13
- a.block.p-2.border-b.border-slate-200(class="hover:bg-slate-100 hover:no-underline" href=`${timetablePage.relativePath}` data-route-ids=`${timetablePage.route_ids ? timetablePage.route_ids.join(',') : ''}`)
14
- .text-lg.text-gray-800.leading-none= timetablePage.timetable_page_label
14
+ a.timetable-overview-label.flex.items-center.gap-2.block.p-2.border-b.border-slate-200(class="hover:bg-slate-100 hover:no-underline" href=`${timetablePage.relativePath}` data-route-ids=`${timetablePage.route_ids ? timetablePage.route_ids.join(',') : ''}`)
15
15
  each route in _.uniqBy(_.flatMap(timetablePage.consolidatedTimetables, timetable => timetable.routes), 'route_id')
16
- .flex.my-1.items-center.gap-1
17
- .route-color-swatch.flex-none(style=`background-color: ${formatRouteColor(route)}; color: ${formatRouteTextColor(route)};`)= route.route_short_name || ''
18
- .text-gray-600.leading-none= formatRouteName(route)
19
- .inline-flex.items-center.justify-center.px-2.py-1.text-xs.font-bold.leading-none.text-slate-800.bg-slate-200.rounded-full= timetablePage.dayList
16
+ .route-color-swatch-large.flex-none(style=`background-color: ${formatRouteColor(route)}; color: ${formatRouteTextColor(route)};`)= route.route_short_name || ''
17
+ div
18
+ .text-xl.leading-none.text-slate-800= timetablePage.timetable_page_label
19
+ .inline-flex.items-center.justify-center.px-2.py-1.text-xs.font-bold.leading-none.text-slate-800.bg-slate-200.rounded-full= timetablePage.dayList
20
20
  if config.showMap
21
- .map.ml-4.h-full.w-full(id="system_map")
21
+ .map.h-full.w-full(id="system_map")
22
22
 
23
23
  //- Use #{variable} format to inject values from pug to client side js
24
24
  script.
25
25
  (function() {
26
- var geojson = !{JSON.stringify(geojson) || '\'\''};
26
+ const geojson = !{JSON.stringify(geojson) || '\'\''};
27
27
  createSystemMap('system_map', geojson);
28
28
  })();
@@ -6,9 +6,9 @@ block extraHeader
6
6
  if config.showMap
7
7
  script(src="https://unpkg.com/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous")
8
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.3.0/mapbox-gl.js")
9
+ script(src="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.js")
10
10
  script.
11
11
  mapboxgl.accessToken = '#{config.mapboxAccessToken}';
12
12
  script(src=`${config.assetPath}js/system-map.js`)
13
13
 
14
- link(href="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css" rel="stylesheet")
14
+ link(href="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.css" rel="stylesheet")
@@ -1,6 +1,6 @@
1
1
  include formatting_functions.pug
2
2
 
3
- <!-- Timetable generated on #{Date()} using GTFS-to-HTML version #{config.gtfsToHtmlVersion} -->
3
+ <!-- Timetable generated on #{new Date().toISOString()} using GTFS-to-HTML version #{config.gtfsToHtmlVersion} -->
4
4
  .timetable-page(class=`menu-type-${config.menuType}`)
5
5
  .container.mx-4(class="md:mx-auto")
6
6
  if config.showRouteTitle
@@ -9,10 +9,10 @@ block extraHeader
9
9
  script(src=`${config.assetPath}js/timetable-menu.js`)
10
10
 
11
11
  if config.showMap
12
- script(src="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js")
12
+ script(src="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.js")
13
13
  script.
14
14
  mapboxgl.accessToken = '#{config.mapboxAccessToken}';
15
15
  script(src=`${config.assetPath}js/timetable-map.js`)
16
16
 
17
- link(href="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css" rel="stylesheet")
17
+ link(href="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.css" rel="stylesheet")
18
18
 
@@ -11,10 +11,14 @@ After an initial run of `gtfs-to-html`, the GTFS data will be downloaded and loa
11
11
 
12
12
  You can view an individual route HTML on demand by running the included Express app:
13
13
 
14
+ ```bash
14
15
  node app
16
+ ```
15
17
 
16
18
  By default, `gtfs-to-html` will look for a `config.json` file in the project root. To specify a different path for the configuration file:
17
19
 
20
+ ```bash
18
21
  node app --configPath /path/to/your/custom-config.json
22
+ ```
19
23
 
20
24
  Once running, you can view the HTML in your browser at [localhost:3000](http://localhost:3000)
@@ -5,4 +5,6 @@ title: Processing very large GTFS files
5
5
 
6
6
  By default, node has a memory limit of 512 MB or 1 GB. If you have a very large GTFS file and want to use the option `showOnlyTimepoint` = `false` you may need to allocate more memory. Use the `max-old-space-size` option. For example to allocate 4 GB:
7
7
 
8
+ ```
8
9
  NODE_OPTIONS=--max_old_space_size=4096 gtfs-to-html
10
+ ```
@@ -4,37 +4,51 @@ title: Related Libraries
4
4
  ---
5
5
 
6
6
  ## `node-gtfs`
7
-
8
- `gtfs-to-html` uses the [`node-gtfs`](https://github.com/blinktaginc/node-gtfs) library to handle importing and querying GTFS data. It provides methods for loading transit data in GTFS format into a SQLite database and methods to query for agencies, routes, stops, times, fares, calendars and other GTFS data. It also offers spatial queries to find nearby stops, routes and agencies and can convert stops and shapes to geoJSON format.
9
-
10
7
  [`https://github.com/blinktaginc/node-gtfs`](https://github.com/blinktaginc/node-gtfs)
8
+ <div style={{ display: 'flex', gap: 20 }}>
9
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/node-gtfs/raw/master/docs/images/node-gtfs-logo.svg" alt="node-gtfs" width="100" /></div>
10
+ <div><code>gtfs-to-html</code> uses the <a href="https://github.com/blinktaginc/node-gtfs">node-gtfs</a> library to handle importing and querying GTFS data. It provides methods for loading transit data in GTFS format into a SQLite database and methods to query for agencies, routes, stops, times, fares, calendars and other GTFS data. It also offers spatial queries to find nearby stops, routes and agencies and can convert stops and shapes to geoJSON format.</div>
11
+ </div>
11
12
 
12
13
  ## `gtfs-to-geojson`
13
-
14
- [`gtfs-to-geojson`](https://github.com/blinktaginc/gtfs-to-geojson) converts transit data in GTFS format into geoJSON. This includes both shapes and stops. It can be configured to generate one geoJSON file per route or a single file which contains all routes for an agency. This is useful for creating maps of transit routes.
15
-
16
14
  [`https://github.com/blinktaginc/gtfs-to-geojson`](https://github.com/blinktaginc/gtfs-to-geojson)
15
+ <div style={{ display: 'flex', gap: 20 }}>
16
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/gtfs-to-geojson/raw/master/docs/images/gtfs-to-geojson-logo.svg" alt="gtfs-to-geojson" width="100" /></div>
17
+ <div><a href="https://github.com/blinktaginc/gtfs-to-geojson"><code>gtfs-to-geojson</code></a> converts transit data in GTFS format into geoJSON. This includes both shapes and stops. It can be configured to generate one geoJSON file per route or a single file which contains all routes for an agency. This is useful for creating maps of transit routes.</div>
18
+ </div>
17
19
 
18
20
  ## `gtfs-to-chart`
19
-
20
- [`gtfs-to-chart`](https://github.com/blinktaginc/gtfs-to-chart) generates a stringline chart in D3 using data from an agency's GTFS. This chart shows all trips for a specific route as they travel through space over a single day.
21
-
22
21
  [`https://github.com/blinktaginc/gtfs-to-chart`](https://github.com/blinktaginc/gtfs-to-chart)
22
+ <div style={{ display: 'flex', gap: 20 }}>
23
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/gtfs-to-chart/raw/master/docs/images/gtfs-to-chart-logo.svg" alt="gtfs-to-chart" width="100" /></div>
24
+ <div><a href="https://github.com/blinktaginc/gtfs-to-chart"><code>gtfs-to-chart</code></a> generates a stringline chart in D3 using data from an agency's GTFS. This chart shows all trips for a specific route as they travel through space over a single day.</div>
25
+ </div>
23
26
 
24
27
  ## Transit Departures Widget
25
-
26
- The [Transit Departures Widget](https://github.com/BlinkTagInc/transit-departures-widget) generates a user-friendly transit realtime departures widget in HTML format directly from GTFS and GTFS-RT transit data. Most transit agencies have schedule data in GTFS format and many publish realtime departure information using GTFS-RT. This project generates HTML, JS and CSS for use on a transit agency website to allow users to see when the next vehicle is departing from a specific stop and includes features like caching, auto-refresh, url parameters and custom templates.
27
-
28
28
  [`https://github.com/BlinkTagInc/transit-departures-widget`](https://github.com/BlinkTagInc/transit-departures-widget)
29
+ <div style={{ display: 'flex', gap: 20 }}>
30
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/transit-departures-widget/raw/main/docs/images/transit-departures-widget-logo.svg" alt="Transit Departures Widget" width="100" /></div>
31
+ <div>The <a href="https://github.com/BlinkTagInc/transit-departures-widget">Transit Departures Widget</a> generates a user-friendly transit realtime departures widget in HTML format directly from GTFS and GTFS-RT transit data. Most transit agencies have schedule data in GTFS format and many publish realtime departure information using GTFS-RT. This project generates HTML, JS and CSS for use on a transit agency website to allow users to see when the next vehicle is departing from a specific stop and includes features like caching, auto-refresh, url parameters and custom templates.</div>
32
+ </div>
33
+
34
+ ## GTFS Accessibility Validator
35
+ [`https://github.com/BlinkTagInc/gtfs-accessibility-validator`](https://github.com/BlinkTagInc/gtfs-accessibility-validator)
36
+ <div style={{ display: 'flex', gap: 20 }}>
37
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/gtfs-accessibility-validator/raw/main/docs/images/gtfs-accessibility-validator-logo.svg" alt="Transit Departures Widget" width="100" /></div>
38
+ <div>The <a href="https://github.com/BlinkTagInc/gtfs-accessibility-validator">GTFS Accessibility Validator</a> checks transit data in GTFS format for fields and files related to accessibility. The accessibility guidelines are taken from the <a href="https://dot.ca.gov/cal-itp/california-transit-data-guidelines-v3_0#section-checklist">California Transit Data Guidelines</a> published by Caltrans.</div>
39
+ </div>
29
40
 
30
41
  ## GTFS Text-to-Speech Tester
31
-
32
- The [GTFS Text-to-Speech Tester](https://github.com/BlinkTagInc/node-gtfs-tts) is a command-line tool that will read all GTFS stop names using Text-to-Speech and allow flagging which names need Text-to-Speech values for tts_stop_name in stops.txt. Using this tool is the quickest way to determine which stops need phoenetic spellings, abbreviations written out, large digits written as words, ordinals written out or other changes so that they can be read.
33
-
34
42
  [`https://github.com/BlinkTagInc/node-gtfs-tts`](https://github.com/BlinkTagInc/node-gtfs-tts)
43
+ <div style={{ display: 'flex', gap: 20 }}>
44
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/node-gtfs-tts/raw/main/docs/images/gtfs-tts-logo.svg" alt="Transit Departures Widget" width="100" /></div>
45
+ <div>The <a href="https://github.com/BlinkTagInc/node-gtfs-tts">GTFS Text-to-Speech Tester</a> is a command-line tool that will read all GTFS stop names using Text-to-Speech and allow flagging which names need Text-to-Speech values for tts_stop_name in stops.txt. Using this tool is the quickest way to determine which stops need phonetic spellings, abbreviations written out, large digits written as words, ordinals written out or other changes so that they can be read.</div>
46
+ </div>
35
47
 
36
48
  ## `node-gtfs-realtime`
37
-
38
- [GTFS-realtime](https://developers.google.com/transit/gtfs-realtime) transit data is in [protobuf format](https://developers.google.com/protocol-buffers) which means its not human-readable by default. `node-GTFS-Realtime` aims to make it fast and easy to inspect GTFS-realtime data by providing a one-line command for downloading [GTFS-realtime format](https://developers.google.com/transit/gtfs-realtime) data and converting to JSON. Try it by running `npx gtfs-realtime http://api.bart.gov/gtfsrt/tripupdate.aspx` in your terminal.
39
-
40
49
  [`https://github.com/BlinkTagInc/node-gtfs-realtime`](https://github.com/BlinkTagInc/node-gtfs-realtime)
50
+ <div style={{ display: 'flex', gap: 20 }}>
51
+ <div style={{ width: 100, flexShrink: 0 }}><img src="https://github.com/BlinkTagInc/node-gtfs-realtime/raw/main/docs/images/node-gtfs-realtime-logo.svg
52
+ " alt="Transit Departures Widget" width="100" /></div>
53
+ <div>GTFS-realtime transit data is in <a href="https://developers.google.com/protocol-buffers">protobuf format</a> which means its not human-readable by default. <code>node-GTFS-Realtime</code> aims to make it fast and easy to inspect GTFS-realtime data by providing a one-line command for downloading GTFS-realtime format data and converting to JSON. Try it out by running <code>npx gtfs-realtime http://api.bart.gov/gtfsrt/tripupdate.aspx</code> in your terminal.</div>
54
+ </div>
@@ -18,8 +18,12 @@ First generate two folders of GTFS-to-HTML output to compare. To make it easy to
18
18
 
19
19
  Then, install diff2html:
20
20
 
21
+ ```bash
21
22
  npm install -g diff2html-cli
23
+ ```
22
24
 
23
25
  Use the `diff` command and pipe the output to `diff2html` to get a nicely formatted list of the differences between two folders of html files.
24
26
 
27
+ ```bash
25
28
  diff -bur html/folder1 html/folder2 | diff2html -i stdin
29
+ ```
Binary file