'murica!
The style is located within src/ and is organized as follows:
- layer/ - Individual style layers, organized by subject area. The ordering of layers is specified in
index.js
. - icons/ - SVG icons, which get converted into PNG stylesheets
- constants/ - Style elements that are frequently re-used
- js/ - Dynamic javascript code for highway shields and stylesheet building
- config.js - Configuration settings (MapTiler API key, OpenMapTiles tile server URL, etc)
- americana.js - MapLibre loader and configuration for the demo map
- index.html - Demonstration map HTML page
Any currently supported version of Node.js should work. The current LTS release is recommended. Installation options:
- Download and run the installer from nodejs.org
- Install via package manager (See platform specific notes below)
- Use NVM to manage multiple different Node.js versions
NPM is included with the Node.js install, but as NPM version 8.3 or newer is required for this project, you may need to update it. To update NPM to the latest version, run either of these commands:
npm update -g npm
npm install -g npm@latest
It may be necessary to prefix these with sudo
depending where NPM is installed on your system.
macOS doesn't include a default package manager, but Node.js and NPM can be installed via Homebrew or MacPorts:
- Homebrew -
brew install node
- MacPorts -
sudo port install npm8
Running the project natively on an Apple Silicon Mac is not currently possible due to dependency issues. However, it is possible to work around this by running the project through Rosetta.
The project can be run from any Windows command line environment provided that Node.js and npm are installed.
The Node.js packages in the default Ubuntu repos are generally out of date. Instead, it is recommended to use the NodeSource repositories for installing Node.js via APT. You can choose a specific version, or install the current LTS release:
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install nodejs
All other dependencies are installed via NPM. Dependencies are listed in the package.json
,
and package-lock.json
files. Run this command to install them in the project directory:
npm install
If you run into permissions errors with NPM, setting the user with this command may
help: npm -g config set user $USER
. Issues like this this can usually be avoided by
not running npm
with root
or sudo
. Another good troubleshooting step is
simply deleting the node_modules
folder (contains all the installed dependencies)
and re-running npm install
.
Environment specific settings go in the untracked file config.js
. Copy from one of
the templates in the configs/ folder config.*.js
and rename it config.js
in
the src/ root. The variables in this file can then be changed without the risk of
accidentally committing to the main repo. By default, the repository config.js
points
to a development tile server operated by the project maintainers. It is free to use
for development purposes but service is not guaranteed.
You can create a new copy of the config file by running npm run config
This project can use vector tiles provided by MapTiler.
For this to work, you must create an account and obtain a free key from
MapTiler Cloud. This key should be pasted into the MAPTILER_KEY
variable of
the config.js
file.
For testing upcoming features of the OpenMapTiles schema or for fresher data than
MapTiler Cloud provides, a custom vector tile url can be set in the OPENMAPTILES_URL
variable of the config.js
file. However, this requires setting up a custom OpenMapTiles
server which is beyond the scope of this guide.
For production usages, consider running your own tile server. Thanks to advances in technology, it is possible to run an OpenMapTiles tile server for a modest cost. See the diary entry Host an OpenMapTiles Vector Tile Server on AWS for $19.75/month for more details.
npm install
npm start
The simplest way to run the style is to run npm start
. This will generate the sprite
sheet and launch a simple HTTP server on port 1776 with a document root at the current
location. For a production installation, the .html and .js files, as well as the
generated sprites folder need to be installed on a production web server.
Running npm run sprites
will re-generate the sprite sheets without needing to
restart the web server.
npm install
npm run build
These commands will build a minified/bundled version of the Americana demo with
all assets in dist/
. The contents of dist/
can then be copied to a webserver
for distribution. A taginfo project file will also be generated based on the
boilerplate in scripts/taginfo_template.json
.
- Please prettify all files prior to submission. Run
npm run code_format
to format code files with prettier and SVG files with SVGO. - If you are introducing a new kind of feature to the style, add a section to
src/js/legend_config.js
or a legend entry in the corresponding file insrc/layer/
that tells the Legend control how to find and render a representative feature. Also try out the Samples button to catch any visual conflicts. - If you are introducing a novel approach to depicting a layer or feature
property from the OpenMapTiles schema, document how the corresponding
OpenStreetMap key or tag is used in
scripts/taginfo_template.json
. - If any shield background icons are introduced, add lines to
src/shieldtest.js
to demonstrate overlaid text on each of them. - If you are introducing new JavaScript code that can run independently of a
browser environment, add automated unit tests for it to
test/spec/
, then runnpm test
to ensure that they pass. This project structures unit tests using Chai for assertions.
When adding or changing style layer code, it can be helpful to assess the change in size and complexity. In general, higher layer counts and higher layer size have a negative impact in performance. Contributors should attempt to consolidate layers when possible.
There is a "stats" script that will generate various statistics about layer composition and complexity:
npm run -s stats -- -a -s
- overall size and breakdown of layersnpm run -s stats -- -c
- total layer countnpm run -s stats -- -h
- list all options
There is an "extract_layers" script that will extract layer style data:
npm run -s extract_layer -pl <layer>
- JSON contents of a specified layernpm run -s extract_layer -pg <source>
- list of layers from a specified sourcenpm run -s extract_layer -h
- list all options
- Layers must be uniquely named.
- For performance reasons, it is better to have fewer layers with filters than multiple, simpler layers.
- Layers are drawn in the order specified in
layer/index.js
using the Painter's Algorithm.
To see layer statistics, run npm run stats
to get a list of options.
Highway shields are a key feature of the OpenStreetMap Americana style. This guide describes some of the style principles that contributors of highway shield artwork should consider when submitting new shields. The required elements are as follows:
- Shields are in .svg format
- Shields are 20px on the smallest dimension (this will be rasterized to 20px or 40px depending on display resolution)
- Shields are license-compatible (public domain or CC0)
In addition, the following style guidelines are recommended:
- Use a 1px stroke size for line elements. Horizontal/vertical lines should be aligned to the pixel grid.
- In Inkscape, press
Ctrl+Shift+D
, and create a rectangular grid in the "Grids" tab. Set Spacing X and Spacing Y to0.5
, and Major grid line every2
. You can turn snapping to the grid on and off by pressing%
.
- In Inkscape, press
- Complex or intricate graphic elements should be simplified.
- Background shading should be removed.
- Route numbers should be large enough to be legible.
- Shields should consistently use squared or rounded corners, but not a mix of both. Rounded corners should have a 2px radius.
- To give a rectangle a 2px corner radius, drag the circular handles 2 pixels (4 grid lines) away from the edge, as shown in the following examples:
In general, this style is not trying to exactly replicate highway shields as seen on signage. Instead, we are trying to extract the key stylistic elements so that the graphics are recognizable as simplifications of their real-world counterparts. Here are some examples of Americana's simplified shields for small-size readability:
Network | Real-world Shield | Americana Representation |
---|---|---|
NJ Turnpike | ||
Washington State Route |
More complicated shields may be more challenging to simplify. Consider taking some inspiration from the rebusurance project, which effectivly simplifies a number of complex state shield designs by stretching, compressing, omitting, or simplifying graphic elements.
For consistency, most shields should use the following color palette, which is based on the national Manual of Uniform Traffic Control Devices:1
Color | Pantone | RGB | Hex triplet |
---|---|---|---|
|
294 | 0 63 135 | #003f87 |
|
469 | 105 63 35 | #693f23 |
|
342 | 0 103 71 | #006747 |
|
152 | 243 143 0 | #f38f00 |
|
198 | 223 70 97 | #df4661 |
|
259 | 109 32 119 | #6d2077 |
|
187 | 191 32 51 | #bf2033 |
|
116 | 255 205 0 | #ffcd00 |
|
382 | 196 214 0 | #c4d600 |
|
N/A | 255 255 255 | #ffffff |
|
N/A | 0 0 0 | #000000 |
The MUTCD’s standard colors are designed for high-contrast backgrounds and legends. This is also advantageous on a map where shields need to stand out a variety of lines and fills. However, tourist and scenic route shield often depict natural scenes in a photorealistic style, requiring some tints that stand out against the usual background shades. These shields can take advantage of additional colors for contrast and recognizability, including:2
Color and example usage | Pantone | RGB | Hex triplet |
---|---|---|---|
|
468 | 221 203 164 | #ddcba4 |
|
291 | 155 203 235 | #9bcbeb |
|
360 | 108 194 74 | #6cc24a |
See the developer tools for an importable, Inkscape-compatible palette file.
There is a utility script called icon_grid that will generate a pixel grid on an SVG. This can be used to check how well the icon will align to the pixel grid. Run this utility as follows:
npm run icon_grid -- icons/poi_fuel.svg
Shields should target 8-14px text actual-size character heights for readability:
Example | Text height |
---|---|
16px | |
14px | |
12px | |
10px | |
8px | |
6px |
It is not possible to use font sizes greater than 14px in shields.
The loadShields
function in js/shield_defs.js contains a definition object for each shield displayed on the map. A definition object can contain the following properties:
spriteBlank
– A reference to the image file used as the shield background, based on the name of the file in icons/. To use a different image depending on the length of the inscribed text, specify an array of images.colorLighten
– Replace the black portions of the specified background image with this color via a "lighten" operation.colorDarken
– Replace the white portions of the specified background image with this color via a "darken" operation.numberingSystem
– If the shield should express the route number in Roman numerals for stylistic reasons, even though the same route number is normally expressed in (Western) Arabic numerals in other contexts, set this property toroman
to automatically convert theref
to Roman numerals.noref
– An alternate shield definition to use when there is noref
. This is appropriate if some routes in the network have aref
tag and others do not, and the routes with no ref need a special shield.notext
– By default, a relation missing aref
tag will not appear as a shield. Set this property totrue
to display a shield even if it has noref
. This is appropriate for one-off shield networks, which are common for toll roads and touristic routes.padding
– An object that specifies the amount of padding on each side of the inscribed text relative to the background image.textColor
– The color of the inscribed text to superimpose on the background.textHaloColor
– The color of the halo surrounding the inscribed text.textLayoutConstraint
– A strategy for constraining the text within the background image, useful for shields of certain shapes. By default, the text will expand to fill a rectangle bounded by the specified padding while maintaining the same aspect ratio.verticalReflect
– Set this property totrue
to draw the shield image upside-down.
In addition to textHaloColor
, the config variable SHIELD_TEXT_HALO_COLOR_OVERRIDE
can be used to override the text halo color on all shields. This can be helpful to avoid collisions with other design features when determining padding values. For example, set SHIELD_TEXT_HALO_COLOR_OVERRIDE
in src/config.js to "magenta"
to display a magenta halo around all shield text.
If special code is necessary to style a route with a specific ref
or name
in a particular network, overrideByRef
or overrideByName
can be used to define and override any of the above properties. overrideByRef
is an object mapping ref
values to partial shield definition objects, containing whichever properties are to be overridden for that particular ref
value. overrideByName
does the same for name
values. If necessary, these parameters can be used to override the entire shield definition.
Additionally, refsByName
is an object mapping way names to text that can be superimposed on the background as a fallback for a missing ref
value. (refsByName
implies notext
.) This temporary fallback is designed for use in limited situations. In the future, it is expected that these initialisms will be encoded on the server side by processing appropriate tagging which holds the initialism in the database.
refsByName
only works if there is no ref
tag and the expression in the routeConcurrency
function in layer/highway_shield.js includes the name
property in the image name. The network needs to be listed as an input value that causes the match
expression to append name
to the image name.
When using overrideByRef
or refsByName
, make sure to add a line to the Special Cases section of this page explaining why it is necessary, as they are only intended for use in special cases.
In the case where all routes in a network should be drawn with the same shield text, set the text value in ref
.
The shield definition supports a property banners
which accepts an array of text strings which will be drawn atop each shield, in 10px height increments. This is used in cases where additional text is needed to differentiate shields with a common symbology, for example for special routes of the US Numbered Highway System:
Banners should be specified in the following cases:
- When a route represents a variant of a main route with which it shares a common shield design. The banner ensures that the variant route information, which is an important component of the route, is visually displayed.
- When two or more routes from different networks share a common symbology in the map within a common geographical area. Shields which are very similar may be drawn using common graphics for simplicity and readability, for example, when the networks differ only by a difference in text. In these cases, the most significant network should be drawn with no banner, and each of the less significant networks should be drawn with a banner.
- When a short text of up to 4 characters is a significant stylistic element of a shield that can't reasonably be incorporated into the main shield graphic for aesthetic reasons.
In all cases, banner text should be no more than 4 characters in length.
This style strives to draw representative highway shields wherever they are tagged on road route relations consistently with international norms. This style operates on the expectation that the network
value on a route relation corresponds to the shield design that will be drawn, and the ref
value will contain the text which is drawn on the shield. In order to give appropriate mapper feedback, this style will add support for special cases only when the complexity of the route network and shield styling cannot be adequately expressed via network
and ref
alone. These special cases should be exceptionally rare and documented in the list below. PRs to add special case code should also add an entry below justifying its inclusion. For all other network
and ref
combinations, the style will draw a "generic" shield displaying the ref
value.
- Shields of individual routes that have unique design elements while sharing an overall theme. Such cases include:
- Great Lakes Circle Tour. Each shield shows a ribbon encircling another graphic representing one of the Great Lakes.
- Shields of individual routes having a special color scheme (and possibly additional artwork or text omitted for the purposes of this project), but otherwise matching the shape of shields for the rest of the network. Such cases include:
- Arkansas Highway 980. Highway 980 is a designation applied to various short state highways leading to airports. It has a unique shield based on the state route shield, with a white-on-blue color scheme and additional artwork.
- Georgia State Routes 515 and 520. Highway shields for Georgia State Routes 515 and 520 are colored in blue and green respectively, rather than the usual black, for their entire length. This is done because these roads are part of the Governor's Road Improvement Program (GRIP).
- Michigan Highway M-185. M-185 has a special shield based on the State Trunkline Highway shield, with a white-on-brown color scheme and additional text.
- Ontario's Queen Elizabeth Way. The Queen Elizabeth Way has a special shield based on the King's Highway shield, with a blue-on-yellow color scheme.
- Yukon Routes. The majority of Yukon Route shields are red, but certain numbered highways have yellow, blue or green shields for their entire length. All shields have a simple square shape.
- Shields for route networks where the full name of the route is displayed unabbreviated in real life, but abbreviated for the purposes of this project. Such cases include:
- Houston, TX toll roads. Harris and Fort Bend Counties each sign a network of toll roads which use a common shield styling, but with full-text names of the highways on the shields. Because these counties' toll road systems are clearly common networks due to their common shield symbology, special code is needed to convert toll road names to their locally-expected initialisms. Because the initialisms are not present on shields, it would not be appropriate to encode this data in the
ref
tag. - Kentucky Parkways. Kentucky signs a network of state highways which use a common shield styling, but with full-text names of the parkways on the shields. In addition, these routes are locally known by initialisms. Because these parkways are clearly a common network due to their common shield symbology, special code is needed to convert parkway names to their locally-expected initialisms. Because the initialisms are not present on shields, it would not be appropriate to encode this data in the
ref
tag. - New York Parkways. The State of New York signs a network of highways which use a common shield styling, but with full-text names of the parkways on the shields. The first letter of each word in a parkway's name is capitalized and in a larger font, making initialisms easily recognizable. Because these parkways are clearly a common network due to their common shield symbology, special code is needed to convert parkway names to their initialisms. Because the initialisms are present on shields, but only as part of the full name, it would not be appropriate to encode this data in the
ref
tag. - Connecticut Parkways. Connecticut has several state-designated parkways that share the
network=US:CT:Parkway
tag but have no parkway-specificref
tags. The Merritt Parkway is the only of these to be signed with a route shield. Special code is needed to differentiate the Merritt from the state's other parkways. - New Hampshire Turnpikes. New Hampshire has three named turnpikes without unique
ref=
values. One turnpike is unsigned, while the other two use a shield with the full name of the turnpike and a color for each turnpike.
- Houston, TX toll roads. Harris and Fort Bend Counties each sign a network of toll roads which use a common shield styling, but with full-text names of the highways on the shields. Because these counties' toll road systems are clearly common networks due to their common shield symbology, special code is needed to convert toll road names to their locally-expected initialisms. Because the initialisms are not present on shields, it would not be appropriate to encode this data in the
- Shields for route networks where each individual route is identified by a color, rather than a number or letter. Such cases include:
- Allegheny County, PA Belt Routes. Shields for this system use colors, with a colored circle and the words " BELT". These shields are drawn as squares with colored circles, with the
ref
values correctly corresponding to the text on the shield. Because of the common design (white shield with colored circle), these shields are properly part of a common route network. Special code is needed to convert the textual ref values to the colors displayed in the shield. - Branson, MO color-coded routes. Shields for this system use colors, with a colored rectangle and the words " ROUTE". These shields are drawn as squares with colored rectangles, with the
ref
values correctly corresponding to the text on the shield. Because of the common design (green shield with colored rectangle), these shields are properly part of a common route network. Special code is needed to convert the textual ref values to the colors displayed in the shield.
- Allegheny County, PA Belt Routes. Shields for this system use colors, with a colored circle and the words " BELT". These shields are drawn as squares with colored circles, with the
- Shields with a stacked ref configuration, with
/
separating the two lines of text in theref
value. Currently, theseref
values are displayed verbatim on one line, and the code necessary for stacked ref rendering has not been written yet (#366). Such cases include:- Italy "Diramazione" (branch) motorways. Between their main autostrade "A" roads, the Italian motorway network has branch motorways which carry the name of both highways that they connect. For example, the A7 and A26 motorways have a branch motorway named A7/A26, which is correctly tagged
ref=A7/A26
and shown on shields with the two numbers stacked vertically. - West Virginia County Routes. The West Virginia Department of Transportation posts County Routes, which can have shields with two stacked numbers. For example, in Mercer County, County Route 460/1 is a branch off U.S. Route 460, and County Route 27/6 is a branch off County Route 27. These routes are correctly tagged
ref=460/1
andref=27/6
respectively, and shown on shields with the two numbers stacked vertically.
- Italy "Diramazione" (branch) motorways. Between their main autostrade "A" roads, the Italian motorway network has branch motorways which carry the name of both highways that they connect. For example, the A7 and A26 motorways have a branch motorway named A7/A26, which is correctly tagged
- The highway classification system of the United Kingdom. In the UK, mappers need to and are able to tag the actual official road classifications independently of route networks. The color and style of route signage is based on a strict 1:1 correspondence with the
highway=*
value of the underlying road, and not based on M/A/B highway network type. While "M" roads are always motorways with blue route symbology, "A" roads can anything from primary through motorway, and thus may take one of three colors and may change along a single route. Even if mappers were to create route relations containing all roads with the same route number, these relations would not be usable for determining how to render route symbology. Additionally, there are no route concurrencies in the UK; all roads that arehighway=secondary
or higher carry a singleref
value that can be directly rendered into a shield without pre-processing. There is established data consumers support for this highway classification-based symbology system, most notably OpenMapTiles, which has provided pseudo-network values for UK routes since the project's inception. Therefore, this project consumes the UK pseudo-network scheme established by OpenMapTiles and colors UK route network symbology strictly based onhighway=<motorway/trunk/primary/secondary>
consistent with UK signage.
For testing out changes across a variety of different shield designs and ref lengths there is a shield test gallery available:
- In local development: http://localhost:1776/shieldtest.html
- On the public demo site: https://americanamap.org/shieldtest.html
This aims to display a table of all the unique shield designs in the style with some example refs from 1 to 6 characters. The networks
and refs
arrays can be modified for testing with a different set of either:
openstreetmap-americana/src/shieldtest.js
Lines 16 to 31 in 581e1e5
openstreetmap-americana/src/shieldtest.js
Lines 203 to 218 in 581e1e5
To test with a list of all the supported networks in the style this line can be uncommented:
openstreetmap-americana/src/shieldtest.js
Lines 200 to 201 in 581e1e5
This results in a very long page and can be quite slow or even crash the browser tab.
A "point of interest" or POI is any feature on the map represented by an icon on the map. To add a new POI:
- Identify the
subclass
of the POI you are adding from the OpenMapTiles schema. - Place the icon file under /icons using the
poi_
prefix. Icons should have a black fill and may have a 1px white halo. - In poi.js, add an entry to
iconDefs
with thesubclass
, sprite name, color category (see below), and legend description. Also update thepaint
andfilter
statements with the newsubclass
.
POIs are broken down into the following broad categories, in order to constrain the number of colors shown on the map. Some features may not cleanly fit into one category or another. Contributors should consider other POIs in the category to determine which category is the best fit.
- Geographic Place Names: labels associated with
place=
tags, for countries, cities, locations, etc. - Infrastructure: features associated with public infrastructure, health, safety, or government.
- Consumer: businesses that provide services to the public, such as shops and restaurants.
- Outdoor: parks, nature reserves, and other outdoorsy features.
- Attraction: places where people go for entertainment, leisure, or curiosity.
- Transport: places where people can access forms of transportation, such as airports, train stations, bus stops, and other public transit.
For consistency, POI icons use the following color palette:
Category | Scheme | Color | RGB | Hex triplet |
---|---|---|---|---|
Geographic Place Names | N/A |
|
0 0 0 | #000000 |
Infrastructure | Pantone 294 |
|
0 63 135 | #003f87 |
Consumer | UTexas Orange |
|
191 87 0 | #bf5700 |
Outdoor | TBD (green?) | |||
Attraction | Pantone 469 |
|
105 63 35 | #693f23 |
Airport | Medium Purple C |
|
78 0 142 | #4e008e |
Transport | Pantone 234 C |
|
162 0 103 | #a20067 |
Knockout |
|
249 245 240 | #f9f5f0 |
Fonts for style labels are packaged and defined in fontstack66, Americana's font package.
A GitHub action will check a list of regression test locations to see if the map has changed. If any of those locations have changed visually, the "Map Preview" check will generate before and after images. If your PR changes the visual appearance of the map, add an entry to test/sample_locations.json
with a location that best illustrates the change. This will help show your change to PR reviewers as well as act as a regression test for future PRs.
Footnotes
-
MUTCD Color Specifications, Federal Highway Administration ↩
-
California Sign Specification Drawings, California Department of Transportation ↩