Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bc7e27e
feat(route-viewer): route details viewer prototype
miles-grant-ibigroup Aug 19, 2021
1c0655b
improvement(route-viewer): improve color styling using tinycolor
miles-grant-ibigroup Aug 24, 2021
3011751
improvement(route-viewer): route details functionality + fill full si…
miles-grant-ibigroup Aug 24, 2021
7a0f5ae
Merge branch 'dev' into route-details-viewer
miles-grant-ibigroup Aug 25, 2021
0942770
improvement(route-details): show stops of pattern
miles-grant-ibigroup Aug 25, 2021
6e61767
improvement(route-viewer): resolve route details stop list edge cases
miles-grant-ibigroup Aug 26, 2021
ced75d8
feat(route-viewer): show realtime vehicle positions
miles-grant-ibigroup Aug 26, 2021
583982f
refactor: avoid crash on missing route data
miles-grant-ibigroup Aug 26, 2021
516d21a
improvement(map): when viewing pattern, show only pattern and its stops
miles-grant-ibigroup Aug 26, 2021
c0ccde2
improvement(route-details-viewer): sort headsigns by number of vehicl…
miles-grant-ibigroup Aug 26, 2021
747e651
style(route-viewer): cleanup
miles-grant-ibigroup Aug 26, 2021
99ce62c
improvement(map): realtime vehicles show icon based on their mode
miles-grant-ibigroup Aug 26, 2021
9df6f56
improvement(route-details): support routing directly to pattern viewer
miles-grant-ibigroup Aug 26, 2021
fef76d1
improvement(route-details): resolve duplicate headsigns based on geom…
miles-grant-ibigroup Aug 27, 2021
f99cd2c
improvement(api): reduce queries to OTP by receiving all pattern geom…
miles-grant-ibigroup Aug 27, 2021
9baddca
refactor(connected-stops-overlay): fix regression and show pattern stops
miles-grant-ibigroup Aug 27, 2021
f1d6f5c
improvement(route-details): highlight hovered stops on map
miles-grant-ibigroup Aug 27, 2021
0bef23b
improvement(route-details): show realtime vehicle position info on hover
miles-grant-ibigroup Aug 27, 2021
10baa92
refactor(connected-transit-vehicle-overlay): adjust tooltip to server…
miles-grant-ibigroup Aug 27, 2021
2f07d6b
revert: match OTP vehicle position schema
miles-grant-ibigroup Aug 27, 2021
237eeac
refactor: address pr comments
miles-grant-ibigroup Aug 30, 2021
dbf66c7
refactor: more robust path generation
miles-grant-ibigroup Aug 30, 2021
ac380e1
Merge branch 'route-viewer-filter-and-search' into route-details-viewer
miles-grant-ibigroup Aug 30, 2021
78686a5
refactor: polish and cleanup
miles-grant-ibigroup Aug 30, 2021
62843e8
improvement(route-details): add internationalization
miles-grant-ibigroup Aug 30, 2021
8e45300
refactor(route-details-viewer): avoid white-screen crashes
miles-grant-ibigroup Aug 31, 2021
a52e1df
refactor(route-details-viewer): avoid white-screen crashes when updat…
miles-grant-ibigroup Sep 1, 2021
bfb7698
improvement(route-viewer): scroll to active route on initial render
miles-grant-ibigroup Sep 1, 2021
712c2a1
Merge branch 'route-viewer-filter-and-search' into route-details-viewer
miles-grant-ibigroup Sep 7, 2021
c55bc53
Merge branch 'route-viewer-filter-and-search' into route-details-viewer
miles-grant-ibigroup Sep 14, 2021
cc444a4
refactor(route-details): update icon import
miles-grant-ibigroup Sep 14, 2021
2d07989
refactor: correct typo
miles-grant-ibigroup Sep 14, 2021
25aa724
refactor(route-details): address pr feedback
miles-grant-ibigroup Sep 15, 2021
ac6e90d
Merge branch 'route-viewer-filter-and-search' into route-details-viewer
miles-grant-ibigroup Sep 15, 2021
d5080c9
refactor(connected-transit-vehicle-overlay): adjust for latest OTP ch…
miles-grant-ibigroup Sep 15, 2021
c672387
revert(RouteDetails): remove color; remove headsign buttons
miles-grant-ibigroup Sep 16, 2021
140c81e
refactor(RouteViewer): clean up, extract routeRow to new file
miles-grant-ibigroup Sep 16, 2021
30f4a83
improvement: show all route shapes when OTP instances don't support i…
miles-grant-ibigroup Sep 17, 2021
9a71395
refactor: address pr comments
miles-grant-ibigroup Sep 20, 2021
a5ea1e0
chore(i18n): Add matching FR strings.
binh-dam-ibigroup Sep 20, 2021
092b53f
refactor: correct typos and sort imports
miles-grant-ibigroup Sep 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

