gtfs-to-html 2.9.15 → 2.10.0
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 +0 -1
- package/dist/app/index.js +2 -1
- package/dist/app/index.js.map +1 -1
- package/dist/bin/gtfs-to-html.js +2 -1
- package/dist/bin/gtfs-to-html.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/views/default/css/overview_styles.css +7 -7
- package/views/default/css/timetable_styles.css +14 -14
- package/views/default/formatting_functions.pug +2 -1
- package/views/default/js/system-map.js +83 -25
- package/views/default/js/timetable-map.js +50 -28
- package/views/default/overview.pug +3 -4
- package/views/default/overview_full.pug +4 -4
- package/views/default/timetablepage.pug +1 -1
- package/views/default/timetablepage_full.pug +2 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtfs-to-html",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Build human readable transit timetables as HTML, PDF or CSV from GTFS",
|
|
6
6
|
"keywords": [
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"cli-table": "^0.3.11",
|
|
54
54
|
"csv-stringify": "^6.5.1",
|
|
55
55
|
"express": "^5.0.1",
|
|
56
|
-
"gtfs": "^4.15.
|
|
56
|
+
"gtfs": "^4.15.3",
|
|
57
57
|
"gtfs-realtime-pbf-js-module": "^1.0.0",
|
|
58
58
|
"insane": "^2.6.2",
|
|
59
59
|
"js-beautify": "^1.15.1",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"pbf": "^4.0.1",
|
|
64
64
|
"pretty-error": "^4.0.0",
|
|
65
65
|
"pug": "^3.0.3",
|
|
66
|
-
"puppeteer": "^23.
|
|
66
|
+
"puppeteer": "^23.6.0",
|
|
67
67
|
"sanitize-filename": "^1.6.3",
|
|
68
68
|
"sqlstring": "^2.3.3",
|
|
69
69
|
"timer-machine": "^1.1.0",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@types/js-beautify": "^1.14.3",
|
|
80
80
|
"@types/lodash-es": "^4.17.12",
|
|
81
81
|
"@types/morgan": "^1.9.9",
|
|
82
|
-
"@types/node": "^20.16.
|
|
82
|
+
"@types/node": "^20.16.13",
|
|
83
83
|
"@types/pug": "^2.0.10",
|
|
84
84
|
"@types/puppeteer": "^7.0.4",
|
|
85
85
|
"@types/sanitize-filename": "^1.6.3",
|
|
@@ -166,23 +166,23 @@ a:hover {
|
|
|
166
166
|
width: 100%;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
.overview-map .
|
|
169
|
+
.overview-map .maplibregl-popup-content .popup-title {
|
|
170
170
|
margin: 0 20px 5px 0;
|
|
171
171
|
font-size: 16px;
|
|
172
172
|
font-weight: bold;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
.overview-map .
|
|
175
|
+
.overview-map .maplibregl-popup-content .popup-label {
|
|
176
176
|
border-bottom: 1px solid #e0e0e0;
|
|
177
177
|
padding-top: 0.5rem;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
.overview-map .
|
|
180
|
+
.overview-map .maplibregl-popup-content .route-list {
|
|
181
181
|
margin-bottom: 1rem;
|
|
182
182
|
margin-top: 0.25rem;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
.overview-map .
|
|
185
|
+
.overview-map .maplibregl-popup-content .map-route-item {
|
|
186
186
|
display: flex;
|
|
187
187
|
align-items: center;
|
|
188
188
|
font-size: 0.75rem;
|
|
@@ -191,14 +191,14 @@ a:hover {
|
|
|
191
191
|
gap: 0.5rem;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
.overview-map .
|
|
194
|
+
.overview-map .maplibregl-popup-content .map-route-item:hover {
|
|
195
195
|
text-decoration: none;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
.overview-map .
|
|
198
|
+
.overview-map .maplibregl-popup-content a.map-route-item .underline-hover:hover {
|
|
199
199
|
text-decoration: underline;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
.overview-map .
|
|
202
|
+
.overview-map .maplibregl-popup-content .maplibregl-popup-close-button {
|
|
203
203
|
padding: 0 5px;
|
|
204
204
|
}
|
|
@@ -453,24 +453,24 @@ a:hover {
|
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
.timetable-page .map .
|
|
456
|
+
.timetable-page .map .maplibregl-popup-content .popup-title {
|
|
457
457
|
margin: 0 20px 5px 0;
|
|
458
458
|
font-size: 1rem;
|
|
459
459
|
font-weight: 700;
|
|
460
460
|
line-height: 1;
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
-
.timetable-page .map .
|
|
463
|
+
.timetable-page .map .maplibregl-popup-content .popup-label {
|
|
464
464
|
border-bottom: 1px solid #e0e0e0;
|
|
465
465
|
padding-top: 0.5rem;
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
.timetable-page .map .
|
|
468
|
+
.timetable-page .map .maplibregl-popup-content .route-list {
|
|
469
469
|
margin-bottom: 1rem;
|
|
470
470
|
margin-top: 0.25rem;
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
.timetable-page .map .
|
|
473
|
+
.timetable-page .map .maplibregl-popup-content .map-route-item {
|
|
474
474
|
display: flex;
|
|
475
475
|
align-items: center;
|
|
476
476
|
font-size: 0.75rem;
|
|
@@ -479,23 +479,23 @@ a:hover {
|
|
|
479
479
|
gap: 0.5rem;
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
-
.timetable-page .map .
|
|
482
|
+
.timetable-page .map .maplibregl-popup-content .map-route-item:hover {
|
|
483
483
|
text-decoration: none;
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
.timetable-page
|
|
487
487
|
.map
|
|
488
|
-
.
|
|
488
|
+
.maplibregl-popup-content
|
|
489
489
|
a.map-route-item
|
|
490
490
|
.underline-hover:hover {
|
|
491
491
|
text-decoration: underline;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
.timetable-page .map .
|
|
494
|
+
.timetable-page .map .maplibregl-popup-content .maplibregl-popup-close-button {
|
|
495
495
|
padding: 0 5px;
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
-
.timetable-page .map .
|
|
498
|
+
.timetable-page .map .maplibregl-popup-content .upcoming-stops {
|
|
499
499
|
display: grid;
|
|
500
500
|
grid-template-columns: auto 1fr;
|
|
501
501
|
gap: 0.5rem;
|
|
@@ -505,7 +505,7 @@ a:hover {
|
|
|
505
505
|
|
|
506
506
|
.timetable-page
|
|
507
507
|
.map
|
|
508
|
-
.
|
|
508
|
+
.maplibregl-popup-content
|
|
509
509
|
.upcoming-stops div:nth-child(1) {
|
|
510
510
|
font-weight: bold;
|
|
511
511
|
border-bottom: 1px solid #dddddd;
|
|
@@ -515,7 +515,7 @@ a:hover {
|
|
|
515
515
|
|
|
516
516
|
.timetable-page
|
|
517
517
|
.map
|
|
518
|
-
.
|
|
518
|
+
.maplibregl-popup-content
|
|
519
519
|
.upcoming-stops div:nth-child(2) {
|
|
520
520
|
font-weight: bold;
|
|
521
521
|
border-bottom: 1px solid #dddddd;
|
|
@@ -525,20 +525,20 @@ a:hover {
|
|
|
525
525
|
|
|
526
526
|
.timetable-page
|
|
527
527
|
.map
|
|
528
|
-
.
|
|
528
|
+
.maplibregl-popup-content
|
|
529
529
|
.upcoming-stops
|
|
530
530
|
div:nth-child(2n-1) {
|
|
531
531
|
text-align: right;
|
|
532
532
|
font-weight: bold;
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
-
.timetable-page .map .
|
|
535
|
+
.timetable-page .map .maplibregl-popup-content .vehicle-updated {
|
|
536
536
|
padding-top: 5px;
|
|
537
537
|
font-size: 10px;
|
|
538
538
|
text-align: right;
|
|
539
539
|
}
|
|
540
540
|
|
|
541
|
-
.timetable-page .map .vehicle-popup .
|
|
541
|
+
.timetable-page .map .vehicle-popup .maplibregl-popup-content {
|
|
542
542
|
padding-bottom: 5px;
|
|
543
543
|
}
|
|
544
544
|
|
|
@@ -550,7 +550,7 @@ a:hover {
|
|
|
550
550
|
padding: 10px;
|
|
551
551
|
position: absolute;
|
|
552
552
|
left: 10px;
|
|
553
|
-
bottom:
|
|
553
|
+
bottom: 10px;
|
|
554
554
|
z-index: 1;
|
|
555
555
|
}
|
|
556
556
|
|
|
@@ -97,12 +97,13 @@
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
return {
|
|
100
|
+
gtfsRealtimeUrls,
|
|
101
|
+
mapStyleUrl: config.mapStyleUrl,
|
|
100
102
|
pageData: {
|
|
101
103
|
routeIds: _.uniq(_.flatMap(timetablePage.consolidatedTimetables, timetable => timetable.routes.map(route => route.route_id))),
|
|
102
104
|
tripIds: _.uniq(_.flatMap(timetablePage.consolidatedTimetables, timetable => timetable.orderedTrips.map(trip => trip.trip_id))),
|
|
103
105
|
stopIds: Object.keys(stopData),
|
|
104
106
|
geojsons,
|
|
105
|
-
gtfsRealtimeUrls,
|
|
106
107
|
},
|
|
107
108
|
routeData,
|
|
108
109
|
stopData,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
/* global
|
|
1
|
+
/* global document, jQuery, _, maplibregl, geojson, mapStyleUrl */
|
|
2
2
|
/* eslint prefer-arrow-callback: "off", no-unused-vars: "off" */
|
|
3
3
|
|
|
4
|
-
const maps = {};
|
|
5
|
-
|
|
6
4
|
function formatRouteColor(route) {
|
|
7
5
|
return route.route_color || '#000000';
|
|
8
6
|
}
|
|
@@ -95,7 +93,7 @@ function formatStopPopup(feature) {
|
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
function getBounds(geojson) {
|
|
98
|
-
const bounds = new
|
|
96
|
+
const bounds = new maplibregl.LngLatBounds();
|
|
99
97
|
for (const feature of geojson.features) {
|
|
100
98
|
if (feature.geometry.type.toLowerCase() === 'point') {
|
|
101
99
|
bounds.extend(feature.geometry.coordinates);
|
|
@@ -115,7 +113,7 @@ function getBounds(geojson) {
|
|
|
115
113
|
return bounds;
|
|
116
114
|
}
|
|
117
115
|
|
|
118
|
-
function createSystemMap(
|
|
116
|
+
function createSystemMap() {
|
|
119
117
|
const defaultRouteColor = '#000000';
|
|
120
118
|
const lineLayout = {
|
|
121
119
|
'line-join': 'round',
|
|
@@ -128,9 +126,9 @@ function createSystemMap(id, geojson) {
|
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
const bounds = getBounds(geojson);
|
|
131
|
-
const map = new
|
|
132
|
-
container:
|
|
133
|
-
style:
|
|
129
|
+
const map = new maplibregl.Map({
|
|
130
|
+
container: 'system_map',
|
|
131
|
+
style: mapStyleUrl,
|
|
134
132
|
center: bounds.getCenter(),
|
|
135
133
|
zoom: 12,
|
|
136
134
|
});
|
|
@@ -141,16 +139,67 @@ function createSystemMap(id, geojson) {
|
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
map.scrollZoom.disable();
|
|
144
|
-
map.addControl(new
|
|
142
|
+
map.addControl(new maplibregl.NavigationControl());
|
|
143
|
+
map.addControl(new maplibregl.FullscreenControl());
|
|
144
|
+
|
|
145
|
+
addGeocoder(map, bounds);
|
|
145
146
|
|
|
146
147
|
map.on('load', () => {
|
|
147
148
|
fitMapToBounds(map, bounds);
|
|
148
149
|
disablePointsOfInterest(map);
|
|
149
150
|
addMapLayers(map, geojson, defaultRouteColor, lineLayout);
|
|
150
|
-
setupEventListeners(map,
|
|
151
|
+
setupEventListeners(map, routes);
|
|
151
152
|
});
|
|
153
|
+
}
|
|
152
154
|
|
|
153
|
-
|
|
155
|
+
function addGeocoder(map, bounds) {
|
|
156
|
+
map.addControl(
|
|
157
|
+
new MaplibreGeocoder(
|
|
158
|
+
{
|
|
159
|
+
forwardGeocode: async (config) => {
|
|
160
|
+
const features = [];
|
|
161
|
+
try {
|
|
162
|
+
const request = `https://nominatim.openstreetmap.org/search?q=${
|
|
163
|
+
config.query
|
|
164
|
+
}&format=geojson&polygon_geojson=1&addressdetails=1&viewbox=${bounds.getWest()},${bounds.getSouth()},${bounds.getEast()},${bounds.getNorth()}&bounded=1`;
|
|
165
|
+
const response = await fetch(request);
|
|
166
|
+
const geojson = await response.json();
|
|
167
|
+
for (const feature of geojson.features) {
|
|
168
|
+
const center = [
|
|
169
|
+
feature.bbox[0] + (feature.bbox[2] - feature.bbox[0]) / 2,
|
|
170
|
+
feature.bbox[1] + (feature.bbox[3] - feature.bbox[1]) / 2,
|
|
171
|
+
];
|
|
172
|
+
const point = {
|
|
173
|
+
type: 'Feature',
|
|
174
|
+
geometry: {
|
|
175
|
+
type: 'Point',
|
|
176
|
+
coordinates: center,
|
|
177
|
+
},
|
|
178
|
+
place_name: feature.properties.display_name,
|
|
179
|
+
properties: feature.properties,
|
|
180
|
+
text: feature.properties.display_name,
|
|
181
|
+
place_type: ['place'],
|
|
182
|
+
center,
|
|
183
|
+
};
|
|
184
|
+
features.push(point);
|
|
185
|
+
}
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.error(`Failed to forwardGeocode with error: ${e}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
features,
|
|
192
|
+
type: 'FeatureCollection',
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
maplibregl,
|
|
198
|
+
zoom: 12,
|
|
199
|
+
},
|
|
200
|
+
),
|
|
201
|
+
'top-left',
|
|
202
|
+
);
|
|
154
203
|
}
|
|
155
204
|
|
|
156
205
|
function fitMapToBounds(map, bounds) {
|
|
@@ -161,23 +210,32 @@ function fitMapToBounds(map, bounds) {
|
|
|
161
210
|
}
|
|
162
211
|
|
|
163
212
|
function disablePointsOfInterest(map) {
|
|
164
|
-
map.
|
|
213
|
+
const layers = map.getStyle().layers;
|
|
214
|
+
const poiLayerIds = layers
|
|
215
|
+
.filter((layer) => layer.id.startsWith('poi'))
|
|
216
|
+
?.map((layer) => layer.id);
|
|
217
|
+
poiLayerIds.forEach((layerId) => {
|
|
218
|
+
map.setLayoutProperty(layerId, 'visibility', 'none');
|
|
219
|
+
});
|
|
165
220
|
}
|
|
166
221
|
|
|
167
222
|
function addMapLayers(map, geojson, defaultRouteColor, lineLayout) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
223
|
+
const layers = map.getStyle().layers;
|
|
224
|
+
const firstLabelLayerId = layers.find(
|
|
225
|
+
(layer) => layer.type === 'symbol' && layer.id.includes('label'),
|
|
226
|
+
)?.id;
|
|
227
|
+
|
|
228
|
+
addRouteLineShadow(map, geojson, lineLayout, firstLabelLayerId);
|
|
229
|
+
addHighlightedRouteLineShadow(map, geojson, lineLayout, firstLabelLayerId);
|
|
230
|
+
addRouteLineOutline(map, geojson, lineLayout, firstLabelLayerId);
|
|
231
|
+
addHighlightedRouteLineOutline(map, geojson, lineLayout, firstLabelLayerId);
|
|
232
|
+
addRouteLine(map, geojson, defaultRouteColor, lineLayout, firstLabelLayerId);
|
|
175
233
|
addHighlightedRouteLine(
|
|
176
234
|
map,
|
|
177
235
|
geojson,
|
|
178
236
|
defaultRouteColor,
|
|
179
237
|
lineLayout,
|
|
180
|
-
|
|
238
|
+
firstLabelLayerId,
|
|
181
239
|
);
|
|
182
240
|
addStops(map, geojson);
|
|
183
241
|
addHighlightedStops(map, geojson);
|
|
@@ -450,10 +508,10 @@ function addRouteLabels(map, geojson) {
|
|
|
450
508
|
});
|
|
451
509
|
}
|
|
452
510
|
|
|
453
|
-
function setupEventListeners(map,
|
|
511
|
+
function setupEventListeners(map, routes) {
|
|
454
512
|
map.on('mousemove', (event) => handleMouseMove(event, map, routes));
|
|
455
513
|
map.on('click', (event) => handleClick(event, map));
|
|
456
|
-
setupTableHoverListeners(
|
|
514
|
+
setupTableHoverListeners(map);
|
|
457
515
|
}
|
|
458
516
|
|
|
459
517
|
function handleMouseMove(event, map, routes) {
|
|
@@ -504,7 +562,7 @@ function handleClick(event, map) {
|
|
|
504
562
|
}
|
|
505
563
|
|
|
506
564
|
function showStopPopup(map, feature) {
|
|
507
|
-
new
|
|
565
|
+
new maplibregl.Popup()
|
|
508
566
|
.setLngLat(feature.geometry.coordinates)
|
|
509
567
|
.setHTML(formatStopPopup(feature))
|
|
510
568
|
.addTo(map);
|
|
@@ -516,7 +574,7 @@ function showRoutePopup(map, features, lngLat) {
|
|
|
516
574
|
(feature) => Number.parseInt(feature.properties.route_short_name, 10),
|
|
517
575
|
);
|
|
518
576
|
|
|
519
|
-
new
|
|
577
|
+
new maplibregl.Popup()
|
|
520
578
|
.setLngLat(lngLat)
|
|
521
579
|
.setHTML(formatRoutePopup(routes))
|
|
522
580
|
.addTo(map);
|
|
@@ -612,7 +670,7 @@ function unHighlightRoutes(map, zoom) {
|
|
|
612
670
|
}
|
|
613
671
|
}
|
|
614
672
|
|
|
615
|
-
function setupTableHoverListeners(
|
|
673
|
+
function setupTableHoverListeners(map) {
|
|
616
674
|
jQuery(() => {
|
|
617
675
|
jQuery('.overview-list a').hover((event) => {
|
|
618
676
|
const routeIdString = jQuery(event.target).data('route-ids');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* global document, jQuery,
|
|
1
|
+
/* global document, jQuery, maplibregl, Pbf, mapStyleUrl, stopData, routeData, routeIds, tripIds, geojsons, gtfsRealtimeUrls */
|
|
2
2
|
/* eslint prefer-arrow-callback: "off", no-unused-vars: "off" */
|
|
3
3
|
|
|
4
4
|
const maps = {};
|
|
@@ -110,7 +110,8 @@ function getStopPopupHtml(feature, stop) {
|
|
|
110
110
|
tripUpdate.trip_update.stop_time_update.filter(
|
|
111
111
|
(stopTimeUpdate) =>
|
|
112
112
|
stopTimeUpdate.stop_id === stop.stop_id &&
|
|
113
|
-
stopTimeUpdate.departure !== null
|
|
113
|
+
(stopTimeUpdate.departure !== null ||
|
|
114
|
+
stopTimeUpdate.arrival !== null) &&
|
|
114
115
|
stopTimeUpdate.schedule_relationship !== 3,
|
|
115
116
|
);
|
|
116
117
|
if (stopTimeUpdatesForStop.length > 0) {
|
|
@@ -146,7 +147,11 @@ function getStopPopupHtml(feature, stop) {
|
|
|
146
147
|
const departureTimes = stopTimeUpdates[direction].map(
|
|
147
148
|
(stopTimeUpdate) =>
|
|
148
149
|
Math.round(
|
|
149
|
-
(stopTimeUpdate.departure
|
|
150
|
+
((stopTimeUpdate.departure
|
|
151
|
+
? stopTimeUpdate.departure.time
|
|
152
|
+
: stopTimeUpdate.arrival.time) -
|
|
153
|
+
Date.now() / 1000) /
|
|
154
|
+
60,
|
|
150
155
|
),
|
|
151
156
|
);
|
|
152
157
|
|
|
@@ -187,7 +192,7 @@ function getStopPopupHtml(feature, stop) {
|
|
|
187
192
|
}
|
|
188
193
|
|
|
189
194
|
function getBounds(geojson) {
|
|
190
|
-
const bounds = new
|
|
195
|
+
const bounds = new maplibregl.LngLatBounds();
|
|
191
196
|
for (const feature of geojson.features) {
|
|
192
197
|
if (feature.geometry.type.toLowerCase() === 'point') {
|
|
193
198
|
bounds.extend(feature.geometry.coordinates);
|
|
@@ -454,7 +459,10 @@ function addVehicleMarker(vehiclePosition, vehicleTripUpdate) {
|
|
|
454
459
|
];
|
|
455
460
|
|
|
456
461
|
// Add marker to map
|
|
457
|
-
const vehicleMarker = new
|
|
462
|
+
const vehicleMarker = new maplibregl.Marker({
|
|
463
|
+
element: el,
|
|
464
|
+
anchor: 'center',
|
|
465
|
+
})
|
|
458
466
|
.setLngLat(coordinates)
|
|
459
467
|
.addTo(maps[visibleTimetableId]);
|
|
460
468
|
|
|
@@ -704,9 +712,9 @@ function createMap(id) {
|
|
|
704
712
|
}
|
|
705
713
|
|
|
706
714
|
const bounds = getBounds(geojson);
|
|
707
|
-
const map = new
|
|
715
|
+
const map = new maplibregl.Map({
|
|
708
716
|
container: `map_timetable_id_${id}`,
|
|
709
|
-
style:
|
|
717
|
+
style: mapStyleUrl,
|
|
710
718
|
center: bounds.getCenter(),
|
|
711
719
|
zoom: 12,
|
|
712
720
|
preserveDrawingBuffer: true,
|
|
@@ -715,7 +723,8 @@ function createMap(id) {
|
|
|
715
723
|
map.initialize = () => fitMapToBounds(map, bounds);
|
|
716
724
|
|
|
717
725
|
map.scrollZoom.disable();
|
|
718
|
-
map.addControl(new
|
|
726
|
+
map.addControl(new maplibregl.NavigationControl());
|
|
727
|
+
map.addControl(new maplibregl.FullscreenControl());
|
|
719
728
|
|
|
720
729
|
map.on('load', () => {
|
|
721
730
|
fitMapToBounds(map, bounds);
|
|
@@ -735,24 +744,28 @@ function fitMapToBounds(map, bounds) {
|
|
|
735
744
|
}
|
|
736
745
|
|
|
737
746
|
function disablePointsOfInterest(map) {
|
|
738
|
-
map.
|
|
747
|
+
const layers = map.getStyle().layers;
|
|
748
|
+
const poiLayerIds = layers
|
|
749
|
+
.filter((layer) => layer.id.startsWith('poi'))
|
|
750
|
+
?.map((layer) => layer.id);
|
|
751
|
+
poiLayerIds.forEach((layerId) => {
|
|
752
|
+
map.setLayoutProperty(layerId, 'visibility', 'none');
|
|
753
|
+
});
|
|
739
754
|
}
|
|
740
755
|
|
|
741
756
|
function addMapLayers(map, geojson, defaultRouteColor, lineLayout) {
|
|
742
|
-
const
|
|
757
|
+
const layers = map.getStyle().layers;
|
|
758
|
+
const firstLabelLayerId = layers.find(
|
|
759
|
+
(layer) => layer.type === 'symbol' && layer.id.includes('label'),
|
|
760
|
+
)?.id;
|
|
743
761
|
|
|
744
|
-
addRouteLineShadow(map, geojson, lineLayout,
|
|
745
|
-
addRouteLineOutline(map, geojson, lineLayout,
|
|
746
|
-
addRouteLine(map, geojson, defaultRouteColor, lineLayout,
|
|
762
|
+
addRouteLineShadow(map, geojson, lineLayout, firstLabelLayerId);
|
|
763
|
+
addRouteLineOutline(map, geojson, lineLayout, firstLabelLayerId);
|
|
764
|
+
addRouteLine(map, geojson, defaultRouteColor, lineLayout, firstLabelLayerId);
|
|
747
765
|
addStops(map, geojson);
|
|
748
766
|
addHighlightedStops(map, geojson);
|
|
749
767
|
}
|
|
750
768
|
|
|
751
|
-
function getFirstSymbolLayerId(map) {
|
|
752
|
-
const layers = map.getStyle().layers;
|
|
753
|
-
return layers.find((layer) => layer.type === 'symbol').id;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
769
|
function addRouteLineShadow(map, geojson, lineLayout, firstSymbolId) {
|
|
757
770
|
map.addLayer(
|
|
758
771
|
{
|
|
@@ -919,7 +932,7 @@ function handleClick(event, map) {
|
|
|
919
932
|
}
|
|
920
933
|
|
|
921
934
|
function showStopPopup(map, feature) {
|
|
922
|
-
new
|
|
935
|
+
new maplibregl.Popup()
|
|
923
936
|
.setLngLat(feature.geometry.coordinates)
|
|
924
937
|
.setHTML(getStopPopupHtml(feature, stopData[feature.properties.stop_id]))
|
|
925
938
|
.addTo(map);
|
|
@@ -1038,18 +1051,27 @@ function createMaps() {
|
|
|
1038
1051
|
gtfsRealtimeUrls?.realtimeVehiclePositions?.url
|
|
1039
1052
|
) {
|
|
1040
1053
|
// Popup for realtime vehicle locations
|
|
1041
|
-
|
|
1054
|
+
const markerHeight = 20;
|
|
1055
|
+
const markerRadius = 10;
|
|
1056
|
+
const linearOffset = 15;
|
|
1057
|
+
vehiclePopup = new maplibregl.Popup({
|
|
1042
1058
|
closeOnClick: false,
|
|
1043
1059
|
className: 'vehicle-popup',
|
|
1044
1060
|
offset: {
|
|
1045
|
-
top: [0,
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
'
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1061
|
+
top: [0, 0],
|
|
1062
|
+
'top-left': [0, 0],
|
|
1063
|
+
'top-right': [0, 0],
|
|
1064
|
+
bottom: [0, -markerHeight],
|
|
1065
|
+
'bottom-left': [
|
|
1066
|
+
linearOffset,
|
|
1067
|
+
(markerHeight - markerRadius + linearOffset) * -1,
|
|
1068
|
+
],
|
|
1069
|
+
'bottom-right': [
|
|
1070
|
+
-linearOffset,
|
|
1071
|
+
(markerHeight - markerRadius + linearOffset) * -1,
|
|
1072
|
+
],
|
|
1073
|
+
left: [markerRadius, (markerHeight - markerRadius) * -1],
|
|
1074
|
+
right: [-markerRadius, (markerHeight - markerRadius) * -1],
|
|
1053
1075
|
},
|
|
1054
1076
|
});
|
|
1055
1077
|
|
|
@@ -21,7 +21,6 @@ include formatting_functions.pug
|
|
|
21
21
|
|
|
22
22
|
//- Use !{variable} format to inject values from pug to client side js
|
|
23
23
|
script.
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
})();
|
|
24
|
+
const geojson = !{JSON.stringify(geojson) || '\'\''};
|
|
25
|
+
const mapStyleUrl = '#{config.mapStyleUrl}';
|
|
26
|
+
createSystemMap();
|
|
@@ -6,11 +6,11 @@ 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://
|
|
10
|
-
script.
|
|
11
|
-
mapboxgl.accessToken = '#{config.mapboxAccessToken}';
|
|
9
|
+
script(src="https://unpkg.com/maplibre-gl@^4.7.1/dist/maplibre-gl.js")
|
|
10
|
+
script(src="https://unpkg.com/@maplibre/maplibre-gl-geocoder@1.5.0/dist/maplibre-gl-geocoder.min.js")
|
|
12
11
|
script(src=`${config.assetPath}js/system-map.js`)
|
|
13
12
|
|
|
14
|
-
link(href="https://
|
|
13
|
+
link(href="https://unpkg.com/maplibre-gl@^4.7.1/dist/maplibre-gl.css" rel="stylesheet")
|
|
14
|
+
link(href="https://unpkg.com/@maplibre/maplibre-gl-geocoder@1.5.0/dist/maplibre-gl-geocoder.css" rel="stylesheet")
|
|
15
15
|
|
|
16
16
|
link(rel="stylesheet" href=`${config.assetPath}css/overview_styles.css`)
|
|
@@ -68,5 +68,5 @@ include formatting_functions.pug
|
|
|
68
68
|
|
|
69
69
|
if config.showMap
|
|
70
70
|
script.
|
|
71
|
-
const { routeData, stopData, pageData: { routeIds, tripIds, stopIds, geojsons
|
|
71
|
+
const { gtfsRealtimeUrls, mapStyleUrl, routeData, stopData, pageData: { routeIds, tripIds, stopIds, geojsons } } = !{JSON.stringify(prepareMapData(timetablePage, config))};
|
|
72
72
|
createMaps();
|
|
@@ -13,10 +13,8 @@ block extraHeader
|
|
|
13
13
|
script(src=`${config.assetPath}js/gtfs-realtime.browser.proto.js`)
|
|
14
14
|
|
|
15
15
|
if config.showMap
|
|
16
|
-
link(href="https://
|
|
17
|
-
script(src="https://
|
|
18
|
-
script.
|
|
19
|
-
mapboxgl.accessToken = '#{config.mapboxAccessToken}';
|
|
16
|
+
link(href="https://unpkg.com/maplibre-gl@^4.7.1/dist/maplibre-gl.css" rel="stylesheet")
|
|
17
|
+
script(src="https://unpkg.com/maplibre-gl@^4.7.1/dist/maplibre-gl.js")
|
|
20
18
|
script(src=`${config.assetPath}js/timetable-map.js`)
|
|
21
19
|
|
|
22
20
|
if config.hasGtfsRealtimeAlerts
|