diff --git a/data/colors.json b/data/colors.json new file mode 100644 index 0000000000..6b675aed3a --- /dev/null +++ b/data/colors.json @@ -0,0 +1,78 @@ +{ + "default": { + "red": { + "fill": { "color": "0xe06e5f", "alpha": 0.3 } + }, + "green": { + "fill": { "color": "0x8cd05f", "alpha": 0.3 } + }, + "blue": { + "fill": { "color": "0x77d4de", "alpha": 0.3 } + }, + "yellow": { + "fill": { "color": "0xffff94", "alpha": 0.25 } + }, + "gold": { + "fill": { "color": "0xc4be19", "alpha": 0.3 } + }, + "orange": { + "fill": { "color": "0xd6881a", "alpha": 0.3 } + }, + "pink": { + "fill": { "color": "0xe3a4f5", "alpha": 0.3 } + }, + "teal": { + "fill": { "color": "0x99e1aa", "alpha": 0.3 } + }, + "lightgreen": { + "fill": { "color": "0xbee83f", "alpha": 0.3 } + }, + "tan": { + "fill": { "color": "0xf5dcba", "alpha": 0.3 } + }, + "darkgray": { + "fill": { "color": "0x8c8c8c", "alpha": 0.5 } + }, + "lightgray": { + "fill": { "color": "0xaaaaaa", "alpha": 0.3 } + } + }, + "example": { + "red": { + "fill": { "color": "0xFF0E41", "alpha": 0.3 } + }, + "green": { + "fill": { "color": "0x09F04A", "alpha": 0.3 } + }, + "blue": { + "fill": { "color": "0x0CBCFF", "alpha": 0.3 } + }, + "yellow": { + "fill": { "color": "0xFFCA09", "alpha": 0.25 } + }, + "gold": { + "fill": { "color": "0xFF0EBC", "alpha": 0.3 } + }, + "orange": { + "fill": { "color": "0xFF510B", "alpha": 0.3 } + }, + "pink": { + "fill": { "color": "0xF1C0E8", "alpha": 0.3 } + }, + "teal": { + "fill": { "color": "0x12FFD1", "alpha": 0.3 } + }, + "lightgreen": { + "fill": { "color": "0x540FFF", "alpha": 0.3 } + }, + "tan": { + "fill": { "color": "0xAFFA1F", "alpha": 0.3 } + }, + "darkgray": { + "fill": { "color": "0x0000FE", "alpha": 0.5 } + }, + "lightgray": { + "fill": { "color": "0xE9AF1E", "alpha": 0.3 } + } + } +} diff --git a/data/core.yaml b/data/core.yaml index e0c5b98073..b2f6213ef5 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -270,7 +270,7 @@ en: to_line: Moved a point to a line. to_area: Moved a point to an area. relation: These features can't be connected because they have conflicting relation roles. - restriction: "These features can't be connected because it would damage a \"{relation}\" relation." + restriction: 'These features can''t be connected because it would damage a "{relation}" relation.' disconnect: title: Disconnect description: @@ -313,7 +313,7 @@ en: other: "Merged {n} features." not_eligible: These features can't be merged. not_adjacent: These features can't be merged because their endpoints aren't connected. - damage_relation: "These features can't be merged because it would damage a \"{relation}\" relation." + damage_relation: 'These features can''t be merged because it would damage a "{relation}" relation.' relation: These features can't be merged because they have conflicting relation roles. incomplete_relation: These features can't be merged because at least one hasn't been fully downloaded. conflicting_tags: These features can't be merged because some of their tags have conflicting values. @@ -547,7 +547,7 @@ en: via_names: "{via} {viaNames}" select_from: "Click to select a {from} segment" select_from_name: "Click to select {from} {fromName}" - toggle: "Click for \"{turn}\"" + toggle: 'Click for "{turn}"' undo: title: Undo tooltip: "Undo: {action}" @@ -571,7 +571,7 @@ en: help_translate: Help translate example: "Example:" sidebar: - key: '`' + key: "`" tooltip: Toggle the sidebar. feature_info: hidden_warning: @@ -788,11 +788,11 @@ en: 3dmap: description: Show 3D map tooltip: Show an inset 3D map. - key: '/' + key: "/" minimap: description: Show Minimap tooltip: Show a zoomed out map to help locate the area currently displayed. - key: '/' + key: "/" panel: description: Show Background Panel tooltip: Show advanced background information. @@ -802,9 +802,9 @@ en: fix_misalignment: Imagery Offset offset: "Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters." next_background: - key: '.' + key: "." previous_background: - key: ',' + key: "," map_data: title: Map Data description: Map Data @@ -971,7 +971,7 @@ en: instructions: "Enter a URL to any of the above file types, an MVT-style vector tile service, or a .pmtiles archive." tokens: "Supported replacement tokens:" xyz: "`{zoom}` or `{z}`, `{x}`, `{y}` for Z/X/Y tile scheme" - example_file: "https://example.com/custom.gpx" + example_file: "https://example.com/custom.gpx" example_xyz: "https://example.com/{z}/{x}/{y}.mvt?access_token=123" example_pmtiles: "https://example.com/buildings.pmtiles" placeholder: Enter a url @@ -1012,6 +1012,15 @@ en: deuteranopia: Deuteranopia tritanopia: Tritanopia placeholder: Select colorblind mode + focus_modes: + title: Focus Modes + default: + title: Default (None) + tooltip: No focus mode enabled + pedestrian: + title: Pedestrian Mode + tooltip: Highlight Pedestrian Infrastructure + restore: heading: You have unsaved changes description: "Do you wish to restore unsaved changes from a previous editing session?" @@ -1029,9 +1038,9 @@ en: unsaved_changes: You have unsaved changes conflict: header: Resolve conflicting edits - count: 'Conflict {num} of {total}' - previous: '< Previous' - next: 'Next >' + count: "Conflict {num} of {total}" + previous: "< Previous" + next: "Next >" keep_local: Keep mine keep_remote: Use theirs restore: Restore @@ -1045,10 +1054,10 @@ en: no_changes: No changes to download. merge_remote_changes: conflict: - deleted: 'This feature has been deleted by {user}.' - location: 'This feature was moved by both you and {user}.' - nodelist: 'Nodes were changed by both you and {user}.' - memberlist: 'Relation members were changed by both you and {user}.' + deleted: "This feature has been deleted by {user}." + location: "This feature was moved by both you and {user}." + nodelist: "Nodes were changed by both you and {user}." + memberlist: "Relation members were changed by both you and {user}." tags: 'You changed the {tag} tag to "{local}" and {user} changed it to "{remote}".' success: just_edited: "You just edited OpenStreetMap!" @@ -1179,7 +1188,7 @@ en: bearing: title: Reset Bearing disabled: North is up - n: 'N' + n: "N" cannot_zoom: "Cannot zoom out further in current mode." full_screen: Toggle Full Screen self_intersection: @@ -1215,8 +1224,8 @@ en: description: 'Along this section of {highway}, {percentage}% of {num_trips} recorded trips travel from {from_node} to {to_node}. There may be missing a "oneway" tag.' mr: title: Missing Geometry - description: '{num_trips} recorded trips in this area suggest there may be unmapped {geometry_type} here.' - description_alt: 'Data from a 3rd party suggests there may be unmapped {geometry_type} here.' + description: "{num_trips} recorded trips in this area suggest there may be unmapped {geometry_type} here." + description_alt: "Data from a 3rd party suggests there may be unmapped {geometry_type} here." tr: title: Missing Turn Restriction description: '{num_passed} of {num_trips} recorded trips (travelling {travel_direction}) make a turn from {from_way} to {to_way} at {junction}. There may be a missing "{turn_restriction}" restriction.' @@ -1231,80 +1240,80 @@ en: close_comment: Close and Comment ignore_comment: Remove and Comment error_parts: - this_node: 'this node' - this_way: 'this way' - this_relation: 'this relation' - this_oneway: 'this oneway' - this_highway: 'this highway' - this_railway: 'this railway' - this_waterway: 'this waterway' - this_cycleway: 'this cycleway' - this_cycleway_footpath: 'this cycleway/footpath' - this_riverbank: 'this riverbank' - this_crossing: 'this crossing' - this_railway_crossing: 'this railway crossing' - this_bridge: 'this bridge' - this_tunnel: 'this tunnel' - this_boundary: 'this boundary' - this_turn_restriction: 'this turn restriction' - this_roundabout: 'this roundabout' - this_mini_roundabout: 'this mini-roundabout' - this_track: 'this track' - this_feature: 'this feature' - highway: 'highway' - railway: 'railway' - waterway: 'waterway' - cycleway: 'cycleway' - cycleway_footpath: 'cycleway/footpath' - riverbank: 'riverbank' - place_of_worship: 'place of worship' - pub: 'pub' - restaurant: 'restaurant' - school: 'school' - university: 'university' - hospital: 'hospital' - library: 'library' - theatre: 'theatre' - courthouse: 'courthouse' - bank: 'bank' - cinema: 'cinema' - pharmacy: 'pharmacy' - cafe: 'cafe' - fast_food: 'fast food' - fuel: 'fuel' - from: 'from' - to: 'to' - left_hand: 'left-hand' - right_hand: 'right-hand' + this_node: "this node" + this_way: "this way" + this_relation: "this relation" + this_oneway: "this oneway" + this_highway: "this highway" + this_railway: "this railway" + this_waterway: "this waterway" + this_cycleway: "this cycleway" + this_cycleway_footpath: "this cycleway/footpath" + this_riverbank: "this riverbank" + this_crossing: "this crossing" + this_railway_crossing: "this railway crossing" + this_bridge: "this bridge" + this_tunnel: "this tunnel" + this_boundary: "this boundary" + this_turn_restriction: "this turn restriction" + this_roundabout: "this roundabout" + this_mini_roundabout: "this mini-roundabout" + this_track: "this track" + this_feature: "this feature" + highway: "highway" + railway: "railway" + waterway: "waterway" + cycleway: "cycleway" + cycleway_footpath: "cycleway/footpath" + riverbank: "riverbank" + place_of_worship: "place of worship" + pub: "pub" + restaurant: "restaurant" + school: "school" + university: "university" + hospital: "hospital" + library: "library" + theatre: "theatre" + courthouse: "courthouse" + bank: "bank" + cinema: "cinema" + pharmacy: "pharmacy" + cafe: "cafe" + fast_food: "fast food" + fuel: "fuel" + from: "from" + to: "to" + left_hand: "left-hand" + right_hand: "right-hand" errorTypes: 20: - title: 'Multiple nodes on the same spot' - description: 'There is more than one node in this spot. Node IDs: {var1}.' + title: "Multiple nodes on the same spot" + description: "There is more than one node in this spot. Node IDs: {var1}." 30: - title: 'Non-closed area' + title: "Non-closed area" description: '{var1} is tagged with "{var2}" and should be a closed loop.' 40: - title: 'Impossible oneway' - description: 'The first node {var1} of {var2} is not connected to any other way.' + title: "Impossible oneway" + description: "The first node {var1} of {var2} is not connected to any other way." 41: - description: 'The last node {var1} of {var2} is not connected to any other way.' + description: "The last node {var1} of {var2} is not connected to any other way." 42: - description: 'You cannot reach {var1} because all ways leading from it are oneway.' + description: "You cannot reach {var1} because all ways leading from it are oneway." 43: - description: 'You cannot escape from {var1} because all ways leading to it are oneway.' + description: "You cannot escape from {var1} because all ways leading to it are oneway." 50: - title: 'Almost junction' - description: '{var1} is very close but not connected to way {var2}.' + title: "Almost junction" + description: "{var1} is very close but not connected to way {var2}." 60: - title: 'Deprecated tag' + title: "Deprecated tag" description: '{var1} uses deprecated tag "{var2}". Please use "{var3}" instead.' 70: - title: 'Missing tag' + title: "Missing tag" description: '{var1} has an empty tag: "{var2}".' 71: - description: '{var1} has no tags.' + description: "{var1} has no tags." 72: - description: '{var1} is not member of any way and doesn''t have any tags.' + description: "{var1} is not member of any way and doesn't have any tags." 73: description: '{var1} has a "{var2}" tag but no "highway" tag.' 74: @@ -1312,85 +1321,85 @@ en: 75: description: '{var1} has a name "{var2}" but no other tags.' 90: - title: 'Motorway without ref tag' + title: "Motorway without ref tag" description: '{var1} is tagged as a motorway and therefore needs a "ref", "nat_ref", or "int_ref" tag.' 100: - title: 'Place of worship without religion' - description: '{var1} is tagged as a place of worship and therefore needs a religion tag.' + title: "Place of worship without religion" + description: "{var1} is tagged as a place of worship and therefore needs a religion tag." 110: - title: 'Point of interest without name' + title: "Point of interest without name" description: '{var1} is tagged as a "{var2}" and therefore needs a name tag.' 120: - title: 'Way without nodes' - description: '{var1} has just one single node.' + title: "Way without nodes" + description: "{var1} has just one single node." 130: - title: 'Disconnected way' - description: '{var1} is not connected to the rest of the map.' + title: "Disconnected way" + description: "{var1} is not connected to the rest of the map." 150: - title: 'Railway crossing without tag' + title: "Railway crossing without tag" description: '{var1} of a highway and a railway needs to be tagged as "railway=crossing" or "railway=level_crossing".' 160: - title: 'Railway layer conflict' - description: 'There are ways in different layers (e.g. tunnel or bridge) meeting at {var1}.' + title: "Railway layer conflict" + description: "There are ways in different layers (e.g. tunnel or bridge) meeting at {var1}." 170: - title: 'FIXME tagged item' - description: '{var1} has a FIXME tag: {var2}' + title: "FIXME tagged item" + description: "{var1} has a FIXME tag: {var2}" 180: - title: 'Relation without type' + title: "Relation without type" description: '{var1} is missing a "type" tag.' 190: - title: 'Intersection without junction' - description: '{var1} intersects the {var2} {var3} but there is no junction node, bridge, or tunnel.' + title: "Intersection without junction" + description: "{var1} intersects the {var2} {var3} but there is no junction node, bridge, or tunnel." 200: - title: 'Overlapping ways' - description: '{var1} overlaps the {var2} {var3}.' + title: "Overlapping ways" + description: "{var1} overlaps the {var2} {var3}." 210: - title: 'Self-intersecting way' - description: 'There is an unspecified issue with self intersecting ways.' + title: "Self-intersecting way" + description: "There is an unspecified issue with self intersecting ways." 211: - description: '{var1} contains more than one node multiple times. Nodes are {var2}. This may or may not be an error.' + description: "{var1} contains more than one node multiple times. Nodes are {var2}. This may or may not be an error." 212: - description: '{var1} has only two different nodes and contains one of them more than once.' + description: "{var1} has only two different nodes and contains one of them more than once." 220: - title: 'Misspelled tag' + title: "Misspelled tag" description: '{var1} is tagged "{var2}" where "{var3}" looks like "{var4}".' 221: description: '{var1} has a suspicious tag "{var2}".' 230: - title: 'Layer conflict' - description: '{var1} is a junction of ways on different layers.' + title: "Layer conflict" + description: "{var1} is a junction of ways on different layers." 231: - description: '{var1} is a junction of ways on different layers: {var2}.' - layer: '(layer: {layer})' + description: "{var1} is a junction of ways on different layers: {var2}." + layer: "(layer: {layer})" 232: description: '{var1} is tagged with "layer={var2}". This need not be an error but it looks strange.' 270: - title: 'Unusual motorway connection' + title: "Unusual motorway connection" description: '{var1} is a junction of a motorway and a highway other than "motorway", "motorway_link", "trunk", "rest_area", or "construction". Connection to "service" or "unclassified" is only valid if it has "access=no/private", or it leads to a motorway service area, or if it is a "service=parking_aisle".' 280: - title: 'Boundary issue' - description: 'There is an unspecified issue with this boundary.' + title: "Boundary issue" + description: "There is an unspecified issue with this boundary." 281: - title: 'Boundary missing name' - description: '{var1} has no name.' + title: "Boundary missing name" + description: "{var1} has no name." 282: - title: 'Boundary missing admin level' + title: "Boundary missing admin level" description: 'The boundary of {var1} has no valid numeric admin_level. Please do not mix admin levels (e.g. "6;7"). Always tag the lowest admin_level of all boundaries.' 283: - title: 'Boundary not a closed loop' - description: 'The boundary of {var1} is not a closed loop.' + title: "Boundary not a closed loop" + description: "The boundary of {var1} is not a closed loop." 284: - title: 'Boundary is split' - description: 'The boundary of {var1} splits here.' + title: "Boundary is split" + description: "The boundary of {var1} splits here." 285: - title: 'Boundary admin_level too high' + title: "Boundary admin_level too high" description: '{var1} has "admin_level={var2}" but belongs to a relation with lower "admin_level" (e.g. higher priority); it should have the lowest "admin_level" of all relations.' 290: - title: 'Restriction issue' - description: 'There is an unspecified issue with this restriction.' + title: "Restriction issue" + description: "There is an unspecified issue with this restriction." 291: - title: 'Restriction missing type' - description: '{var1} has an unrecognized restriction type.' + title: "Restriction missing type" + description: "{var1} has an unrecognized restriction type." 292: title: 'Restriction missing "from" way' description: '{var1} has {var2} "from" members, but it should have 1.' @@ -1404,62 +1413,62 @@ en: title: 'Restriction "via" is not an endpoint' description: '{var1} has a "via" (node {var2}) which is not the first or the last member of "{var3}" (way {var4}).' 296: - title: 'Unusual restriction angle' + title: "Unusual restriction angle" description: '{var1} has a restriction type "{var2}" but the angle is {var3} degrees. Maybe the restriction type is not appropriate?' 297: title: 'Wrong direction of "to" way' description: '{var1} does not match the direction of "to" way {var2}.' 298: - title: 'Redundant restriction - oneway' + title: "Redundant restriction - oneway" description: '{var1} may be redundant. Entry already prohibited by "oneway" tag on {var2}.' 300: - title: 'Missing maxspeed' + title: "Missing maxspeed" description: '{var1} is missing a "maxspeed" tag and is tagged as motorway, trunk, primary, or secondary.' 310: - title: 'Roundabout issue' - description: 'There is an unspecified issue with this roundabout.' + title: "Roundabout issue" + description: "There is an unspecified issue with this roundabout." 311: - title: 'Roundabout not closed loop' - description: '{var1} is part of a roundabout but is not closed-loop. (Split carriageways approaching a roundabout should not be tagged as roundabout).' + title: "Roundabout not closed loop" + description: "{var1} is part of a roundabout but is not closed-loop. (Split carriageways approaching a roundabout should not be tagged as roundabout)." 312: - title: 'Roundabout wrong direction' - description: 'If {var1} is in a country with {var2} traffic then its orientation goes the wrong way around.' + title: "Roundabout wrong direction" + description: "If {var1} is in a country with {var2} traffic then its orientation goes the wrong way around." 313: - title: 'Roundabout weakly connected' - description: '{var1} has only {var2} other road(s) connected. Roundabouts typically have 3 or more.' + title: "Roundabout weakly connected" + description: "{var1} has only {var2} other road(s) connected. Roundabouts typically have 3 or more." 320: - title: 'Improper link connection' + title: "Improper link connection" description: '{var1} is tagged as "{var2}" but doesn''t have a connection to any other "{var3}" or "{var4}".' 350: - title: 'Improper bridge tag' - description: '{var1} doesn''t have a tag in common with its surrounding ways that shows the purpose of this bridge. There should be one of these tags: {var2}.' + title: "Improper bridge tag" + description: "{var1} doesn't have a tag in common with its surrounding ways that shows the purpose of this bridge. There should be one of these tags: {var2}." 360: - title: 'Missing local name tag' + title: "Missing local name tag" description: 'It would be nice if {var1} had a local name tag "name:XX={var2}" where XX shows the language of its common name "{var2}".' 370: - title: 'Doubled places' - description: '{var1} has tags in common with the surrounding way {var2} {var3} and seems to be redundant.' + title: "Doubled places" + description: "{var1} has tags in common with the surrounding way {var2} {var3} and seems to be redundant." including_the_name: "(including the name {name})" 380: - title: 'Non-physical use of sport tag' + title: "Non-physical use of sport tag" description: '{var1} is tagged "{var2}" but has no physical tag (e.g. "leisure", "building", "amenity", or "highway").' 390: - title: 'Missing tracktype' + title: "Missing tracktype" description: '{var1} doesn''t have a "tracktype" tag.' 400: - title: 'Geometry issue' - description: 'There is an unspecified issue with the geometry here.' + title: "Geometry issue" + description: "There is an unspecified issue with the geometry here." 401: - title: 'Missing turn restriction' - description: 'Ways {var1} and {var2} join in a very sharp angle here and there is no oneway tag or turn restriction that prevents turning.' + title: "Missing turn restriction" + description: "Ways {var1} and {var2} join in a very sharp angle here and there is no oneway tag or turn restriction that prevents turning." 402: - title: 'Impossible angle' - description: '{var1} bends in a very sharp angle here.' + title: "Impossible angle" + description: "{var1} bends in a very sharp angle here." 410: - title: 'Website issue' - description: 'There is an unspecified issue with a contact website or URL.' + title: "Website issue" + description: "There is an unspecified issue with a contact website or URL." 411: - description: '{var1} may have an outdated URL: {var2} returned HTTP status code {var3}.' + description: "{var1} may have an outdated URL: {var2} returned HTTP status code {var3}." 412: description: '{var1} may have an outdated URL: {var2} contained suspicious text "{var3}".' 413: @@ -1578,7 +1587,7 @@ en: open_data_h: "Open Data" open_data: "Edits that you make on this map will be visible to everyone who uses OpenStreetMap. Your edits can be based on personal knowledge, on-the-ground surveying, or imagery collected from aerial or street level photos. Copying from commercial sources, like Google Maps, [is strictly forbidden](https://www.openstreetmap.org/copyright)." before_start_h: "Before you start" - before_start: "You should be familiar with OpenStreetMap and this editor before you start editing. Rapid contains a walkthrough to teach you the basics of editing OpenStreetMap. Press the \"{start_the_walkthrough}\" button on this screen to start the tutorial—it takes only about 15 minutes." + before_start: 'You should be familiar with OpenStreetMap and this editor before you start editing. Rapid contains a walkthrough to teach you the basics of editing OpenStreetMap. Press the "{start_the_walkthrough}" button on this screen to start the tutorial—it takes only about 15 minutes.' open_source_h: "Open Source" open_source: "The Rapid editor is a collaborative open source project, and you are using version {version} now. The source code is available [on GitHub](https://github.com/facebook/Rapid)." open_source_help: "You can help Rapid by [reporting bugs](https://github.com/facebook/Rapid/issues)." @@ -1620,11 +1629,11 @@ en: type: "You can press the feature type to change the feature to a different type. Everything that exists in the real world can be added to OpenStreetMap, so there are thousands of feature types to choose from." type_picker: "The type picker displays the most common feature types, such as parks, hospitals, restaurants, roads, and buildings. You can search for anything by typing what you're looking for in the search box. You can also press the {inspect} **Info** icon next to the feature type to learn more about it." fields_h: "Fields" - fields_all_fields: "The \"{fields}\" section contains all of the feature's details that you may edit. In OpenStreetMap, all of the fields are optional, and it's OK to leave a field blank if you are unsure." + fields_all_fields: 'The "{fields}" section contains all of the feature''s details that you may edit. In OpenStreetMap, all of the fields are optional, and it''s OK to leave a field blank if you are unsure.' fields_example: "Each feature type will display different fields. For example, a road may display fields for its surface and speed limit, but a restaurant may display fields for the type of food it serves and the hours it is open." - fields_add_field: "You can also use the \"Add field\" dropdown to add more fields, such as a description, Wikipedia link, wheelchair access, and more." + fields_add_field: 'You can also use the "Add field" dropdown to add more fields, such as a description, Wikipedia link, wheelchair access, and more.' tags_h: "Tags" - tags_all_tags: "Below the fields section, you can expand the \"{tags}\" section to edit any of the OpenStreetMap *tags* for the selected feature. Each tag consists of a *key* and *value*, data elements that define all of the features stored in OpenStreetMap." + tags_all_tags: 'Below the fields section, you can expand the "{tags}" section to edit any of the OpenStreetMap *tags* for the selected feature. Each tag consists of a *key* and *value*, data elements that define all of the features stored in OpenStreetMap.' tags_resources: "Editing a feature's tags requires intermediate knowledge about OpenStreetMap. You should consult resources like the [OpenStreetMap Wiki](https://wiki.openstreetmap.org/wiki/Main_Page) or [Taginfo](https://taginfo.openstreetmap.org/) to learn more about accepted OpenStreetMap tagging practices." points: title: Points @@ -1683,8 +1692,8 @@ en: title: Relations intro: "A *relation* is a special type of feature in OpenStreetMap that groups together other features. The features that belong to a relation are called *members*, and each member can have a *role* in the relation." edit_relation_h: "Editing Relations" - edit_relation: "At the bottom of the feature editor, you can expand the \"{relations}\" section to see if the selected feature is a member of any relations. You can then select a relation to edit it." - edit_relation_add: "To add a feature to a relation, select the feature, then press the {plus} add button in the \"{relations}\" section of the feature editor. You can choose from a list of nearby relations, or choose the \"{new_relation}\" option." + edit_relation: 'At the bottom of the feature editor, you can expand the "{relations}" section to see if the selected feature is a member of any relations. You can then select a relation to edit it.' + edit_relation_add: 'To add a feature to a relation, select the feature, then press the {plus} add button in the "{relations}" section of the feature editor. You can choose from a list of nearby relations, or choose the "{new_relation}" option.' edit_relation_delete: "You can also press the {delete_icon} **{delete}** button to remove the selected feature from the relation. If you remove all of the members from a relation, the relation will be deleted automatically." maintain_relation_h: "Maintaining Relations" maintain_relation: "For the most part, Rapid will maintain relations automatically as you edit. You should take care when replacing features that might be members of relations. For example if you delete a section of road and draw a new section of road to replace it, you should add the new section to the same relations (routes, turn restrictions, etc.) as the original." @@ -1695,14 +1704,14 @@ en: multipolygon_merge: "Merging several lines or areas will create a new multipolygon relation with all selected areas as members. Rapid will choose the inner and outer roles automatically, based on which features are contained inside other features." turn_restriction_h: "Turn restrictions" turn_restriction: "A *turn restriction* relation is a group of several road segments in an intersection. Turn restrictions consist of a *from* road, *via* node or roads, and a *to* road." - turn_restriction_field: "To edit turn restrictions, select a junction node where two or more roads meet. The feature editor will display a special \"{turn_restrictions}\" field containing a model of the intersection." - turn_restriction_editing: "In the \"{turn_restrictions}\" field, select a \"from\" road, and see whether turns are allowed or restricted to any of the \"to\" roads. You can press the turn icons to toggle them between allowed and restricted. Rapid will create relations automatically and set the from, via, and to roles based on your choices." + turn_restriction_field: 'To edit turn restrictions, select a junction node where two or more roads meet. The feature editor will display a special "{turn_restrictions}" field containing a model of the intersection.' + turn_restriction_editing: 'In the "{turn_restrictions}" field, select a "from" road, and see whether turns are allowed or restricted to any of the "to" roads. You can press the turn icons to toggle them between allowed and restricted. Rapid will create relations automatically and set the from, via, and to roles based on your choices.' route_h: "Routes" route: "A *route* relation is a group of one or more line features that together form a route network, like a bus route, train route, or highway route." - route_add: "To add a feature to a route relation, select the feature and scroll down to the \"{relations}\" section of the feature editor, then press the {plus} add button to add this feature to a nearby existing relation or a new relation." + route_add: 'To add a feature to a route relation, select the feature and scroll down to the "{relations}" section of the feature editor, then press the {plus} add button to add this feature to a nearby existing relation or a new relation.' boundary_h: "Boundaries" boundary: "A *boundary* relation is a group of one or more line features that together form an administrative boundary." - boundary_add: "To add a feature to a boundary relation, select the feature and scroll down to the \"{relations}\" section of the feature editor, then press the {plus} add button to add this feature to a nearby existing relation or a new relation." + boundary_add: 'To add a feature to a boundary relation, select the feature and scroll down to the "{relations}" section of the feature editor, then press the {plus} add button to add this feature to a nearby existing relation or a new relation.' operations: title: Operations intro: "*Operations* are special commands you can use to edit features. {mouse_right_icon} Right-click or {onefinger_tap_and_hold_icon} long-press any feature to view the available operations." @@ -1740,7 +1749,7 @@ en: choosing: "To see which imagery sources are available for editing, open the {layers_icon} **{background_settings}** panel on the side of the map." sources: "The [Bing Maps](https://www.bing.com/maps/) satellite layer or the best local imagery is set as the default background. Depending on where you are editing, multiple imagery sources are available. Some may be newer or have higher resolution, so it is always useful to check and see which layer is the best one to use as a mapping reference." offsets_h: "Adjusting Imagery Offset" - offset: "Imagery is sometimes offset slightly from accurate map data. If you see a lot of roads or buildings shifted from the background imagery, it may be the imagery that's incorrect, so don't move them all to match the background. Instead, you can adjust the background so that it matches the existing data by expanding the \"{imagery_offset}\" section at the bottom of the Background Settings pane." + offset: 'Imagery is sometimes offset slightly from accurate map data. If you see a lot of roads or buildings shifted from the background imagery, it may be the imagery that''s incorrect, so don''t move them all to match the background. Instead, you can adjust the background so that it matches the existing data by expanding the "{imagery_offset}" section at the bottom of the Background Settings pane.' offset_change: "Press the small triangle buttons to adjust the imagery offset in small steps, or hold the {mouse_left_icon} left mouse button and drag within the gray square to slide the imagery into alignment." streetlevel: title: Street Level Photos @@ -1771,8 +1780,8 @@ en: title: About about: "This field allows you to inspect and modify turn restrictions. It displays a model of the selected intersection including other nearby connected roads." from_via_to: "A turn restriction always contains: one **FROM way**, one **TO way**, and either one **VIA node** or one or more **VIA ways**." - maxdist: "The \"{distField}\" slider controls how far to search for additional connected roads." - maxvia: "The \"{viaField}\" slider adjusts how many via ways may be included in the search. (Tip: simple is better)" + maxdist: 'The "{distField}" slider controls how far to search for additional connected roads.' + maxvia: 'The "{viaField}" slider adjusts how many via ways may be included in the search. (Tip: simple is better)' inspecting: title: Inspecting about: "Hover over any **FROM** segment to see whether it has any turn restrictions. Each possible **TO** destination will be drawn with a colored shadow showing whether a restriction exists." @@ -1780,12 +1789,12 @@ en: allow_shadow: "{allowShadow} **TO Allowed**" restrict_shadow: "{restrictShadow} **TO Restricted**" only_shadow: "{onlyShadow} **TO Only**" - restricted: "\"Restricted\" means that there is a turn restriction, for example \"No Left Turn\"." - only: "\"Only\" means that a vehicle taking that path may only make that choice, for example \"Only Straight On\"." + restricted: '"Restricted" means that there is a turn restriction, for example "No Left Turn".' + only: '"Only" means that a vehicle taking that path may only make that choice, for example "Only Straight On".' modifying: title: Modifying about: "To modify turn restrictions, first click on any starting **FROM** segment to select it. The selected segment will pulse, and all possible **TO** destinations will appear as turn symbols." - indicators: "Then, click on a turn symbol to toggle it between \"Allowed\", \"Restricted\", and \"Only\"." + indicators: 'Then, click on a turn symbol to toggle it between "Allowed", "Restricted", and "Only".' allow_turn: "{allowTurn} **TO Allowed**" restrict_turn: "{restrictTurn} **TO Restricted**" only_turn: "{onlyTurn} **TO Only**" @@ -1793,8 +1802,8 @@ en: title: Tips simple: "**Prefer simple restrictions over complex ones.**" simple_example: "For example, avoid creating a via-way restriction if a simpler via-node turn restriction will do." - indirect: "**Some restrictions display the text \"(indirect)\" and are drawn lighter.**" - indirect_example: "These restrictions exist because of another nearby restriction. For example, an \"Only Straight On\" restriction will indirectly create \"No Turn\" restrictions for all other paths through the intersection." + indirect: '**Some restrictions display the text "(indirect)" and are drawn lighter.**' + indirect_example: 'These restrictions exist because of another nearby restriction. For example, an "Only Straight On" restriction will indirectly create "No Turn" restrictions for all other paths through the intersection.' indirect_noedit: "You may not edit indirect restrictions. Instead, edit the nearby direct restriction." issues: title: Issues @@ -1871,7 +1880,7 @@ en: remove_all: Remove all crossing tags update_type: "Update tags for a '{type}' crossing" area_as_point: - message: '{feature} should be an area, not a point' + message: "{feature} should be an area, not a point" close_nodes: title: "Very Close Points" tip: "Find redundant and crowded points" @@ -1952,8 +1961,8 @@ en: message_language: '{feature} has the suspicious name "{name}" in {language}' reference: "Names should be the actual, on-the-ground names of features." help_request: - title: 'Help Requests' - tip: 'Find features where others requested assistance' + title: "Help Requests" + tip: "Find features where others requested assistance" incompatible_source: title: Suspicious Sources tip: "Find features with suspicious source tags" @@ -1970,13 +1979,13 @@ en: title: Invalid Formatting tip: Find tags with unexpected formats email: - message: '{feature} has an invalid email address' - message_multi: '{feature} has multiple invalid email addresses' + message: "{feature} has an invalid email address" + message_multi: "{feature} has multiple invalid email addresses" reference: 'Email addresses must look like "user@example.com".' line_as_area: - message: '{feature} should be a line, not an area' + message: "{feature} should be a line, not an area" line_as_point: - message: '{feature} should be a line, not a point' + message: "{feature} should be a line, not a point" mismatched_geometry: title: Mismatched Geometry tip: "Find features with conflicting tags and geometry" @@ -2013,18 +2022,18 @@ en: message_incomplete: "{feature} looks like a common feature with incomplete tags" reference: "Some features, for example retail chains or post offices, are expected to have certain tags in common." point_as_area: - message: '{feature} should be a point, not an area' + message: "{feature} should be a point, not an area" point_as_line: - message: '{feature} should be a point, not a line' + message: "{feature} should be a point, not a line" point_as_vertex: - message: '{feature} should be a standalone point based on its tags' + message: "{feature} should be a standalone point based on its tags" reference: "Some features shouldn't be part of lines or areas." private_data: title: Private Information tip: "Find features that may contain private information" reference: "Sensitive data like personal phone numbers should not be tagged." contact: - message: '{feature} might be tagged with private contact information' + message: "{feature} might be tagged with private contact information" suspicious_name: title: Suspicious Names tip: "Find features with generic or suspicious names" @@ -2072,7 +2081,7 @@ en: buildings: reference: "Buildings with unsquare corners can often be drawn more accurately." vertex_as_point: - message: '{feature} should be part of a line or area based on its tags' + message: "{feature} should be part of a line or area based on its tags" reference: "Some features shouldn't be standalone points." fix: add_a_bridge: @@ -2169,7 +2178,7 @@ en: title: Tag as disconnected annotation: Tagged very close features as disconnected. tag_as_not: - title: "Tag as not the same \"{name}\"" + title: 'Tag as not the same "{name}"' annotation: "Added not: tag" tag_as_unsquare: title: Tag as physically unsquare @@ -2493,7 +2502,7 @@ en: select_road_again: "Next, we'll learn how to ignore roads that you don't want to add. **Select the AI-assisted road again with a left-click.**" ignore_road: "This time, press the 'Ignore this Feature' button to remove the incorrect road from the working map." help: "You're now ready to use AI-assisted roads! Once you have had some practice, be sure to look in the {button} Help button for key shortcuts with the {rapid} icon. These indicate new Rapid-specific shortcuts that speed up your mapping." - done: "You're all done! One final note- AI-assisted roads don't appear everywhere. For the most up-to-date information on feature availability, check the Available Countries List. **Click '{next}' to continue.**" + done: 'You''re all done! One final note- AI-assisted roads don''t appear everywhere. For the most up-to-date information on feature availability, check the Available Countries List. **Click ''{next}'' to continue.**' startediting: title: "Start Editing" help: "You're now ready to edit OpenStreetMap!{br}You can replay this walkthrough anytime or view more documentation by pressing the {help_icon} {help} button or the `{help_key}` key." @@ -2504,7 +2513,7 @@ en: title: "Keyboard Shortcuts" tooltip: "Show the keyboard shortcuts screen." toggle: - key: '?' + key: "?" key: alt: Alt backspace: Backspace @@ -2555,6 +2564,7 @@ en: osm_data: "Toggle OpenStreetMap data" rapid_features_data: "Toggle Rapid Features" highlight_edits: "Highlight unsaved edits" + pedestrian_mode: "Toggle Pedestrian Mode" selecting: title: "Selecting features" select_one: "Select a single feature" diff --git a/modules/core/DataLoaderSystem.js b/modules/core/DataLoaderSystem.js index 810beb269a..13ee6e6c32 100644 --- a/modules/core/DataLoaderSystem.js +++ b/modules/core/DataLoaderSystem.js @@ -23,6 +23,7 @@ export class DataLoaderSystem extends AbstractSystem { const fileMap = new Map(); fileMap.set('address_formats', 'data/address_formats.min.json'); + fileMap.set('colors', 'data/colors.min.json'); fileMap.set('deprecated', 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@6.6/dist/deprecated.min.json'); fileMap.set('discarded', 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@6.6/dist/discarded.min.json'); fileMap.set('imagery', 'data/imagery.min.json'); diff --git a/modules/core/StyleSystem.js b/modules/core/StyleSystem.js index 4beb1a4671..423634f827 100644 --- a/modules/core/StyleSystem.js +++ b/modules/core/StyleSystem.js @@ -13,10 +13,16 @@ const lifecycleVals = new Set([ 'intermittent', 'obliterated', 'planned', 'proposed', 'razed', 'removed', 'was' ]); +const pedestrianTags = new Set([ + 'path', 'steps', 'pedestrian', 'sidewalk', 'footway', 'garden', 'nature_reserve', + 'pitch', 'golf_course', 'park', 'dog_park', 'grass' +]); + // matches these things as a tag prefix const lifecycleRegex = new RegExp('^(' + Array.from(lifecycleVals).join('|') + '):'); + /** * `StyleSystem` maintains the the rules about how map data should look. * @@ -35,28 +41,31 @@ export class StyleSystem extends AbstractSystem { this.context = context; this.dependencies = new Set(['dataloader']); this.autoStart = true; + this.colorSchemes = null; + this.currentColorScheme = null; + this.focusMode = 'default'; // Experiment, see Rapid#1230 // matrix values from https://github.com/maputnik/editor this.protanopiaMatrix = [ - 0.567, 0.433, 0, 0, 0, - 0.558, 0.442, 0, 0, 0, - 0, 0.242, 0.758, 0, 0, - 0, 0, 0, 1, 0 + 0.567, 0.433, 0, 0, 0, + 0.558, 0.442, 0, 0, 0, + 0, 0.242, 0.758, 0, 0, + 0, 0, 0, 1, 0 ]; this.deuteranopiaMatrix = [ - 0.625, 0.375, 0, 0, 0, - 0.7, 0.3, 0, 0, 0, - 0, 0.3, 0.7, 0, 0, - 0, 0, 0, 1, 0 + 0.625, 0.375, 0, 0, 0, + 0.7, 0.3, 0, 0, 0, + 0, 0.3, 0.7, 0, 0, + 0, 0, 0, 1, 0 ]; this.tritanopiaMatrix = [ - 0.95, 0.05, 0, 0, 0, - 0, 0.433, 0.567, 0, 0, - 0, 0.475, 0.525, 0, 0, - 0, 0, 0, 1, 0 + 0.95, 0.05, 0, 0, 0, + 0, 0.433, 0.567, 0, 0, + 0, 0.475, 0.525, 0, 0, + 0, 0, 0, 1, 0 ]; @@ -88,7 +97,7 @@ export class StyleSystem extends AbstractSystem { this.STYLE_DECLARATIONS = { DEFAULTS: { - fill: { width: 2, color: 0xaaaaaa, alpha: 0.3 }, + fill: { width: 2, color: 0xaaaaaa, alpha: 0.3 }, casing: { width: 5, color: 0x444444, alpha: 1, cap: 'round', join: 'round' }, stroke: { width: 3, color: 0xcccccc, alpha: 1, cap: 'round', join: 'round' } }, @@ -98,43 +107,6 @@ export class StyleSystem extends AbstractSystem { stroke: { dash: [7, 3], cap: 'butt' } }, - red: { - fill: { color: 0xe06e5f, alpha: 0.3 } // rgb(224, 110, 95) - }, - green: { - fill: { color: 0x8cd05f, alpha: 0.3 } // rgb(140, 208, 95) - }, - blue: { - fill: { color: 0x77d4de, alpha: 0.3 } // rgb(119, 211, 222) - }, - yellow: { - fill: { color: 0xffff94, alpha: 0.25 } // rgb(255, 255, 148) - }, - gold: { - fill: { color: 0xc4be19, alpha: 0.3 } // rgb(196, 189, 25) - }, - orange: { - fill: { color: 0xd6881a, alpha: 0.3 } // rgb(214, 136, 26) - }, - pink: { - fill: { color: 0xe3a4f5, alpha: 0.3 } // rgb(228, 164, 245) - }, - teal: { - fill: { color: 0x99e1aa, alpha: 0.3 } // rgb(153, 225, 170) - }, - lightgreen: { - fill: { color: 0xbee83f, alpha: 0.3 } // rgb(191, 232, 63) - }, - tan: { - fill: { color: 0xf5dcba, alpha: 0.3 } // rgb(245, 220, 186) - }, - darkgray: { - fill: { color: 0x8c8c8c, alpha: 0.5 } // rgb(140, 140, 140) - }, - lightgray: { - fill: { color: 0xaaaaaa, alpha: 0.3 } // rgb(170, 170, 170) - }, - motorway: { casing: { width: 10, color: 0x70372f }, stroke: { width: 8, color: 0xcf2081 } @@ -216,17 +188,17 @@ export class StyleSystem extends AbstractSystem { stroke: { width: 3, color: 0x81d25c, dash: [3, 3], cap: 'butt' } }, river: { - fill: { color: 0x77d4de, alpha: 0.3 }, // rgb(119, 211, 222) + fill: { color: 0x77d4de, alpha: 0.3 }, // rgb(119, 211, 222) casing: { width: 10, color: 0x444444 }, stroke: { width: 8, color: 0x77dddd } }, stream: { - fill: { color: 0x77d4de, alpha: 0.3 }, // rgb(119, 211, 222) + fill: { color: 0x77d4de, alpha: 0.3 }, // rgb(119, 211, 222) casing: { width: 7, color: 0x444444 }, stroke: { width: 5, color: 0x77dddd } }, ridge: { - stroke: { width: 2, color: 0x8cd05f} // rgb(140, 208, 95) + stroke: { width: 2, color: 0x8cd05f } // rgb(140, 208, 95) }, runway: { casing: { width: 10, color: 0x000000, cap: 'butt' }, @@ -261,7 +233,7 @@ export class StyleSystem extends AbstractSystem { stroke: { width: 3, color: 0xdddddd, dash: [10, 5, 2, 5], cap: 'round' } }, barrier_hedge: { - fill: { color: 0x8cd05f, alpha: 0.3 }, // rgb(140, 208, 95) + fill: { color: 0x8cd05f, alpha: 0.3 }, // rgb(140, 208, 95) casing: { alpha: 0 }, // disable stroke: { width: 3, color: 0x8cd05f, dash: [10, 5, 2, 5], cap: 'round' } }, @@ -270,7 +242,7 @@ export class StyleSystem extends AbstractSystem { stroke: { width: 5, color: 0x8cd05f } }, construction: { - casing: { width: 10, color: 0xffffff}, + casing: { width: 10, color: 0xffffff }, stroke: { width: 8, color: 0xfc6c14, dash: [10, 10], cap: 'butt' } }, pipeline: { @@ -280,9 +252,11 @@ export class StyleSystem extends AbstractSystem { roller_coaster: { casing: { width: 7, color: 0x444444 }, stroke: { width: 5, color: 0xdddddd, dash: [10, 1], cap: 'butt' } - } + }, }; + + // // A "Style Selector" contains OSM key/value tags to match to a style declaration. // Each style selector looks like this: @@ -553,6 +527,11 @@ export class StyleSystem extends AbstractSystem { this.styleMatch = this.styleMatch.bind(this); + this.getColorScheme = this.getColorScheme.bind(this); + this.getAllColorSchemes = this.getAllColorSchemes.bind(this); + this.setColorScheme = this.setColorScheme.bind(this); + this.setMode = this.setMode.bind(this); + this.getMode = this.getMode.bind(this); } @@ -561,10 +540,10 @@ export class StyleSystem extends AbstractSystem { * Called after all core objects have been constructed. * @return {Promise} Promise resolved when this component has completed initialization */ - initAsync(){ + initAsync() { for (const id of this.dependencies) { if (!this.context.systems[id]) { - return Promise.reject(`Cannot init: ${this.id} requires ${id}`); + return Promise.reject(`Cannot init: ${this.id} requires ${id}`); } } return Promise.resolve(); @@ -577,6 +556,19 @@ export class StyleSystem extends AbstractSystem { */ startAsync() { this._started = true; + + // To handle color schemes + const context = this.context; + const dataloader = context.systems.dataloader; + + dataloader.getDataAsync('colors') + .then((data) => { + this.colorSchemes = data; + // set current scheme to default + this.currentColorScheme = data.default; + this.emit('colorsloaded'); // emit copies + }); + return Promise.resolve(); } @@ -590,12 +582,58 @@ export class StyleSystem extends AbstractSystem { return Promise.resolve(); } + /** + * getColorScheme + * @return {Object} Default color scheme object + */ + getColorScheme() { + return this.currentColorScheme; + } + + /** + * getAllColorSchemeas + * @return {Object} All color scheme objects + */ + getAllColorSchemes() { + return this.colorSchemes; + } + + /** + * setColorScheme + * Assigns the colorData var to the new scheme, if the selected scheme is not the current scheme + * @param {Object} scheme - color scheme project + */ + setColorScheme(scheme) { + let currentScheme = this.colorSchemes[scheme]; + if (this.currentColorScheme !== currentScheme) { + this.currentColorScheme = currentScheme; + } + } + + /** + * setMode + * Assigns Focus mode + * @param {String} mode - Mode Name + */ + setMode(mode) { + this.focusMode = mode; + } + + /** + * getMode + * Retrive Focus mode name + * @return {String} mode - Mode Name + */ + getMode() { + return this.focusMode; + } /** * styleMatch * @param {Object} tags - OSM tags to match to a display style * @return {Object} Styling info for the given tags */ + // eslint-disable-next-line complexity styleMatch(tags) { const defaults = this.STYLE_DECLARATIONS.DEFAULTS; @@ -603,6 +641,8 @@ export class StyleSystem extends AbstractSystem { let styleScore = 999; // lower numbers are better let styleKey; // the key controlling the styling, if any let styleVal; // the value controlling the styling, if any + let tagName; + let colorScheme = this.getColorScheme(); // First, match the tags to the best matching `styleID`.. for (const [k, v] of Object.entries(tags)) { @@ -617,7 +657,7 @@ export class StyleSystem extends AbstractSystem { if (lifecycleVals.has(v)) score = 999; // exception: lifecycle values if (styleID && score <= styleScore) { - const declaration = this.STYLE_DECLARATIONS[styleID]; + const declaration = this.STYLE_DECLARATIONS[styleID] || colorScheme[styleID]; if (!declaration) { console.error(`invalid styleID: ${styleID}`); // eslint-disable-line continue; @@ -626,7 +666,8 @@ export class StyleSystem extends AbstractSystem { matched = declaration; styleScore = score; styleKey = k; - styleVal = v; + styleVal = styleID; + tagName = v; if (styleScore === 1) break; // no need to keep looking at tags } @@ -643,14 +684,14 @@ export class StyleSystem extends AbstractSystem { hasLifecycleTag = true; break; - // Lifecycle value, e.g. `railway=demolished` - // (applies only if `k` is styleKey or there is no styleKey controlling styling) + // Lifecycle value, e.g. `railway=demolished` + // (applies only if `k` is styleKey or there is no styleKey controlling styling) } else if ((!styleKey || k === styleKey) && lifecycleVals.has(v)) { hasLifecycleTag = true; break; - // Lifecycle key prefix, e.g. `demolished:railway=rail` - // (applies only if there is no styleKey controlling the styling) + // Lifecycle key prefix, e.g. `demolished:railway=rail` + // (applies only if there is no styleKey controlling the styling) } else if (!styleKey && lifecycleRegex.test(k) && v !== 'no') { hasLifecycleTag = true; break; @@ -684,6 +725,7 @@ export class StyleSystem extends AbstractSystem { const tracktype = getTag(tags, 'tracktype'); const tunnel = getTag(tags, 'tunnel'); let surface = getTag(tags, 'surface'); + if (highway === 'track' && tracktype !== 'grade1') { surface = surface || 'dirt'; // assume unimproved (non-grade1) tracks have 'dirt' surface } @@ -707,6 +749,25 @@ export class StyleSystem extends AbstractSystem { style.casing.dash = [4, 4]; } + // If a focus mode is enabled, reduce alpha of all elements not in focus + if (this.focusMode === 'pedestrian') { + if (!pedestrianTags.has(tagName) && getTag(tags, 'foot') === undefined) { + style.fill.alpha = 0.1; + style.fill.color = 0x848884; + + style.casing.alpha = 0.1; + style.casing.color = 0x848884; + + style.stroke.alpha = 0.1; + style.stroke.color = 0x848884; + + } else { + if (tagName === 'sidewalk' || tagName === 'footway' || tagName === 'path') { + style.casing.width = 8; + } + } + } + // After applying all other styling rules and overrides, perform lifecycle overrides. // (This is for features that are not really existing - "abandoned", "proposed", etc.) if (hasLifecycleTag) { @@ -755,6 +816,7 @@ export class StyleSystem extends AbstractSystem { } } + return style; diff --git a/modules/ui/panes/preferences.js b/modules/ui/panes/preferences.js index b9ab5ce188..6521ff69d9 100644 --- a/modules/ui/panes/preferences.js +++ b/modules/ui/panes/preferences.js @@ -1,22 +1,24 @@ import { uiPane } from '../pane.js'; import { uiSectionPrivacy } from '../sections/privacy.js'; -//import { uiSectionColorSelection } from '../sections/color_selection.js'; -//import { uiSectionColorblindModeOptions } from '../sections/colorblind_mode_options.js'; import { uiSectionMapInteractionOptions } from '../sections/map_interaction_options.js'; +import { uiSectionColorSelection } from '../sections/color_selection.js'; +import { uiSectionColorblindModeOptions } from '../sections/colorblind_mode_options.js'; +import { uiSectionFocusModes } from '../sections/focus_modes.js'; export function uiPanePreferences(context) { - const l10n = context.systems.l10n; + const l10n = context.systems.l10n; - return uiPane(context, 'preferences') - .key(l10n.t('preferences.key')) - .label(l10n.t('preferences.title')) - .description(l10n.t('preferences.description')) - .iconName('fas-user-cog') - .sections([ - uiSectionPrivacy(context), - uiSectionMapInteractionOptions(context), -// uiSectionColorSelection(context), -// uiSectionColorblindModeOptions(context) - ]); + return uiPane(context, 'preferences') + .key(l10n.t('preferences.key')) + .label(l10n.t('preferences.title')) + .description(l10n.t('preferences.description')) + .iconName('fas-user-cog') + .sections([ + uiSectionPrivacy(context), + uiSectionMapInteractionOptions(context), + uiSectionColorSelection(context), + uiSectionColorblindModeOptions(context), + uiSectionFocusModes(context) + ]); } diff --git a/modules/ui/sections/color_selection.js b/modules/ui/sections/color_selection.js index b7ca52679b..0bc958b82f 100644 --- a/modules/ui/sections/color_selection.js +++ b/modules/ui/sections/color_selection.js @@ -3,19 +3,18 @@ import { uiCombobox } from '../combobox.js'; import { uiSection } from '../section.js'; import { utilNoAuto } from '../../util/index.js'; - export function uiSectionColorSelection(context) { const l10n = context.systems.l10n; - const colors = context.systems.colors; // todo: replace + const styles = context.systems.styles; // Add or replace event handlers - colors.off('colorsloaded', loadComboBoxData); - colors.on('colorsloaded', loadComboBoxData); + styles.off('colorsloaded', loadComboBoxData); + styles.on('colorsloaded', loadComboBoxData); let comboData = []; - function loadComboBoxData(){ - let colorSchemeKeys = Object.keys(colors.getAllColorSchemes()); + function loadComboBoxData() { + let colorSchemeKeys = Object.keys(styles.getAllColorSchemes()); for (let i = 0; i < colorSchemeKeys.length; i++) { let colorObject = {}; @@ -27,9 +26,8 @@ export function uiSectionColorSelection(context) { return comboData; } - const section = uiSection(context, 'preferences-color-selection') - .label(l10n.tHtml('preferences.color_selection.title')) + .label(l10n.t('preferences.color_selection.title')) .disclosureContent(renderDisclosureContent); const colorCombo = uiCombobox(context, 'color-selection'); @@ -63,8 +61,8 @@ export function uiSectionColorSelection(context) { _colorSelectedId = val; let colorSchemeName = getColorSchemeName(_colorSelectedId); - if (colors.currentColorScheme !== colorSchemeName) { - colors.setColorScheme(colorSchemeName); + if (styles.currentColorScheme !== colorSchemeName) { + styles.setColorScheme(colorSchemeName); context.scene().dirtyScene(); context.systems.map.deferredRedraw(); } diff --git a/modules/ui/sections/colorblind_mode_options.js b/modules/ui/sections/colorblind_mode_options.js index a5cc99f5eb..080d4054cb 100644 --- a/modules/ui/sections/colorblind_mode_options.js +++ b/modules/ui/sections/colorblind_mode_options.js @@ -7,7 +7,7 @@ import { utilNoAuto } from '../../util/index.js'; export function uiSectionColorblindModeOptions(context) { const l10n = context.systems.l10n; - const colors = context.systems.colors; // todo: replace + const styles = context.systems.styles; let comboData = [{ title: 'default', value: l10n.t('preferences.colorblind_options.default') }]; @@ -20,16 +20,16 @@ export function uiSectionColorblindModeOptions(context) { const filtersObject = { 'Protanopia': protanopiaFilter, 'Deuteranopia': deuteranopiaFilter, 'Tritanopia': tritanopiaFilter }; // color matrices - const protanopiaMatrix = colors.protanopiaMatrix; - const deuteranopiaMatrix = colors.deuteranopiaMatrix; - const tritanopiaMatrix = colors.tritanopiaMatrix; + const protanopiaMatrix = styles.protanopiaMatrix; + const deuteranopiaMatrix = styles.deuteranopiaMatrix; + const tritanopiaMatrix = styles.tritanopiaMatrix; // apply color matrices to filters protanopiaFilter.matrix = protanopiaMatrix; deuteranopiaFilter.matrix = deuteranopiaMatrix; tritanopiaFilter.matrix = tritanopiaMatrix; - function loadComboBoxData(){ + function loadComboBoxData() { let colorblindModes = Object.keys(filtersObject); for (let i = 0; i < colorblindModes.length; i++) { @@ -45,7 +45,7 @@ export function uiSectionColorblindModeOptions(context) { loadComboBoxData(); const section = uiSection(context, 'preferences-colorblind-mode-options') - .label(l10n.tHtml('preferences.colorblind_options.title')) + .label(l10n.t('preferences.colorblind_options.title')) .disclosureContent(renderDisclosureContent); const colorblindCombo = uiCombobox(context, 'colorblind-mode-options'); diff --git a/modules/ui/sections/focus_modes.js b/modules/ui/sections/focus_modes.js new file mode 100644 index 0000000000..f2b4d16f51 --- /dev/null +++ b/modules/ui/sections/focus_modes.js @@ -0,0 +1,109 @@ +/* eslint-disable linebreak-style */ +import { uiTooltip } from '../tooltip.js'; +import { uiSection } from '../section.js'; +import { uiCmd } from '../cmd.js'; + +export function uiSectionFocusModes(context) { + const styles = context.systems.styles; + const l10n = context.systems.l10n; + + const section = uiSection(context, 'focus-modes') + .label(l10n.t('preferences.focus_modes.title')) + .disclosureContent(renderDisclosureContent); + + const FOCUS_OPTIONS = ['default', 'pedestrian']; + + function renderDisclosureContent(selection) { + let container = selection.selectAll('.focus-mode-options') + .data([0]); + + // Enter + const enter = container.enter() + .append('div') + .attr('class', 'focus-mode-options'); + + enter + .append('ul') + .attr('class', 'layer-list focus-mode-options-list'); + + // Update + container + .merge(enter) + .selectAll('.focus-mode-options-list') + .call(drawListItems); + } + + + function drawListItems(selection) { + let items = selection.selectAll('li') + .data(FOCUS_OPTIONS); + + // Exit + items.exit() + .remove(); + + // Enter + let enter = items.enter() + .append('li') + .call(uiTooltip(context) + .title(d => l10n.t(`preferences.focus_modes.${d}.tooltip`)) + .placement('top') + ); + + let label = enter + .append('label'); + + label + .append('input') + .attr('type', 'radio') + .attr('name', 'focus_modes') + .on('change', setFocusMode); + + label + .append('span') + .text(d => l10n.t(`preferences.focus_modes.${d}.title`)); + + // Update + items = items + .merge(enter); + + update(); + + function update() { + items + .classed('active', isModeActive) + .selectAll('input') + .property('checked', isModeActive) + .property('indeterminate', false); + } + + const preferenceKey = l10n.t('preferences.key'); + + context.keybinding() + .on(uiCmd('⌥' + preferenceKey), e => { + e.preventDefault(); + e.stopPropagation(); + + const currMode = styles.getMode(); + const newMode = currMode === 'default' ? 'pedestrian' : 'default'; + setFocusMode(null, newMode); + update(); + }); + } + + + function isModeActive(d) { + const curr = styles.getMode(); + return curr === d; + } + + function setFocusMode(d3_event, d) { + if (styles.focusMode !== d) { + styles.setMode(d); + context.scene().dirtyScene(); + context.systems.map.deferredRedraw(); + } + } + + return section; +} diff --git a/scripts/build_data.js b/scripts/build_data.js index 4c28000ab7..3698a018ce 100644 --- a/scripts/build_data.js +++ b/scripts/build_data.js @@ -99,6 +99,7 @@ function buildData() { minifySync('data/qa_data.json', 'dist/data/qa_data.min.json'); minifySync('data/shortcuts.json', 'dist/data/shortcuts.min.json'); minifySync('data/territory_languages.json', 'dist/data/territory_languages.min.json'); + minifySync('data/colors.json', 'dist/data/colors.min.json') return _currBuild = Promise.resolve(true) .then(() => {