From 6cfd1cf6fc700ba925dcf372c89812ee59ee1d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sun, 3 Nov 2024 16:38:00 -0800 Subject: [PATCH] Include route number in label of named route relations (#10478) * iD#8707 Show ref in the name of route relations * Avoid combining PTv2-formatted name with ref * Pair name with other tags when labeling routes --------- Co-authored-by: Kyle Hensel --- data/core.yaml | 16 ++++++++++ modules/ui/sections/raw_membership_editor.js | 6 +++- modules/util/util.js | 26 +++++++++++++--- test/spec/util/util.js | 32 ++++++++++++++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index 5cdb0658e..71957c05f 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -778,6 +778,22 @@ en: network_ref_direction: "{network} {ref} {direction}" network_ref_from_to: "{network} {ref} from {from} to {to}" network_ref_from_to_via: "{network} {ref} from {from} to {to} via {via}" + name_direction: "{name} {direction}" + network_name: "{network} {name}" + name_from_to: "{name} from {from} to {to}" + name_from_to_via: "{name} from {from} to {to} via {via}" + network_name_direction: "{network} {name} {direction}" + network_name_from_to: "{network} {name} from {from} to {to}" + network_name_from_to_via: "{network} {name} from {from} to {to} via {via}" + name: "{name}" + ref_name: "{ref}: {name}" + ref_name_direction: "{ref}: {name} {direction}" + ref_name_from_to: "{ref}: {name} from {from} to {to}" + ref_name_from_to_via: "{ref}: {name} from {from} to {to} via {via}" + network_ref_name: "{network} {ref}: {name}" + network_ref_name_direction: "{network} {ref}: {name} {direction}" + network_ref_name_from_to: "{network} {ref}: {name} from {from} to {to}" + network_ref_name_from_to_via: "{network} {ref}: {name} from {from} to {to} via {via}" speed_unit: "Speed unit" roadheight: # symbol for meters diff --git a/modules/ui/sections/raw_membership_editor.js b/modules/ui/sections/raw_membership_editor.js index a22790b7f..6ce6d8499 100644 --- a/modules/ui/sections/raw_membership_editor.js +++ b/modules/ui/sections/raw_membership_editor.js @@ -386,7 +386,11 @@ export function uiSectionRawMembershipEditor(context) { .attr('class', 'member-entity-name') .classed('has-colour', d => d.relation.tags.colour && isColourValid(d.relation.tags.colour)) .style('border-color', d => d.relation.tags.colour) - .text(function(d) { return utilDisplayName(d.relation); }); + .html(function(d) { + const matched = presetManager.match(d.relation, context.graph()); + // hide the network from the name if there is NSI match + return utilDisplayName(d.relation, matched.suggestion); + }); labelEnter .append('button') diff --git a/modules/util/util.js b/modules/util/util.js index 1dfd007e0..00acc9803 100644 --- a/modules/util/util.js +++ b/modules/util/util.js @@ -177,20 +177,35 @@ export function utilGetAllNodes(ids, graph) { } } - -export function utilDisplayName(entity) { +/** + * @param {boolean} hideNetwork If true, the `network` tag will not be used in the name to prevent + * it being shown twice (see PR #8707#discussion_r712658175) + */ +export function utilDisplayName(entity, hideNetwork) { var localizedNameKey = 'name:' + localizer.languageCode().toLowerCase(); var name = entity.tags[localizedNameKey] || entity.tags.name || ''; - if (name) return name; var tags = { direction: entity.tags.direction, from: entity.tags.from, - network: entity.tags.cycle_network || entity.tags.network, + name, + network: hideNetwork ? undefined : (entity.tags.cycle_network || entity.tags.network), ref: entity.tags.ref, to: entity.tags.to, via: entity.tags.via }; + + // A right or left-right arrow likely indicates a formulaic “name” as specified by the Public Transport v2 schema. + // This name format already contains enough details to disambiguate the feature; avoid duplicating these details. + if (entity.tags.route && entity.tags.name && entity.tags.name.match(/[→⇒↔⇔]|[-=]>/)) { + return entity.tags.name; + } + + // Non-routes tend to be labeled in many places besides the relation lists, such as the map, where brevity is important. + if (!entity.tags.route && name) { + return name; + } + var keyComponents = []; if (tags.network) { @@ -199,6 +214,9 @@ export function utilDisplayName(entity) { if (tags.ref) { keyComponents.push('ref'); } + if (tags.name) { + keyComponents.push('name'); + } // Routes may need more disambiguation based on direction or destination if (entity.tags.route) { diff --git a/test/spec/util/util.js b/test/spec/util/util.js index 604128db5..c6e702b17 100644 --- a/test/spec/util/util.js +++ b/test/spec/util/util.js @@ -262,6 +262,19 @@ describe('iD.util', function() { it('returns the name if tagged with a name', function() { expect(iD.utilDisplayName({tags: {name: 'East Coast Greenway'}})).to.eql('East Coast Greenway'); }); + it('returns just the name for non-routes', function() { + expect(iD.utilDisplayName({tags: { name: 'Abyssinian Room', ref: '260-115' }})).to.eql('Abyssinian Room'); + }); + it('returns just the name for route with PTv2-formatted names', function() { + expect(iD.utilDisplayName({tags: { name: 'NORTA 2: French Market → Canal at Bourbon', network: 'NORTA', ref: '2', from: 'French Market', to: 'Canal at Bourbon'}})).to.eql('NORTA 2: French Market → Canal at Bourbon'); + expect(iD.utilDisplayName({tags: { name: 'VTA 64A: McKee & White => San Jose Diridon => Ohlone/Chynoweth', network: 'VTA', ref: '64A', from: 'McKee & White', to: 'Ohlone/Chynoweth', via: 'San Jose Diridon'}})).to.eql('VTA 64A: McKee & White => San Jose Diridon => Ohlone/Chynoweth'); + expect(iD.utilDisplayName({tags: { name: 'Bus 224: Downtown Garland Station -> Lake Ray Hubbard TC -> Downtown Dallas', route: 'bus', ref: '224', from: 'Downtown Garland Station', to: 'Downtown Dallas', via: 'Lake Ray Hubbard TC'}})).to.eql('Bus 224: Downtown Garland Station -> Lake Ray Hubbard TC -> Downtown Dallas'); + }); + it('suppresses the network tag if the hideNetwork argument is true', function() { + expect(iD.utilDisplayName({tags: { name: 'Lynfield Express', ref: '25L', network: 'AT', route: 'bus' }}, true)).to.eql('25L: Lynfield Express'); + expect(iD.utilDisplayName({tags: { network: 'SORTA', ref: '3X' }}, true)).to.eql('3X'); + expect(iD.utilDisplayName({tags: { name: 'Dallas North Tollway', network: 'US:TX:NTTA', route: 'road' }}, true)).to.eql('Dallas North Tollway'); + }); it('distinguishes unnamed features by ref', function() { expect(iD.utilDisplayName({tags: {ref: '66'}})).to.eql('66'); }); @@ -283,6 +296,25 @@ describe('iD.util', function() { // BART Yellow Line: Antioch => Pittsburg/Bay Point => SFO Airport => Millbrae expect(iD.utilDisplayName({tags: {network: 'BART', ref: 'Yellow', from: 'Antioch', to: 'Millbrae', via: 'Pittsburg/Bay Point;San Francisco International Airport', route: 'subway'}})).to.eql('BART Yellow from Antioch to Millbrae via Pittsburg/Bay Point;San Francisco International Airport'); }); + it('distinguishes named features by name', function() { + expect(iD.utilDisplayName({tags: { name: 'Ohio Turnpike', route: 'road' }})).to.eql('Ohio Turnpike'); + expect(iD.utilDisplayName({tags: { name: 'Lynfield Express', ref: '25L', route: 'bus' }})).to.eql('25L: Lynfield Express'); + expect(iD.utilDisplayName({tags: { name: 'Kāpiti Expressway', ref: 'SH1', route: 'road' }})).to.eql('SH1: Kāpiti Expressway'); + expect(iD.utilDisplayName({tags: { name: 'Lynfield Express', ref: '25L', network: 'AT', route: 'bus' }})).to.eql('AT 25L: Lynfield Express'); + }); + it('distinguishes named features by network or cycle_network', function() { + expect(iD.utilDisplayName({tags: { name: 'Dallas North Tollway', network: 'US:TX:NTTA', route: 'road' }})).to.eql('US:TX:NTTA Dallas North Tollway'); + }); + it('distinguishes named features by ref', function() { + expect(iD.utilDisplayName({tags: { name: 'Dallas North Tollway', network: 'US:TX:NTTA', ref: 'DNT', route: 'road' }})).to.eql('US:TX:NTTA DNT: Dallas North Tollway'); + }); + it('distinguishes named features by direction', function() { + expect(iD.utilDisplayName({tags: { name: 'Dallas North Tollway', network: 'US:TX:NTTA', direction: 'south', route: 'road' }})).to.eql('US:TX:NTTA Dallas North Tollway south'); + }); + it('distinguishes named features by waypoints', function() { + expect(iD.utilDisplayName({tags: { name: 'Kings Island Express', network: 'SORTA', ref: '71X', from: 'Sycamore & Court', to: 'Fields Ertel & Royal Point', route: 'bus' }})).to.eql('SORTA 71X: Kings Island Express from Sycamore & Court to Fields Ertel & Royal Point'); + expect(iD.utilDisplayName({tags: { name: 'Local', network: 'Caltrain', from: 'San Francisco', to: 'Tamien', via: 'College Park', route: 'train' }})).to.eql('Caltrain Local from San Francisco to Tamien via College Park'); + }); }); describe('utilOldestID', function() {