From 252805e4cdbe81d41d2cfd848ebb0dacff7dff2d Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:23:18 -0400 Subject: [PATCH 1/6] fix(RouteDetails): Extract and fix method for keeping patterns. --- __tests__/util/viewer.js | 78 ++++++++++++++++++- lib/components/viewers/route-details.tsx | 98 +++++++----------------- lib/util/viewer.js | 54 ++++++++++++- 3 files changed, 158 insertions(+), 72 deletions(-) diff --git a/__tests__/util/viewer.js b/__tests__/util/viewer.js index 500e5d4d8..fbed8ef32 100644 --- a/__tests__/util/viewer.js +++ b/__tests__/util/viewer.js @@ -1,5 +1,19 @@ import '../test-utils/mock-window-url' -import { extractHeadsignFromPattern } from '../../lib/util/viewer' +import { + extractHeadsignFromPattern, + extractMainHeadsigns +} from '../../lib/util/viewer' + +function createStop(id) { + return { + id, + name: id + } +} + +function prefixHeadsign(pattern) { + pattern.headsign = `To ${pattern.headsign}` +} describe('util > viewer', () => { describe('extractHeadsignFromPattern', () => { @@ -26,4 +40,66 @@ describe('util > viewer', () => { ) }) }) + + describe('extractMainHeadsigns', () => { + it('should retain the essential patterns', () => { + // Consider the following patterns P1, P2, P3 of the same route with the same headsigns: + // Stops 1 2 3 4 5 6 7 --> direction of travel + // P1: o--o--o--o--o + // P2: o--o-----o--o + // P3: o--o--o + // + // P3 should be removed because it is a subset of P1. + // P1 and P2 should be kept. + // Patterns are assumed in descending length order because + // pre-sorting happened before extractMainHeadsigns is invoked (key order matters). + const headsign = 'Everett via Lynnwood' + const route = '512' + const patterns = { + P1: { + headsign, + id: 'P1', + name: '512 to Everett Station (CommTrans:2861) from SODO Busway & S Royal Brougham Way (kcm:99267)', + patternGeometry: { + length: 1404, + points: 'p1-points' + }, + stops: [ + createStop('S1'), + createStop('S2'), + createStop('S3'), + createStop('S4'), + createStop('S5') + ] + }, + P2: { + headsign, + id: 'P2', + name: '512 to Hewitt Ave & Virginia Ave (CommTrans:427)', + patternGeometry: { + length: 1072, + points: 'p2-points' + }, + stops: [ + createStop('S3'), + createStop('S4'), + createStop('S6'), + createStop('S7') + ] + }, + P3: { + headsign, + id: 'P3', + name: '512 to Everett Station (CommTrans:2861) from Northgate Station Bay 2 (CommTrans:2192)', + patternGeometry: { + length: 987, + points: 'p3-points' + }, + stops: [createStop('S3'), createStop('S4'), createStop('S5')] + } + } + const headsignData = extractMainHeadsigns(patterns, route, prefixHeadsign) + expect(headsignData.length).toBe(2) + }) + }) }) diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx index aaacb4a42..8a3ac937b 100644 --- a/lib/components/viewers/route-details.tsx +++ b/lib/components/viewers/route-details.tsx @@ -6,8 +6,9 @@ import React, { Component } from 'react' import styled from 'styled-components' import * as uiActions from '../../actions/ui' +import { DEFAULT_ROUTE_COLOR } from '../util/colors' import { - extractHeadsignFromPattern, + extractMainHeadsigns, getRouteColorBasedOnSettings } from '../../util/viewer' import { getOperatorName } from '../../util/state' @@ -30,7 +31,6 @@ import { StopLink, Stop as StyledStop } from './styled' -import { DEFAULT_ROUTE_COLOR } from '../util/colors' const PatternSelectButton = styled(UnstyledButton)` span { @@ -77,6 +77,13 @@ class RouteDetails extends Component<Props> { setViewedStop(stop) } + _prefixHeadsign = (pattern: Pattern) => { + return this.props.intl.formatMessage( + { id: 'components.RouteDetails.headsignTo' }, + { ...pattern } + ) + } + render() { const { intl, operator, patternId, route, setHoveredStop } = this.props const { agency, patterns = {}, shortName, url } = route @@ -86,74 +93,25 @@ class RouteDetails extends Component<Props> { const routeColor = getRouteColorBasedOnSettings(operator, route) - const headsigns = Object.entries(patterns) - .map( - ([id, pat]): PatternSummary => ({ - geometryLength: pat.patternGeometry?.length || 0, - headsign: extractHeadsignFromPattern(pat, shortName), - id, - lastStop: pat.stops?.[pat.stops?.length - 1]?.name - }) - ) - // Address duplicate headsigns. - .reduce((prev: PatternSummary[], cur) => { - const amended = prev - const alreadyExistingIndex = prev.findIndex( - (h) => h.headsign === cur.headsign - ) - // If the headsign is a duplicate, and the last stop of the pattern is not the headsign, - // amend the headsign with the last stop name in parenthesis. - // e.g. "Headsign (Last Stop)" - if ( - alreadyExistingIndex >= 0 && - cur.lastStop && - cur.headsign !== cur.lastStop - ) { - cur.headsign = intl.formatMessage( - { id: 'components.RouteDetails.headsignTo' }, - { ...cur } - ) - - // If there are only two total patterns, then we should rename - // both of them - if (amended.length === 1 && Object.entries(patterns).length === 2) { - amended[0].headsign = intl.formatMessage( - { id: 'components.RouteDetails.headsignTo' }, - { ...amended[0] } - ) - amended.push(cur) - return amended - } - } - - // With all remaining duplicate headsigns, only keep the pattern with the - // longest geometry. - if (alreadyExistingIndex >= 0) { - if ( - amended[alreadyExistingIndex].geometryLength < cur.geometryLength - ) { - amended[alreadyExistingIndex] = cur - } - } else { - amended.push(cur) - } - return amended - }, []) - .sort((a, b) => { - // sort by number of vehicles on that pattern - const aVehicleCount = - route.vehicles?.filter((vehicle) => vehicle.patternId === a.id) - .length || 0 - const bVehicleCount = - route.vehicles?.filter((vehicle) => vehicle.patternId === b.id) - .length || 0 - - // if both have the same count, sort by pattern geometry length - if (aVehicleCount === bVehicleCount) { - return b.geometryLength - a.geometryLength - } - return bVehicleCount - aVehicleCount - }) + const headsigns = extractMainHeadsigns( + patterns, + shortName, + this._prefixHeadsign + ).sort((a, b) => { + // sort by number of vehicles on that pattern + const aVehicleCount = + route.vehicles?.filter((vehicle) => vehicle.patternId === a.id) + .length || 0 + const bVehicleCount = + route.vehicles?.filter((vehicle) => vehicle.patternId === b.id) + .length || 0 + + // if both have the same count, sort by pattern geometry length + if (aVehicleCount === bVehicleCount) { + return b.geometryLength - a.geometryLength + } + return bVehicleCount - aVehicleCount + }) const patternSelectLabel = intl.formatMessage({ id: 'components.RouteDetails.selectADirection' diff --git a/lib/util/viewer.js b/lib/util/viewer.js index d5abd67c4..b4ba34258 100644 --- a/lib/util/viewer.js +++ b/lib/util/viewer.js @@ -3,8 +3,9 @@ import { getMostReadableTextColor } from '@opentripplanner/core-utils/lib/route' import tinycolor from 'tinycolor2' -import { checkForRouteModeOverride } from './config' import { DARK_TEXT_GREY } from '../components/util/colors' + +import { checkForRouteModeOverride } from './config' import { getOperatorAndRoute } from './state' import { isBlank } from './ui' @@ -96,6 +97,57 @@ export function extractHeadsignFromPattern(pattern, routeShortName = null) { return headsign } +export function extractMainHeadsigns(patterns, shortName, prefixHeadsign) { + const mapped = Object.entries(patterns).map( + ([id, pat]) /* : PatternSummary */ => ({ + geometryLength: pat.patternGeometry?.length || 0, + headsign: extractHeadsignFromPattern(pat, shortName), + id, + lastStop: pat.stops?.[pat.stops?.length - 1]?.name + }) + ) + + // Address duplicate headsigns. + return mapped.reduce((prev /* : PatternSummary[] */, cur) => { + const amended = prev + const alreadyExistingIndex = prev.findIndex( + (h) => h.headsign === cur.headsign + ) + // If the headsign is a duplicate, and the last stop of the pattern is not the headsign, + // amend the headsign with the last stop name in parenthesis. + // e.g. "Headsign (Last Stop)" + if ( + alreadyExistingIndex >= 0 && + cur.lastStop && + cur.headsign !== cur.lastStop + ) { + prefixHeadsign(cur) + + // If there are only two total patterns, then we should rename + // both of them + if (amended.length === 1 && Object.entries(patterns).length === 2) { + prefixHeadsign(amended[0]) + amended.push(cur) + return amended + } + } + + // With all remaining duplicate headsigns with the same last stops, only keep the pattern with the + // longest geometry. + if ( + alreadyExistingIndex >= 0 && + amended[alreadyExistingIndex].lastStop === cur.lastStop + ) { + if (amended[alreadyExistingIndex].geometryLength < cur.geometryLength) { + amended[alreadyExistingIndex] = cur + } + } else { + amended.push(cur) + } + return amended + }, []) +} + /** * Gets the mode string from either an OTP Route or RouteShort model. The OTP * Route model returns the mode as an integer type whereas the RouteShort model From 72ce2faeb5936c3d249a103dc47a6ffda9ca14b9 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:28:05 -0400 Subject: [PATCH 2/6] test(util/viewer): Refactor test for extractMainPatterns --- __tests__/util/viewer.js | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/__tests__/util/viewer.js b/__tests__/util/viewer.js index fbed8ef32..27faa8045 100644 --- a/__tests__/util/viewer.js +++ b/__tests__/util/viewer.js @@ -4,11 +4,11 @@ import { extractMainHeadsigns } from '../../lib/util/viewer' -function createStop(id) { - return { +function createStops(ids) { + return ids.map((id) => ({ id, name: id - } + })) } function prefixHeadsign(pattern) { @@ -64,13 +64,7 @@ describe('util > viewer', () => { length: 1404, points: 'p1-points' }, - stops: [ - createStop('S1'), - createStop('S2'), - createStop('S3'), - createStop('S4'), - createStop('S5') - ] + stops: createStops(['S1', 'S2', 'S3', 'S4', 'S5']) }, P2: { headsign, @@ -80,12 +74,7 @@ describe('util > viewer', () => { length: 1072, points: 'p2-points' }, - stops: [ - createStop('S3'), - createStop('S4'), - createStop('S6'), - createStop('S7') - ] + stops: createStops(['S3', 'S4', 'S6', 'S7']) }, P3: { headsign, @@ -95,7 +84,7 @@ describe('util > viewer', () => { length: 987, points: 'p3-points' }, - stops: [createStop('S3'), createStop('S4'), createStop('S5')] + stops: createStops(['S3', 'S4', 'S5']) } } const headsignData = extractMainHeadsigns(patterns, route, prefixHeadsign) From 218ba1cf01452666ba02ee7c8c3f6d1b3bd66c7b Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:41:00 -0400 Subject: [PATCH 3/6] refactor(util/viewer): Rename editHeadsign method --- __tests__/util/viewer.js | 8 +++++--- lib/components/viewers/route-details.tsx | 6 +++--- lib/util/viewer.js | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/__tests__/util/viewer.js b/__tests__/util/viewer.js index 27faa8045..6fe0a6d28 100644 --- a/__tests__/util/viewer.js +++ b/__tests__/util/viewer.js @@ -11,8 +11,8 @@ function createStops(ids) { })) } -function prefixHeadsign(pattern) { - pattern.headsign = `To ${pattern.headsign}` +function editHeadsign(pattern) { + pattern.headsign = `${pattern.headsign} (${pattern.lastStop})` } describe('util > viewer', () => { @@ -87,8 +87,10 @@ describe('util > viewer', () => { stops: createStops(['S3', 'S4', 'S5']) } } - const headsignData = extractMainHeadsigns(patterns, route, prefixHeadsign) + const headsignData = extractMainHeadsigns(patterns, route, editHeadsign) expect(headsignData.length).toBe(2) + expect(headsignData[0].headsign).toBe(headsign) + expect(headsignData[1].headsign).toBe('Everett via Lynnwood (S7)') }) }) }) diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx index 8a3ac937b..b172c1f48 100644 --- a/lib/components/viewers/route-details.tsx +++ b/lib/components/viewers/route-details.tsx @@ -1,7 +1,7 @@ import { connect } from 'react-redux' import { FormattedMessage, injectIntl, IntlShape } from 'react-intl' import { getMostReadableTextColor } from '@opentripplanner/core-utils/lib/route' -import { Stop, TransitOperator } from '@opentripplanner/types' +import { Pattern, Stop, TransitOperator } from '@opentripplanner/types' import React, { Component } from 'react' import styled from 'styled-components' @@ -77,7 +77,7 @@ class RouteDetails extends Component<Props> { setViewedStop(stop) } - _prefixHeadsign = (pattern: Pattern) => { + _editHeadsign = (pattern: Pattern) => { return this.props.intl.formatMessage( { id: 'components.RouteDetails.headsignTo' }, { ...pattern } @@ -96,7 +96,7 @@ class RouteDetails extends Component<Props> { const headsigns = extractMainHeadsigns( patterns, shortName, - this._prefixHeadsign + this._editHeadsign ).sort((a, b) => { // sort by number of vehicles on that pattern const aVehicleCount = diff --git a/lib/util/viewer.js b/lib/util/viewer.js index b4ba34258..a943ef37a 100644 --- a/lib/util/viewer.js +++ b/lib/util/viewer.js @@ -97,7 +97,7 @@ export function extractHeadsignFromPattern(pattern, routeShortName = null) { return headsign } -export function extractMainHeadsigns(patterns, shortName, prefixHeadsign) { +export function extractMainHeadsigns(patterns, shortName, editHeadsign) { const mapped = Object.entries(patterns).map( ([id, pat]) /* : PatternSummary */ => ({ geometryLength: pat.patternGeometry?.length || 0, @@ -121,12 +121,12 @@ export function extractMainHeadsigns(patterns, shortName, prefixHeadsign) { cur.lastStop && cur.headsign !== cur.lastStop ) { - prefixHeadsign(cur) + editHeadsign(cur) // If there are only two total patterns, then we should rename // both of them if (amended.length === 1 && Object.entries(patterns).length === 2) { - prefixHeadsign(amended[0]) + editHeadsign(amended[0]) amended.push(cur) return amended } From eb6cfb216a199632e3b98a18e96173e0e8182263 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:49:40 -0400 Subject: [PATCH 4/6] fix(RouteDetails): Actually edit the headsign --- lib/components/viewers/route-details.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx index b172c1f48..88304731e 100644 --- a/lib/components/viewers/route-details.tsx +++ b/lib/components/viewers/route-details.tsx @@ -78,7 +78,7 @@ class RouteDetails extends Component<Props> { } _editHeadsign = (pattern: Pattern) => { - return this.props.intl.formatMessage( + pattern.headsign = this.props.intl.formatMessage( { id: 'components.RouteDetails.headsignTo' }, { ...pattern } ) From b93cf10ff42bfb3ae48ac31e2df9009139686caf Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Mon, 10 Jun 2024 11:29:00 -0400 Subject: [PATCH 5/6] refactor(util/pattern-viewer): Move pattern extraction to new file, rename imports --- __tests__/util/pattern-viewer.ts | 68 +++++++++++++++++++++++ __tests__/util/viewer.js | 69 +----------------------- lib/components/viewers/route-details.tsx | 19 ++----- lib/util/pattern-viewer.ts | 65 ++++++++++++++++++++++ lib/util/viewer.js | 51 ------------------ 5 files changed, 139 insertions(+), 133 deletions(-) create mode 100644 __tests__/util/pattern-viewer.ts create mode 100644 lib/util/pattern-viewer.ts diff --git a/__tests__/util/pattern-viewer.ts b/__tests__/util/pattern-viewer.ts new file mode 100644 index 000000000..c7a76ee16 --- /dev/null +++ b/__tests__/util/pattern-viewer.ts @@ -0,0 +1,68 @@ +import '../test-utils/mock-window-url' +import { extractMainHeadsigns } from '../../lib/util/pattern-viewer' + +function createStops(ids) { + return ids.map((id) => ({ + id, + name: id + })) +} + +function editHeadsign(pattern) { + pattern.headsign = `${pattern.headsign} (${pattern.lastStop})` +} + +describe('util > pattern-viewer', () => { + describe('extractMainHeadsigns', () => { + it('should retain the essential patterns', () => { + // Consider the following patterns P1, P2, P3 of the same route with the same headsigns: + // Stops 1 2 3 4 5 6 7 --> direction of travel + // P1: o--o--o--o--o + // P2: o--o-----o--o + // P3: o--o--o + // + // P3 should be removed because it is a subset of P1. + // P1 and P2 should be kept. + // Patterns are assumed in descending length order because + // pre-sorting happened before extractMainHeadsigns is invoked (key order matters). + const headsign = 'Everett via Lynnwood' + const route = '512' + const patterns = { + P1: { + headsign, + id: 'P1', + name: '512 to Everett Station (CommTrans:2861) from SODO Busway & S Royal Brougham Way (kcm:99267)', + patternGeometry: { + length: 1404, + points: 'p1-points' + }, + stops: createStops(['S1', 'S2', 'S3', 'S4', 'S5']) + }, + P2: { + headsign, + id: 'P2', + name: '512 to Hewitt Ave & Virginia Ave (CommTrans:427)', + patternGeometry: { + length: 1072, + points: 'p2-points' + }, + stops: createStops(['S3', 'S4', 'S6', 'S7']) + }, + P3: { + headsign, + id: 'P3', + name: '512 to Everett Station (CommTrans:2861) from Northgate Station Bay 2 (CommTrans:2192)', + patternGeometry: { + length: 987, + points: 'p3-points' + }, + stops: createStops(['S3', 'S4', 'S5']) + } + } + const headsignData = extractMainHeadsigns(patterns, route, editHeadsign) + expect(headsignData.length).toBe(2) + expect(headsignData[0].headsign).toBe(headsign) + expect(headsignData[1].headsign).toBe('Everett via Lynnwood (S7)') + }) + }) +}) diff --git a/__tests__/util/viewer.js b/__tests__/util/viewer.js index 6fe0a6d28..500e5d4d8 100644 --- a/__tests__/util/viewer.js +++ b/__tests__/util/viewer.js @@ -1,19 +1,5 @@ import '../test-utils/mock-window-url' -import { - extractHeadsignFromPattern, - extractMainHeadsigns -} from '../../lib/util/viewer' - -function createStops(ids) { - return ids.map((id) => ({ - id, - name: id - })) -} - -function editHeadsign(pattern) { - pattern.headsign = `${pattern.headsign} (${pattern.lastStop})` -} +import { extractHeadsignFromPattern } from '../../lib/util/viewer' describe('util > viewer', () => { describe('extractHeadsignFromPattern', () => { @@ -40,57 +26,4 @@ describe('util > viewer', () => { ) }) }) - - describe('extractMainHeadsigns', () => { - it('should retain the essential patterns', () => { - // Consider the following patterns P1, P2, P3 of the same route with the same headsigns: - // Stops 1 2 3 4 5 6 7 --> direction of travel - // P1: o--o--o--o--o - // P2: o--o-----o--o - // P3: o--o--o - // - // P3 should be removed because it is a subset of P1. - // P1 and P2 should be kept. - // Patterns are assumed in descending length order because - // pre-sorting happened before extractMainHeadsigns is invoked (key order matters). - const headsign = 'Everett via Lynnwood' - const route = '512' - const patterns = { - P1: { - headsign, - id: 'P1', - name: '512 to Everett Station (CommTrans:2861) from SODO Busway & S Royal Brougham Way (kcm:99267)', - patternGeometry: { - length: 1404, - points: 'p1-points' - }, - stops: createStops(['S1', 'S2', 'S3', 'S4', 'S5']) - }, - P2: { - headsign, - id: 'P2', - name: '512 to Hewitt Ave & Virginia Ave (CommTrans:427)', - patternGeometry: { - length: 1072, - points: 'p2-points' - }, - stops: createStops(['S3', 'S4', 'S6', 'S7']) - }, - P3: { - headsign, - id: 'P3', - name: '512 to Everett Station (CommTrans:2861) from Northgate Station Bay 2 (CommTrans:2192)', - patternGeometry: { - length: 987, - points: 'p3-points' - }, - stops: createStops(['S3', 'S4', 'S5']) - } - } - const headsignData = extractMainHeadsigns(patterns, route, editHeadsign) - expect(headsignData.length).toBe(2) - expect(headsignData[0].headsign).toBe(headsign) - expect(headsignData[1].headsign).toBe('Everett via Lynnwood (S7)') - }) - }) }) diff --git a/lib/components/viewers/route-details.tsx b/lib/components/viewers/route-details.tsx index 88304731e..594ea31a4 100644 --- a/lib/components/viewers/route-details.tsx +++ b/lib/components/viewers/route-details.tsx @@ -1,17 +1,15 @@ import { connect } from 'react-redux' import { FormattedMessage, injectIntl, IntlShape } from 'react-intl' import { getMostReadableTextColor } from '@opentripplanner/core-utils/lib/route' -import { Pattern, Stop, TransitOperator } from '@opentripplanner/types' +import { Stop, TransitOperator } from '@opentripplanner/types' import React, { Component } from 'react' import styled from 'styled-components' import * as uiActions from '../../actions/ui' import { DEFAULT_ROUTE_COLOR } from '../util/colors' -import { - extractMainHeadsigns, - getRouteColorBasedOnSettings -} from '../../util/viewer' +import { extractMainHeadsigns, PatternSummary } from '../../util/pattern-viewer' import { getOperatorName } from '../../util/state' +import { getRouteColorBasedOnSettings } from '../../util/viewer' import { LinkOpensNewWindow } from '../util/externalLink' import { SetViewedRouteHandler, @@ -40,13 +38,6 @@ const PatternSelectButton = styled(UnstyledButton)` } ` -interface PatternSummary { - geometryLength: number - headsign: string - id: string - lastStop?: string -} - interface Props { intl: IntlShape operator: TransitOperator @@ -77,11 +68,11 @@ class RouteDetails extends Component<Props> { setViewedStop(stop) } - _editHeadsign = (pattern: Pattern) => { + _editHeadsign = (pattern: PatternSummary) => { pattern.headsign = this.props.intl.formatMessage( { id: 'components.RouteDetails.headsignTo' }, { ...pattern } - ) + ) as string } render() { diff --git a/lib/util/pattern-viewer.ts b/lib/util/pattern-viewer.ts new file mode 100644 index 000000000..1b974df36 --- /dev/null +++ b/lib/util/pattern-viewer.ts @@ -0,0 +1,65 @@ +import { Pattern } from '../components/util/types' + +import { extractHeadsignFromPattern } from './viewer' + +export interface PatternSummary { + geometryLength: number + headsign: string + id: string + lastStop?: string +} + +export function extractMainHeadsigns( + patterns: Record<string, Pattern>, + shortName: string, + editHeadsign: (pattern: PatternSummary) => void +): PatternSummary[] { + const mapped = Object.entries(patterns).map( + ([id, pat]): PatternSummary => ({ + geometryLength: pat.patternGeometry?.length || 0, + headsign: extractHeadsignFromPattern(pat, shortName), + id, + lastStop: pat.stops?.[pat.stops?.length - 1]?.name + }) + ) + + // Address duplicate headsigns. + return mapped.reduce((prev: PatternSummary[], cur) => { + const amended = prev + const alreadyExistingIndex = prev.findIndex( + (h) => h.headsign === cur.headsign + ) + // If the headsign is a duplicate, and the last stop of the pattern is not the headsign, + // amend the headsign with the last stop name in parenthesis. + // e.g. "Headsign (Last Stop)" + if ( + alreadyExistingIndex >= 0 && + cur.lastStop && + cur.headsign !== cur.lastStop + ) { + editHeadsign(cur) + + // If there are only two total patterns, then we should rename + // both of them + if (amended.length === 1 && Object.entries(patterns).length === 2) { + editHeadsign(amended[0]) + amended.push(cur) + return amended + } + } + + // With all remaining duplicate headsigns with the same last stops, only keep the pattern with the + // longest geometry. + if ( + alreadyExistingIndex >= 0 && + amended[alreadyExistingIndex].lastStop === cur.lastStop + ) { + if (amended[alreadyExistingIndex].geometryLength < cur.geometryLength) { + amended[alreadyExistingIndex] = cur + } + } else { + amended.push(cur) + } + return amended + }, []) +} diff --git a/lib/util/viewer.js b/lib/util/viewer.js index a943ef37a..9aabdacc2 100644 --- a/lib/util/viewer.js +++ b/lib/util/viewer.js @@ -97,57 +97,6 @@ export function extractHeadsignFromPattern(pattern, routeShortName = null) { return headsign } -export function extractMainHeadsigns(patterns, shortName, editHeadsign) { - const mapped = Object.entries(patterns).map( - ([id, pat]) /* : PatternSummary */ => ({ - geometryLength: pat.patternGeometry?.length || 0, - headsign: extractHeadsignFromPattern(pat, shortName), - id, - lastStop: pat.stops?.[pat.stops?.length - 1]?.name - }) - ) - - // Address duplicate headsigns. - return mapped.reduce((prev /* : PatternSummary[] */, cur) => { - const amended = prev - const alreadyExistingIndex = prev.findIndex( - (h) => h.headsign === cur.headsign - ) - // If the headsign is a duplicate, and the last stop of the pattern is not the headsign, - // amend the headsign with the last stop name in parenthesis. - // e.g. "Headsign (Last Stop)" - if ( - alreadyExistingIndex >= 0 && - cur.lastStop && - cur.headsign !== cur.lastStop - ) { - editHeadsign(cur) - - // If there are only two total patterns, then we should rename - // both of them - if (amended.length === 1 && Object.entries(patterns).length === 2) { - editHeadsign(amended[0]) - amended.push(cur) - return amended - } - } - - // With all remaining duplicate headsigns with the same last stops, only keep the pattern with the - // longest geometry. - if ( - alreadyExistingIndex >= 0 && - amended[alreadyExistingIndex].lastStop === cur.lastStop - ) { - if (amended[alreadyExistingIndex].geometryLength < cur.geometryLength) { - amended[alreadyExistingIndex] = cur - } - } else { - amended.push(cur) - } - return amended - }, []) -} - /** * Gets the mode string from either an OTP Route or RouteShort model. The OTP * Route model returns the mode as an integer type whereas the RouteShort model From 2b6028609085ddb8bbb15211105ce6c9e0a9ddf6 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:13:15 -0400 Subject: [PATCH 6/6] test(util/pattern-viewer): Remove specific pattern names. --- __tests__/util/pattern-viewer.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/__tests__/util/pattern-viewer.ts b/__tests__/util/pattern-viewer.ts index c7a76ee16..79b3957f7 100644 --- a/__tests__/util/pattern-viewer.ts +++ b/__tests__/util/pattern-viewer.ts @@ -16,7 +16,7 @@ describe('util > pattern-viewer', () => { describe('extractMainHeadsigns', () => { it('should retain the essential patterns', () => { // Consider the following patterns P1, P2, P3 of the same route with the same headsigns: - // Stops 1 2 3 4 5 6 7 --> direction of travel + // Stops S1 S2 S3 S4 S5 S6 S7 --> direction of travel // P1: o--o--o--o--o // P2: o--o-----o--o // P3: o--o--o @@ -31,7 +31,7 @@ describe('util > pattern-viewer', () => { P1: { headsign, id: 'P1', - name: '512 to Everett Station (CommTrans:2861) from SODO Busway & S Royal Brougham Way (kcm:99267)', + name: 'P1 Pattern name', patternGeometry: { length: 1404, points: 'p1-points' @@ -41,7 +41,7 @@ describe('util > pattern-viewer', () => { P2: { headsign, id: 'P2', - name: '512 to Hewitt Ave & Virginia Ave (CommTrans:427)', + name: 'P2 Pattern name', patternGeometry: { length: 1072, points: 'p2-points' @@ -51,7 +51,7 @@ describe('util > pattern-viewer', () => { P3: { headsign, id: 'P3', - name: '512 to Everett Station (CommTrans:2861) from Northgate Station Bay 2 (CommTrans:2192)', + name: 'P3 Pattern name', patternGeometry: { length: 987, points: 'p3-points' @@ -62,7 +62,7 @@ describe('util > pattern-viewer', () => { const headsignData = extractMainHeadsigns(patterns, route, editHeadsign) expect(headsignData.length).toBe(2) expect(headsignData[0].headsign).toBe(headsign) - expect(headsignData[1].headsign).toBe('Everett via Lynnwood (S7)') + expect(headsignData[1].headsign).toBe(`${headsign} (S7)`) }) }) })