Skip to content

Commit c479916

Browse files
Merge pull request #657 from opentripplanner/vector-tiles
Move to Vector Tiles (MapLibreGL)
2 parents 0aad980 + 37494c2 commit c479916

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+17764
-19271
lines changed

__tests__/components/viewers/__snapshots__/stop-viewer.js.snap

+16,336-17,285
Large diffs are not rendered by default.

__tests__/reducers/__snapshots__/create-otp-reducer.js.snap

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ Object {
99
"mobile": "BOTH_LOCATIONS_CHANGED",
1010
},
1111
"debouncePlanTimeMs": 0,
12-
"focusRoute": false,
1312
"homeTimezone": "America/Los_Angeles",
1413
"language": Object {},
1514
"onTimeThresholdSeconds": 60,

a11y/a11y.test.js

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ async function runAxeTestOnPath(otpPath) {
2828
const page = await browser.newPage()
2929
const filePath = `http://localhost:${MOCK_SERVER_PORT}/#${otpPath}`
3030
await Promise.all([
31+
page.setViewport({
32+
deviceScaleFactor: 1,
33+
height: 1080,
34+
width: 1920
35+
}),
3136
page.goto(filePath),
3237
page.waitForNavigation({ waitUntil: 'networkidle2' })
3338
])

index.css

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
@import url(node_modules/bootstrap/dist/css/bootstrap.min.css);
22

3-
@import url(https://unpkg.com/[email protected]/dist/leaflet.css);
4-
@import url(node_modules/transitive-js/lib/transitive.css);
3+
@import url(node_modules/maplibre-gl/dist/maplibre-gl.css);
54

65
@import url(lib/components/admin/call-taker.css);
76
@import url(lib/components/app/app.css);

lib/actions/api.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,8 @@ export function vehicleRentalQuery(
557557
export const findStopResponse = createAction('FIND_STOP_RESPONSE')
558558
export const findStopError = createAction('FIND_STOP_ERROR')
559559

560-
export function fetchStopInfo(stop) {
561-
return executeOTPAction('fetchStopInfo', stop)
560+
export function fetchStopInfo(map, stop) {
561+
return executeOTPAction('fetchStopInfo', map, stop)
562562
}
563563

564564
// Single trip lookup query

lib/actions/apiV1.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import L from 'leaflet'
21
import qs from 'qs'
32

43
import {
@@ -16,6 +15,7 @@ import {
1615
findRoutesAtStop,
1716
findStopError,
1817
findStopResponse,
18+
findStopsForPattern,
1919
findStopsForTrip,
2020
findStopTimesForStop,
2121
findStopTimesForTrip,
@@ -28,6 +28,10 @@ import {
2828
import { setViewedStop } from './ui'
2929
import { zoomToStop } from './map'
3030

31+
// Import must be done like this as maplibregl is incompatible with jest
32+
let maplibregl = null
33+
if (typeof jest === 'undefined') maplibregl = require('maplibre-gl')
34+
3135
const findTrip = (params) =>
3236
createQueryAction(
3337
`index/trips/${params.tripId}`,
@@ -56,7 +60,9 @@ export function vehicleRentalQuery(
5660

5761
function findNearbyAmenities({ lat, lon, radius = 300 }, stopId) {
5862
return function (dispatch, getState) {
59-
const bounds = L.latLng(lat, lon).toBounds(radius)
63+
if (typeof jest !== 'undefined') return
64+
65+
const bounds = new maplibregl.LngLat(lon, lat).toBounds(radius)
6066
const { lat: low, lng: left } = bounds.getSouthWest()
6167
const { lat: up, lng: right } = bounds.getNorthEast()
6268
dispatch(
@@ -123,7 +129,7 @@ export const findStop = (params) =>
123129
}
124130
)
125131

126-
const fetchStopInfo = (stop) =>
132+
const fetchStopInfo = (map, stop) =>
127133
async function (dispatch, getState) {
128134
await dispatch(findStop({ stopId: stop.stopId }))
129135
const state = getState()
@@ -149,7 +155,7 @@ const fetchStopInfo = (stop) =>
149155
dispatch(
150156
findNearbyAmenities({ lat, lon, radius: nearbyRadius }, stop.stopId)
151157
)
152-
dispatch(zoomToStop(fetchedStop))
158+
dispatch(zoomToStop(map, fetchedStop))
153159
}
154160
}
155161

@@ -189,6 +195,12 @@ export const findPatternsForRoute = (params) =>
189195
})
190196
)
191197
}
198+
dispatch(
199+
findStopsForPattern({
200+
patternId: ptn.id,
201+
routeId: params.routeId
202+
})
203+
)
192204
})
193205
},
194206

lib/actions/apiV2.js

+22-17
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ import {
1717
receivedVehiclePositions,
1818
receivedVehiclePositionsError
1919
} from './api'
20-
import { setMapZoom } from './config'
2120
import { zoomToStop } from './map'
2221

22+
const LIGHT_GRAY = '666666'
23+
2324
/**
2425
* Generic helper for crafting GraphQL queries.
2526
*/
@@ -147,7 +148,7 @@ export const vehicleRentalQuery = (
147148
// we should re-write the rest of the UI to match OTP's behavior instead
148149
rewritePayload: (payload) => {
149150
return {
150-
stations: payload?.data?.rentalVehicles.map((vehicle) => {
151+
stations: payload?.data?.rentalVehicles?.map((vehicle) => {
151152
return {
152153
allowPickup: vehicle.allowPickupNow,
153154
id: vehicle.vehicleId,
@@ -297,27 +298,27 @@ const findNearbyAmenities = ({ lat, lon, radius = 300, stopId }) => {
297298
{
298299
noThrottle: true,
299300
rewritePayload: (payload) => {
300-
if (!payload.data)
301+
if (!payload.data?.nearest)
301302
return {
302303
bikeRental: { stations: [] },
303304
vehicleRentalQuery: { stations: [] }
304305
}
305306
const { edges } = payload.data.nearest || []
306-
const bikeStations = edges.filter(
307+
const bikeStations = edges?.filter(
307308
(edge) =>
308309
edge?.node?.place?.bikesAvailable !== undefined ||
309310
!!edge?.node?.place?.bicyclePlaces ||
310311
edge?.node?.place?.vehicleType?.formFactor === 'BICYCLE'
311312
)
312-
const parkAndRides = edges.filter(
313+
const parkAndRides = edges?.filter(
313314
(edge) => edge?.node?.place?.carPlaces
314315
)
315-
const vehicleRentals = edges.filter(
316+
const vehicleRentals = edges?.filter(
316317
(edge) => edge?.node?.place?.vehicleType?.formFactor === 'SCOOTER'
317318
)
318319
return {
319320
bikeRental: {
320-
stations: bikeStations.map((edge) => {
321+
stations: bikeStations?.map((edge) => {
321322
const {
322323
__typename,
323324
bikesAvailable,
@@ -344,7 +345,7 @@ const findNearbyAmenities = ({ lat, lon, radius = 300, stopId }) => {
344345
}
345346
})
346347
},
347-
parkAndRideLocations: parkAndRides.map((edge) => {
348+
parkAndRideLocations: parkAndRides?.map((edge) => {
348349
const { id, lat, lon, name } = edge?.node?.place
349350
return {
350351
distance: edge.node.distance,
@@ -358,7 +359,7 @@ const findNearbyAmenities = ({ lat, lon, radius = 300, stopId }) => {
358359
}),
359360
stopId,
360361
vehicleRental: {
361-
stations: vehicleRentals.map((edge) => {
362+
stations: vehicleRentals?.map((edge) => {
362363
const { id, lat, lon, name, network, networks } =
363364
edge?.node?.place
364365
return {
@@ -380,7 +381,7 @@ const findNearbyAmenities = ({ lat, lon, radius = 300, stopId }) => {
380381
)
381382
}
382383

383-
const fetchStopInfo = (stop) => {
384+
const fetchStopInfo = (map, stop) => {
384385
const { stopId } = stop
385386
if (!stopId)
386387
return function (dispatch, getState) {
@@ -424,17 +425,20 @@ const fetchStopInfo = (stop) => {
424425
})
425426
)
426427

427-
dispatch(zoomToStop(stop))
428-
429-
if (stop?.geometries?.geoJson?.type !== 'Point') {
430-
dispatch(setMapZoom(10))
431-
}
428+
dispatch(
429+
zoomToStop(
430+
map,
431+
stop,
432+
stop?.geometries?.geoJson?.type !== 'Point' && 10
433+
)
434+
)
432435
},
433436
rewritePayload: (payload) => {
434437
const { stop } = payload?.data
435438
if (!stop) return findStopError()
436439

437-
const color = stop.routes?.length > 0 && `#${stop.routes[0].color}`
440+
const color =
441+
stop.routes?.length > 0 && `#${stop.routes[0]?.color || LIGHT_GRAY}`
438442

439443
// Doing some OTP1 compatibility rewriting here
440444
return {
@@ -583,7 +587,8 @@ export const findRoute = (params) =>
583587
newRoute.patterns.forEach((pattern) => {
584588
const patternStops = pattern.stops.map((stop) => {
585589
const color =
586-
stop.routes?.length > 0 && `#${stop.routes[0].color}`
590+
stop.routes?.length > 0 &&
591+
`#${stop.routes[0]?.color || LIGHT_GRAY}`
587592
if (stop.routes) delete stop.routes
588593
return { ...stop, color }
589594
})

lib/actions/config.js

-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@ import { createAction } from 'redux-actions'
33
export const setAutoPlan = createAction('SET_AUTOPLAN')
44

55
// TODO: this should eventually be handled via mapState
6-
export const setMapCenter = createAction('SET_MAP_CENTER')
7-
export const setMapZoom = createAction('SET_MAP_ZOOM')
86
export const setRouterId = createAction('SET_ROUTER_ID')
97
export const updateOverlayVisibility = createAction('UPDATE_OVERLAY_VISIBILITY')

lib/actions/map.js

+21-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import getGeocoder from '@opentripplanner/geocoder'
55
import { clearActiveSearch } from './form'
66
import { deleteUserPlace } from './user'
77
import { routingQuery } from './api'
8-
import { setMapCenter, setMapZoom } from './config'
98

109
/* SET_LOCATION action creator. Updates a from or to location in the store
1110
*
@@ -47,11 +46,26 @@ export function clearLocation(payload) {
4746
}
4847
}
4948

50-
export function zoomToStop(stop) {
51-
return function (dispatch, getState) {
52-
if (!stop) return
53-
dispatch(setMapZoom({ zoom: 17 }))
54-
dispatch(setMapCenter({ lat: stop.lat, lon: stop.lon }))
49+
/**
50+
* Centers the given map to the coordinates of the specified place.
51+
*/
52+
export function setMapCenter(map /* MapRef */, location, zoom) {
53+
return function () {
54+
const { lat, lon } = location
55+
if (map && !isNaN(lat) && !isNaN(lon)) {
56+
map.jumpTo({ center: [lon, lat], zoom })
57+
}
58+
}
59+
}
60+
61+
/**
62+
* Animates the map to the specified stop and the specified zoom level.
63+
*/
64+
export function zoomToStop(map /* MapRef */, stop, zoom) {
65+
return function () {
66+
if (stop && map) {
67+
map.flyTo({ center: [stop.lon, stop.lat], zoom: zoom || 17 })
68+
}
5569
}
5670
}
5771

@@ -148,7 +162,7 @@ export const setElevationPoint = createAction('SET_ELEVATION_POINT')
148162
export const setMapPopupLocation = createAction('SET_MAP_POPUP_LOCATION')
149163

150164
export function setMapPopupLocationAndGeocode(mapEvent) {
151-
const location = coreUtils.map.constructLocation(mapEvent.latlng)
165+
const location = coreUtils.map.constructLocation(mapEvent.lngLat)
152166
return function (dispatch, getState) {
153167
dispatch(setMapPopupLocation({ location }))
154168
getGeocoder(getState().otp.config.geocoder)

lib/actions/ui.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import { getModesForActiveAgencyFilter, getUiUrlParams } from '../util/state'
1313
import { getPathFromParts } from '../util/ui'
1414

1515
import { clearActiveSearch, parseUrlQueryString, setActiveSearch } from './form'
16-
import { clearLocation } from './map'
16+
import { clearLocation, setMapCenter } from './map'
1717
import { findRoute, setUrlSearch } from './api'
1818
import { setActiveItinerary } from './narrative'
19-
import { setMapCenter, setMapZoom, setRouterId } from './config'
19+
import { setRouterId } from './config'
2020

2121
const updateLocale = createAction('UPDATE_LOCALE')
2222

@@ -62,7 +62,6 @@ const viewStop = createAction('SET_VIEWED_STOP')
6262
export const setHoveredStop = createAction('SET_HOVERED_STOP')
6363
export const setViewedTrip = createAction('SET_VIEWED_TRIP')
6464
const viewRoute = createAction('SET_VIEWED_ROUTE')
65-
export const unfocusRoute = createAction('UNFOCUS_ROUTE')
6665
export const toggleAutoRefresh = createAction('TOGGLE_AUTO_REFRESH')
6766
const setPreviousItineraryView = createAction('SET_PREVIOUS_ITINERARY_VIEW')
6867
export const setPopupContent = createAction('SET_POPUP_CONTENT')
@@ -97,6 +96,16 @@ export function routeTo(url, replaceSearch, routingMethod = push) {
9796

9897
export function setViewedRoute(payload) {
9998
return function (dispatch, getState) {
99+
const { otp } = getState()
100+
const { viewedRoute } = otp.ui
101+
if (
102+
viewedRoute &&
103+
payload?.viewedRoute?.routeId === viewedRoute.routeId &&
104+
payload?.viewedRoute?.patternId === viewedRoute.patternId
105+
) {
106+
return
107+
}
108+
100109
dispatch(viewRoute(payload))
101110

102111
const path = getPathFromParts(
@@ -167,7 +176,7 @@ function idToParams(id, delimiter = ',') {
167176
* Checks URL and redirects app to appropriate content (e.g., viewed
168177
* route or stop).
169178
*/
170-
export function matchContentToUrl(location) {
179+
export function matchContentToUrl(map, location) {
171180
// eslint-disable-next-line complexity
172181
return function (dispatch, getState) {
173182
const state = getState()
@@ -224,8 +233,7 @@ export function matchContentToUrl(location) {
224233
}
225234
console.log(lat, lon, zoom, routerId)
226235
// Update map location/zoom and optionally override router ID.
227-
if (+lat && +lon) dispatch(setMapCenter({ lat, lon }))
228-
if (+zoom) dispatch(setMapZoom({ zoom }))
236+
if (+lat && +lon) dispatch(setMapCenter(map, { lat, lon }, zoom))
229237
// If router ID is provided, override the default routerId.
230238
if (routerId) dispatch(setRouterId(routerId))
231239
dispatch(setMainPanelContent(null))

0 commit comments

Comments
 (0)