meta { title: "MTB Trailmap (MTB Difficulty, uphill difficulty, path width, visibility and surface)"; icon: "presets/sport/cycling.svg"; description: "Easily visualize MTB trail difficulty, uphill difficulty, trail width, visibility, and surface type with color-coded indicators and text labels. Inspired by Trailmap.fi, this style ensures your edits are accurately reflected, providing clear and detailed trail information for mountain biking. Includes toggle options allow you to choose which trail attributes are displayed on the map layer. Designed to work seamlessly with JOSM's default styles, such as JOSM Standard and Potlatch 2."; version: "1.1.1_2024-08-01"; author: "Tommi Contursi"; link: "https://github.com/TommiContursi/MTB-TrailMap-JOSM-Style"; min-josm-version: 7110; } /* Settings toggles for users */ /* Toggle for displaying surface information on a separate path */ setting::surface_display { default: false; type: boolean; label: "Display Surface on Separate Paths"; } /* MTB scale styles with user toggle option */ setting::mtb_scale_display { default: true; type: boolean; label: "Display MTB Difficulty on Paths"; } /* Surface styles with user toggle option */ setting::surface_display_path { default: true; type: boolean; label: "Display Surface on Paths"; } /* MTB uphill scale styles with user toggle option */ setting::mtb_uphill_display { default: true; type: boolean; label: "Display MTB Uphill Difficulty on Separate Paths"; } /* Text display for mtb:scale */ setting::mtb_scale_text_display { default: true; type: boolean; label: "Text for MTB Difficulty on Paths"; } /* MTB uphill scale text with user toggle option */ setting::mtb_uphill_display_text { default: true; type: boolean; label: "Text for MTB Uphill Difficulty on Separate Paths"; } /* Surface text with user toggle option */ setting::surface_display_text { default: true; type: boolean; label: "Text for Surface on Paths"; } /* Disable path opacity */ setting::path_opacity { default: true; type: boolean; label: "Display Path Opacity Based on Visibility"; } /* Basic canvas background color canvas { fill-color: #606060; } */ /* Node styles for different zoom levels */ node { symbol-shape: circle; symbol-fill-color: darkgrey; symbol-stroke-color: lightgreen; } node, area { text-color: black; } node|z-15 { symbol-size: 0.1; } node|z16 { symbol-size: 2; } node|z17 { symbol-size: 3; symbol-stroke-width: 1; } node|z18- { symbol-size: 4; symbol-stroke-width: 1; } node:connection { symbol-fill-color: yellow; } /*Gates and barriers*/ node { text-anchor-horizontal: center; text-anchor-vertical: below; } node[barrier=gate], node[highway=gate] {icon-width:"25"; icon-image: "presets/barrier/gate.svg"; text: "barrier"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20;} node[barrier=lift_gate] {icon-width:"25";icon-image: "presets/barrier/lift_gate.svg"; text-offset:0; text: "barrier"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20; } node[barrier=kissing_gate] {icon-width:"25"; icon-image: "presets/barrier/kissing_gate.svg"; text-offset:0; text: "barrier"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20; } node[barrier=cycle_barrier] {icon-width:"25"; icon-image: "presets/barrier/cycle_barrier.svg"; text-offset:0; text: "barrier"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20; } node[barrier=log] {icon-width:"25"; icon-image: "presets/barrier/log.svg"; text-offset:0; text: "barrier"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20; } node[obstacle=fallen_tree] {icon-width:"25"; icon-image: "presets/barrier/log.svg"; text-offset:0; text: "obstacle"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20; } node[noexit=yes] {icon-width:"25"; icon-image: "presets/vehicle/restriction/dead_end.svg";z-index: 20; } node[/^fixme/] {icon-width:"25"; icon-image: "presets/misc/fixme.svg"; text-offset:0; text: "fixme"; text-offset:0; font-size: 10; text-halo-color: white; text-halo-radius: 1; z-index: 20; } node[fixme=continue] {icon-width:"25"; icon-image: "presets/misc/danger.svg"; z-index: 20; } /* Basic highway styles for cycleway, track, and path */ way[highway=~/track|path/] { color: #000; width: 2; casing-width: 2; dashes: 10, 5; } way[highway=track] { casing-color: #ffffff00; } way[highway=cycleway] { color: #3146d7; width: 3; dashes: 15, 5; casing-width: 1; dashes-background-color: #fff; casing-color: #fff; } way[highway=footway] { color: #a43820; width: 4; dashes: 5, 5; } /* Width based on track width */ way[highway=~/track|path/][width] { width: eval( tag("width") < 0.6 ? 2 : tag("width") < 0.9 ? 2 : tag("width") < 1.8 ? 3 : tag("width") > 1.8 ? 4 : 2 ); casing-width: eval( tag("width") < 0.6 ? 2 : tag("width") < 0.9 ? 2 : tag("width") < 1.8 ? 3 : tag("width") > 1.8 ? 4 : 2 ); } /* Visibility based styles */ way[trail_visibility=excellent] { dashes: 10, 6; } way[trail_visibility=good] { dashes: 10, 6; } way[trail_visibility=intermediate] { dashes: 2, 2; } way[trail_visibility=bad] { dashes: 2, 2; } way[trail_visibility=horrible] { dashes: 2, 2; } way[trail_visibility=no] { dashes: 2, 2; } way[setting("path_opacity")][trail_visibility=intermediate]{ casing-opacity: 0.75; dashes-background-opacity: 0.75; } way[setting("path_opacity")][trail_visibility=bad]{ casing-opacity: 0.5; dashes-background-opacity: 0.5; } way[setting("path_opacity")][trail_visibility=horrible]{ casing-opacity: 0.5; dashes-background-opacity: 0.5; } way[setting("path_opacity")][trail_visibility=no]{ casing-opacity: 0.5; dashes-background-opacity: 0.5; } /* surface based styles let's draw these on the trail by defaul and the style will be overridden with the trail difficulty*/ way[highway=~/track|path/][setting("surface_display_path")][surface] { casing-color: eval( tag("surface") == "paved" ? "#555555" : tag("surface") == "asphalt" ? "#333333" : tag("surface") == "gravel" ? "#cccccc" : tag("surface") == "dirt" ? "#a52a2a" : tag("surface") == "grass" ? "#006400" : tag("surface") == "sand" ? "#f4a460" : tag("surface") == "wood" ? "#deb887" : tag("surface") == "concrete" ? "#808080" : tag("surface") == "cobblestone" ? "#8b4513" : tag("surface") == "pebblestone" ? "#a9a9a9" : tag("surface") == "compacted" ? "#b8860b" : tag("surface") == "fine_gravel" ? "#d3d3d3" : tag("surface") == "grass_paver" ? "#006400" : tag("surface") == "paving_stones" ? "#a0522d" : tag("surface") == "metal" ? "#b0c4de" : tag("surface") == "bricks" ? "#b22222" : tag("surface") == "earth" ? "#a52a2a" : tag("surface") == "clay" ? "#d2691e" : tag("surface") == "mud" ? "#8b4513" : tag("surface") == "ground" ? "#8b4513" : tag("surface") == "rock" ? "#808080" : "#d3d3d3" ); } /* Basic road styles */ way[highway=~/unclassified|residential|tertiary|service/] { color: darkgrey; opacity: 0.5; casing-color: grey; casing-width: 2; } way|z-14[highway=~/unclassified|residential|tertiary|service/] { width: 3; } way|z15-16[highway=~/unclassified|residential|tertiary|service/] { width: 4; } way|z17-[highway=~/unclassified|residential|tertiary|service/] { width: 6; } way[highway=~/motorway|trunk|primary|secondary/] { color: darkgrey; opacity: 0.5; casing-color: grey; casing-width: 2; } way|z-14[highway=~/motorway|trunk|primary|secondary/] { width: 3; } way|z15-16[highway=~/motorway|trunk|primary|secondary/] { width: 4; } way|z17-[highway=~/motorway|trunk|primary|secondary/] { width: 6; } /* Waterways */ way[waterway] { color: #6CCEE4; width: 3; } /* Bicycle route relation underlay */ relation[type=route][route=~/bicycle|mtb/][network=ncn] > way::relation_underlay { z-index: -200; width: 15; color: red; opacity: 0.15; linecap: none; } relation[type=route][route=~/bicycle|mtb/][network=rcn] > way::relation_underlay { z-index: -200; width: 15; color: cyan; opacity: 0.15; linecap: none; } relation[type=route][route=~/bicycle|mtb/][network=lcn] > way::relation_underlay { z-index: -200; width: 15; color: blue; opacity: 0.15; linecap: none; } way|z18-[mtb:scale][setting("mtb_scale_text_display")]::mtbscale_layer { font-family: Arial; text: concat("S", tag("mtb:scale")); text-color: eval( tag("mtb:scale") == "0-" ? "#50d6eb" : tag("mtb:scale") == "0" ? "#75e009" : tag("mtb:scale") == "1" ? "#e3e800" : tag("mtb:scale") == "2" ? "#feb13e" : tag("mtb:scale") == "3" ? "#ff4454" : tag("mtb:scale") == "4" ? "#f20bab" : tag("mtb:scale") == "5" ? "#bf1cf5" : tag("mtb:scale") == "6" ? "#8100ac" : "#ffffff" ); font-size: 10; font-weight: bold; text-position: line; z-index: 2; text-halo-color: black; text-halo-radius: 1; } way|z19-[mtb:scale][setting("mtb_scale_text_display")]::mtbscale_layer { font-size: 14; } way|z20-[mtb:scale][setting("mtb_scale_text_display")]::mtbscale_layer { font-size: 16; } /* Surface information display for tracks and paths */ way[highway=~/track|path/][surface][setting("surface_display")]::path_surface { color: eval( tag("surface") == "paved" ? "#555555" : tag("surface") == "asphalt" ? "#333333" : tag("surface") == "gravel" ? "#555555" : tag("surface") == "dirt" ? "#a52a2a" : tag("surface") == "grass" ? "#006400" : tag("surface") == "sand" ? "#f4a460" : tag("surface") == "wood" ? "#deb887" : tag("surface") == "concrete" ? "#808080" : tag("surface") == "cobblestone" ? "#8b4513" : tag("surface") == "pebblestone" ? "#555555" : tag("surface") == "compacted" ? "#b8860b" : tag("surface") == "fine_gravel" ? "#555555" : tag("surface") == "grass_paver" ? "#006400" : tag("surface") == "paving_stones" ? "#a0522d" : tag("surface") == "metal" ? "#b0c4de" : tag("surface") == "bricks" ? "#b22222" : tag("surface") == "earth" ? "#a52a2a" : tag("surface") == "clay" ? "#d2691e" : tag("surface") == "mud" ? "#8b4513" : tag("surface") == "ground" ? "#8b4513" : tag("surface") == "rock" ? "#808080" : "#000000" ); width: eval( tag("width") < 0.6 ? 2 : tag("width") < 0.9 ? 2 : tag("width") < 1.8 ? 3 : tag("width") > 1.8 ? 4 : 2 ); dashes: 3, 3; offset: -5; /* opacity: eval( tag("trail_visibility") == "excellent" ? 1 : tag("trail_visibility") == "good" ? 1 : tag("trail_visibility") == "intermediate" ? 0.75 : tag("trail_visibility") == "bad" ? 0.5 : tag("trail_visibility") == "horrible" ? 0.5 : 1 ); */ } /* Text display for surface information */ way|z18-[highway=~/track|path/][surface][setting("surface_display_text")]::surface_text { text: tag("surface"); text-color: eval( tag("surface") == "paved" ? "#444444" : tag("surface") == "asphalt" ? "#222222" : tag("surface") == "gravel" ? "#999999" : tag("surface") == "dirt" ? "#8b0000" : tag("surface") == "grass" ? "#006400" : tag("surface") == "sand" ? "#d2b48c" : tag("surface") == "wood" ? "#8b4513" : tag("surface") == "concrete" ? "#505050" : tag("surface") == "cobblestone" ? "#654321" : tag("surface") == "pebblestone" ? "#696969" : tag("surface") == "compacted" ? "#8b5a2b" : tag("surface") == "fine_gravel" ? "#a9a9a9" : tag("surface") == "grass_paver" ? "#006400" : tag("surface") == "paving_stones" ? "#6b4423" : tag("surface") == "metal" ? "#4682b4" : tag("surface") == "bricks" ? "#800000" : tag("surface") == "earth" ? "#8b0000" : tag("surface") == "clay" ? "#a0522d" : tag("surface") == "mud" ? "#4b2e0f" : tag("surface") == "ground" ? "#4b2e0f" : tag("surface") == "rock" ? "#505050" : "#a9a9a9" ); font-size: 10; font-family: Arial; font-weight: bold; text-position: line; text-offset: -10; z-index: 3; text-halo-color: #ffffff; text-halo-radius: 1; } way|z19-[highway=~/track|path/][surface][setting("surface_display_text")]::surface_text { font-size: 11; text-offset: -12; } way|z20-[highway=~/track|path/][surface][setting("surface_display_text")]::surface_text { font-size: 13; text-offset: -14; } way[mtb:scale][setting("mtb_scale_display")] { casing-color: eval( tag("mtb:scale") == "0-" ? "#10c5a1" : tag("mtb:scale") == "0" ? "#75df08" : tag("mtb:scale") == "1" ? "#d8dc00" : tag("mtb:scale") == "2" ? "#feb13e" : tag("mtb:scale") == "3" ? "#ff4355" : tag("mtb:scale") == "4" ? "#e410dd" : tag("mtb:scale") == "5" ? "#9600c8" : tag("mtb:scale") == "6" ? "#8101ad" : "#ffffff" ); dashes-background-color: eval( tag("mtb:scale") == "0-" ? "#10c5a1" : tag("mtb:scale") == "0" ? "#75df08" : tag("mtb:scale") == "1" ? "#d8dc00" : tag("mtb:scale") == "2" ? "#feb13e" : tag("mtb:scale") == "3" ? "#ff4355" : tag("mtb:scale") == "4" ? "#e410dd" : tag("mtb:scale") == "5" ? "#9600c8" : tag("mtb:scale") == "6" ? "#8101ad" : "#ffffff" ); } /* Text display for mtb:scale:uphill */ way|z18-[mtb:scale][mtb:scale:uphill][setting("mtb_uphill_display_text")]::uphill_difficulty { text: concat("↑ S", tag("mtb:scale:uphill")); text-color: eval( tag("mtb:scale:uphill") == "0" ? "#75df08" : tag("mtb:scale:uphill") == "1" ? "#d8dc00" : tag("mtb:scale:uphill") == "2" ? "#feb13e" : tag("mtb:scale:uphill") == "3" ? "#ff4355" : tag("mtb:scale:uphill") == "4" ? "#e410dd" : tag("mtb:scale:uphill") == "5" ? "#8101ad" : "#ffffff" ); font-size: 10; font-weight: bold; text-offset: 12; text-position: line; z-index: 2; text-halo-color: black; text-halo-radius: 1; } way|z19-[mtb:scale][mtb:scale:uphill][setting("mtb_uphill_display_text")]::uphill_difficulty { font-size: 12; text-offset: 14; } way|z20-[mtb:scale][mtb:scale:uphill][setting("mtb_uphill_display_text")]::uphill_difficulty { font-size: 14; text-offset: 16; } way[mtb:scale:uphill][setting("mtb_uphill_display")]::uphill_difficulty { color: eval( tag("mtb:scale:uphill") == "0" ? "#3e5a04" : tag("mtb:scale:uphill") == "1" ? "#6d7300" : tag("mtb:scale:uphill") == "2" ? "#8b4f20" : tag("mtb:scale:uphill") == "3" ? "#8b202c" : tag("mtb:scale:uphill") == "4" ? "#710555" : tag("mtb:scale:uphill") == "5" ? "#5b0d7a" : "#999999" ); width: eval( tag("width") < 0.6 ? 4 : tag("width") < 0.9 ? 5 : tag("width") < 1.8 ? 6 : tag("width") > 1.8 ? 7 : 5 ); offset: eval( tag("width") < 0.6 ? 4 : tag("width") < 0.9 ? 6 : tag("width") < 1.8 ? 8 : tag("width") > 1.8 ? 10 : 6 ); /* opacity: eval( tag("trail_visibility") == "excellent" ? 1 : tag("trail_visibility") == "good" ? 1 : tag("trail_visibility") == "intermediate" ? 0.75 : tag("trail_visibility") == "bad" ? 0.5 : tag("trail_visibility") == "horrible" ? 0.5 : 1 ); */ dashes-background-opacity: 0.25; dashes-background-color: eval( tag("mtb:scale:uphill") == "0" ? "#75e009" : tag("mtb:scale:uphill") == "1" ? "#e3e800" : tag("mtb:scale:uphill") == "2" ? "#feb13e" : tag("mtb:scale:uphill") == "3" ? "#ff4454" : tag("mtb:scale:uphill") == "4" ? "#f20bab" : tag("mtb:scale:uphill") == "5" ? "#bf1cf5" : "#ffffff" ); } /*Eval doesn't work with dashes so this needs to be here */ way[mtb:scale:uphill=0][setting("mtb_uphill_display")]::uphill_difficulty { dashes: 0, 15; } way[mtb:scale:uphill=1][setting("mtb_uphill_display")]::uphill_difficulty { dashes: 1.4, 15; } way[mtb:scale:uphill=2][setting("mtb_uphill_display")]::uphill_difficulty { dashes: 1.4, 3, 1.4, 15; } way[mtb:scale:uphill=3][setting("mtb_uphill_display")]::uphill_difficulty { dashes: 1.4, 3, 1.4, 3, 1.4, 17; } way[mtb:scale:uphill=4][setting("mtb_uphill_display")]::uphill_difficulty { dashes: 1.4, 3, 1.4, 3, 1.4, 3, 1.4, 18; } way[mtb:scale:uphill=5][setting("mtb_uphill_display")]::uphill_difficulty { dashes: 1.4, 3, 1.4, 3, 1.4, 3, 1.4, 3, 1.4, 20; } /* Indicates no bicycle access or restricted access (no, private, permissive) for tracks and paths */ way[highway=~/track|path/][bicycle=permissive]::core_access, way[highway=~/track|path/][access=permissive]::core_access { z-index: -1; width: eval( tag("width") < 0.6 ? 10 : tag("width") < 0.9 ? 12 : tag("width") > 1.8 ? 14 : 12 ); color: #ff0000; dashes: 2, 15; } way[highway=~/track|path/][bicycle=no]::core_access, way[highway=~/track|path/][bicycle=private]::core_access, way[highway=~/track|path/][access=no]::core_access, way[highway=~/track|path/][access=private]::core_access { z-index: -1; width: eval( tag("width") < 0.6 ? 10 : tag("width") < 0.9 ? 12 : tag("width") > 1.8 ? 14 : 12 ); color: #ff0000; dashes: 4, 4; } /* Obstacles based styles */ way[highway=~/track|path/][obstacle=vegetation]::core_access { z-index: -1; color: #008300; dashes: 3, 7; offset: 8; width: eval( tag("width") < 0.6 ? 4 : tag("width") < 0.9 ? 6 : tag("width") > 1.8 ? 9 : 6 ); } way[highway=~/track|path/][obstacle=mud]::core_access { z-index: -1; color: #0071ff; dashes: 3, 7; offset: 8; width: eval( tag("width") < 0.6 ? 4 : tag("width") < 0.9 ? 6 : tag("width") > 1.8 ? 9 : 6 ); }