.sidebar {
height: 100%;
padding: 10px;
padding: 0;
box-shadow: 3px 0px 12px #00000052;
z-index: 1000;
}
Expand Down
16 changes: 16 additions & 0 deletions i18n/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ components:
tripDurationFormatZeroHours: "{minutes, number} min"
# TODO: Distinguish between one hour (singular) and 2 hours or more?
tripDurationFormat: "{hours, number} hr {minutes, number} min"
RouteDetails:
operatedBy: "Operated by {agencyName}"
moreDetails: "More Details"
stopsTo: "Towards"
selectADirection: "Select a direction..."
RouteViewer:
allAgencies: All Agencies
allModes: All Modes # Note to translator: This text is width-constrained.
Expand All @@ -47,6 +52,17 @@ components:
agencyFilter: Agency Filter
modeFilter: Mode Filter
details: " " # If the string is left blank, React-Intl renders the id
RouteRow:
operatorLogoAltText: '{operatorName} logo'
TransitVehicleOverlay:
# keys designed to match API output
incoming_at: "approaching {stop}"
stopped_at: "doors open at {stop}"
in_transit_to: "next stop {stop}"

vehicleName: "Vehicle {vehicleNumber}: "
realtimeVehicleInfo: "<b>{vehicleNameOrBlank}</b>{relativeTime}"
travelingAt: "traveling at {milesPerHour}"
ItinerarySummary:
fareCost: "{useMaxFare, select,
true {{minTotalFare} - {maxTotalFare}}
Expand Down
16 changes: 16 additions & 0 deletions i18n/fr-FR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ components:
tripDurationFormatZeroHours: "{minutes, number} mn"
# TODO: Distinguish between one hour (singular) and 2 hours or more?
tripDurationFormat: "{hours, number} h {minutes, number} mn"
RouteDetails:
operatedBy: "Exploité par {agencyName}"
moreDetails: "Plus d'infos"
stopsTo: "Direction"
selectADirection: "Choisissez une direction..."
RouteViewer:
allAgencies: Tous exploitants
allModes: Tous modes # Note to translator: This text is width-constrained.
Expand All @@ -22,6 +27,17 @@ components:
agencyFilter: Filtre pour les exploitants
modeFilter: Filtre pour les modes
details: " " # If the string is left blank, React-Intl renders the id
RouteRow:
operatorLogoAltText: "Logo de {operatorName}"
TransitVehicleOverlay:
# keys designed to match API output
incoming_at: "Approchant {stop}"
stopped_at: "À quai à {stop}"
in_transit_to: "Prochain arrêt : {stop}"

vehicleName: "Véhicule {vehicleNumber}: "
realtimeVehicleInfo: "<b>{vehicleNameOrBlank}</b>{relativeTime}"
travelingAt: "Vitesse : {milesPerHour}"
ItinerarySummary:
fareCost: "{useMaxFare, select,
true {{minTotalFare} - {maxTotalFare}}
Expand Down
61 changes: 56 additions & 5 deletions lib/actions/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -507,19 +507,25 @@ export function findRoute (params) {

export function findPatternsForRoute (params) {
return createQueryAction(
`index/routes/${params.routeId}/patterns`,
`index/routes/${params.routeId}/patterns?includeGeometry=true`,
findPatternsForRouteResponse,
findPatternsForRouteError,
{
noThrottle: true,
postprocess: (payload, dispatch) => {
// load geometry for each pattern
payload.forEach(ptn => {
dispatch(findGeometryForPattern({
patternId: ptn.id,
routeId: params.routeId
}))
// Some OTP instances don't support includeGeometry.
// We need to manually fetch geometry in these cases.
if (!ptn.geometry) {
dispatch(findGeometryForPattern({
patternId: ptn.id,
routeId: params.routeId
}))
}
})
},

rewritePayload: (payload) => {
// convert pattern array to ID-mapped object
const patterns = {}
Expand Down Expand Up @@ -556,6 +562,29 @@ export function findGeometryForPattern (params) {
)
}

// Stops for pattern query

export const findStopsForPatternResponse = createAction('FIND_STOPS_FOR_PATTERN_RESPONSE')
export const findStopsForPatternError = createAction('FIND_STOPS_FOR_PATTERN_ERROR')

export function findStopsForPattern (params) {
return createQueryAction(
`index/patterns/${params.patternId}/stops`,
findStopsForPatternResponse,
findStopsForPatternError,
{
noThrottle: true,
rewritePayload: (payload) => {
return {
patternId: params.patternId,
routeId: params.routeId,
stops: payload
}
}
}
)
}

// TNC ETA estimate lookup query

export const transportationNetworkCompanyEtaResponse = createAction('TNC_ETA_RESPONSE')
Expand Down Expand Up @@ -682,6 +711,27 @@ export function findStopsWithinBBox (params) {

export const clearStops = createAction('CLEAR_STOPS_OVERLAY')

// Realtime Vehicle positions query

const receivedVehiclePositions = createAction('REALTIME_VEHICLE_POSITIONS_RESPONSE')
const receivedVehiclePositionsError = createAction('REALTIME_VEHICLE_POSITIONS_ERROR')

export function getVehiclePositionsForRoute (routeId) {
return createQueryAction(
`index/routes/${routeId}/vehicles`,
receivedVehiclePositions,
receivedVehiclePositionsError,
{
rewritePayload: (payload) => {
return {
routeId: routeId,
vehicles: payload
}
}
}
)
}

const throttledUrls = {}

function now () {
Expand Down Expand Up @@ -720,6 +770,7 @@ window.setInterval(() => {
*/

function createQueryAction (endpoint, responseAction, errorAction, options = {}) {
/* eslint-disable-next-line complexity */
return async function (dispatch, getState) {
const state = getState()
const { config } = state.otp
Expand Down
34 changes: 25 additions & 9 deletions lib/actions/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { matchPath } from 'react-router'

import { getUiUrlParams, getModesForActiveAgencyFilter } from '../util/state'
import { getDefaultLocale, loadLocaleData } from '../util/i18n'
import { getPathFromParts } from '../util/ui'

import { findRoute, setUrlSearch } from './api'
import { setMapCenter, setMapZoom, setRouterId } from './config'
Expand Down Expand Up @@ -47,22 +48,31 @@ export function routeTo (url, replaceSearch, routingMethod = push) {
* route or stop).
*/
export function matchContentToUrl (location) {
// eslint-disable-next-line complexity
return function (dispatch, getState) {
// This is a bit of a hack to make up for the fact that react-router does
// not always provide the match params as expected.
// https://github.com/ReactTraining/react-router/issues/5870#issuecomment-394194338
const root = location.pathname.split('/')[1]
const match = matchPath(location.pathname, {
exact: true,
exact: false,
path: `/${root}/:id`,
strict: false
})
const id = match && match.params && match.params.id
const id = match?.params?.id
switch (root) {
case 'route':
if (id) {
dispatch(findRoute({ routeId: id }))
dispatch(setViewedRoute({ routeId: id }))
// Check for pattern "submatch"
const subMatch = matchPath(location.pathname, {
exact: true,
path: `/${root}/:id/pattern/:patternId`,
strict: false
})
const patternId = subMatch?.params?.patternId
// patternId may be undefined, which is OK as the route will still be routed
dispatch(setViewedRoute({ patternId, routeId: id }))
} else {
dispatch(setViewedRoute(null))
dispatch(setMainPanelContent(MainPanelContent.ROUTE_VIEWER))
Expand Down Expand Up @@ -196,23 +206,29 @@ export const clearPanel = createAction('CLEAR_MAIN_PANEL')
export function setViewedStop (payload) {
return function (dispatch, getState) {
dispatch(viewStop(payload))
const path = payload && payload.stopId
? `/stop/${payload.stopId}`
: '/stop'
// payload.stopId may be undefined, which is ok as will be ignored by getPathFromParts
const path = getPathFromParts('stop', payload?.stopId)
dispatch(routeTo(path))
}
}

const viewStop = createAction('SET_VIEWED_STOP')

export const setHoveredStop = createAction('SET_HOVERED_STOP')

export const setViewedTrip = createAction('SET_VIEWED_TRIP')

export function setViewedRoute (payload) {
return function (dispatch, getState) {
dispatch(viewRoute(payload))
const path = payload && payload.routeId
? `/route/${payload.routeId}`
: '/route'

const path = getPathFromParts(
'route',
payload?.routeId,
// If a pattern is supplied, include pattern in path
payload?.patternId && 'pattern',
payload?.patternId
)
dispatch(routeTo(path))
}
}
Expand Down
4 changes: 4 additions & 0 deletions lib/components/app/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
box-sizing: border-box;
}

/* Batch routing panel requires padding removed from sidebar */
.batch-routing-panel {
padding: 10px;
}
/* View Switcher Styling */
.view-switcher {
align-items: center;
Expand Down
14 changes: 12 additions & 2 deletions lib/components/map/connected-route-viewer-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@ import { connect } from 'react-redux'

const mapStateToProps = (state, ownProps) => {
const viewedRoute = state.otp.ui.viewedRoute
return {
routeData: viewedRoute && state.otp.transitIndex.routes

const routeData =
viewedRoute && state.otp.transitIndex.routes
? state.otp.transitIndex.routes[viewedRoute.routeId]
: null
let filteredPatterns = routeData?.patterns

// If a pattern is selected, hide all other patterns
if (viewedRoute?.patternId && routeData?.patterns) {
filteredPatterns = {[viewedRoute.patternId]: routeData.patterns[viewedRoute.patternId]}
}

return {
routeData: { ...routeData, patterns: filteredPatterns }
}
}

Expand Down
10 changes: 10 additions & 0 deletions lib/components/map/connected-stop-marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,18 @@ import { setViewedStop } from '../../actions/ui'
// connect to the redux store

const mapStateToProps = (state, ownProps) => {
const { highlightedStop, viewedRoute } = state.otp.ui
const routeData = viewedRoute && state.otp.transitIndex.routes?.[viewedRoute.routeId]
const hoverColor = routeData?.routeColor || '#333'

return {
languageConfig: state.otp.config.language,
leafletPath: {
color: '#000',
fillColor: highlightedStop === ownProps.entity.id ? hoverColor : '#FFF',
fillOpacity: 1,
weight: 1
},
stop: ownProps.entity
}
}
Expand Down
18 changes: 15 additions & 3 deletions lib/components/map/connected-stops-overlay.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import StopsOverlay from '@opentripplanner/stops-overlay'
import StopMarker from './connected-stop-marker'
import { connect } from 'react-redux'

import { findStopsWithinBBox } from '../../actions/api'

import StopMarker from './connected-stop-marker'

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
const { viewedRoute } = state.otp.ui

let { stops } = state.otp.overlay.transit
let minZoom = 15

// If a pattern is being shown, show only the pattern's stops and show them large
if (viewedRoute?.patternId && state.otp.transitIndex.routes) {
stops = state.otp.transitIndex.routes[viewedRoute.routeId]?.patterns?.[viewedRoute.patternId].stops
minZoom = 2
}

return {
stops: state.otp.overlay.transit.stops,
stops: stops || [],
symbols: [
{
minZoom: 15,
minZoom,
symbol: StopMarker
}
]
Expand Down
Loading