Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
@americana/maplibre-shield-generator
Advanced tools
Generate highway shields for maplibre-gl-js maps
The Americana shield renderer is a library intended to draw highway shields on a maplibre-gl-js vector-tiled map.
Rendering shields requires the following compoments:
Encode shield information in vector tiles. First, your tiles must contain the information which tells the shield renderer what shields to draw. In OpenMapTiles, shield information is encoded in the transportation_name
vector tile layer with a series of attributes named route_1
, route_2
, etc. Each attribute contains a text string which contains all of the information needed to determine which graphic to display, including numeric route number if the shield is numbered. However, this library allows you to specify how the shield information has been encoded, and it's possible to stitch together data from multiple fields when encoding shield data.
Expose shield information in a style layer. Next, route information must be exposed in a maplibre expression using image in a structured string containing the route information. For example, you might encode Interstate 95 as an image named shield|US:I=95
. Normally, the image expression is used to point to pre-designated sprites in a sprite sheet, but in this case, we're pointing to a sprite which doesn't exist called shield|US:I=95
. This will trigger a styleimagemissing
event which allows the shield renderer to create the required graphic on the fly. As an example of how to encode shield information, see OSM Americana's highway_shield
style layer.
Create a callback that defines how route information is encoded. There are three parts to a route definition:
network
string, which defines a network with a common shield shape, graphic, and colorref
string, which defines a text sequence that should be drawn on top of the shield graphicname
string, which defines a name, separate from the ref, that is used to determine which graphic to drawlet routeExtractor = (id) => {
//format is `shield|${network}=${ref}|${name}`
let id_parts = id.split("|");
let network_ref = id_parts[1].split("=");
return {
network: network_ref[0],
ref: network_ref[1],
name: id_parts[2],
};
};
shield|
, this would look like:let shieldPredicate = (imageID) => imageID.startsWith("shield");
This step can be skipped if all unhandled image IDs are shields.
Additionally, you can specify which networks will be handled. The example below ignores all nwn, lwn, ncn, etc network values:
let networkPredicate = (network: string) => !/^[lrni][chimpw]n$/.test(network);
Create shield definitions and artwork. The shield definition is expressed as a JSON file along with a set of sprites containing any raster artwork used for the shields. It can be generated as an object or hosted as a JSON file accessible by URL. See the next section for how to create this definition.
Hook up the shield generator to a maplibre-gl-js map. Pass either the URL of the JSON shield definition or create an object in javascript code. There are two separate classes for each approach.
new URLShieldRenderer("shields.json", routeExtractor)
.filterImageID(shieldPredicate)
.filterNetwork(networkPredicate)
.renderOn(map);
new ShieldRenderer(shields, routeExtractor)
.filterImageID(shieldPredicate)
.filterNetwork(networkPredicate)
.renderOn(map);
The purpose of the shield definition is to define which graphics and text to draw for each network/ref/name combination that you wish to display. This can be created in javascript as an object, or as an HTTP-accessible JSON file.
This description uses the following conventions:
The structure is as follows:
{
"options": {
"bannerTextColor": "black",
"bannerTextHaloColor": "white",
"shieldFont": "sans-serif-condensed, 'Arial Narrow', sans-serif"
},
"default": { ...definiton },
"network_1": { ...definiton },
"network_2": { ...definiton },
"network_2": { ...definiton }
}
The options block contains global parameters that apply across all shield drawing:
bannerTextColor
: color to draw text banners above the shieldbannerTextHaloColor
: color to draw an outline around the text bannershieldFont
: font to use for shield text and bannersYou should create one definition entry for each network. The entry key must match the encoded network
value exactly. The "default" network defines what should be drawn if there's no definition for a particular network. A network definiton can contain any combination of the following parameters:
{
"textColor": "black",
"textHaloColor": "white",
"padding": {
"left": 3,
"right": 3,
"top": 3,
"bottom": 3
},
"spriteBlank": "name_of_image_1",
"noref": {
"spriteBlank": "name_of_image_2"
}
"shapeBlank": {
"drawFunc": "pentagon",
"params": {
"pointUp": false,
"offset": 5,
"angle": 0,
"fillColor": "white",
"strokeColor": "black",
"radius1": 2,
"radius2": 2
}
},
"modifiers": ["ALT"],
"textLayout": {
"constraintFunc": "roundedRect",
"options": {
"radius": 2
}
},
"colorLighten": "#006747",
"overrideByRef": {
"REF": {
"spriteBlank": "special_case_image",
"textColor": "#003f87",
"colorLighten": "#003f87"
}
},
"refsByName": {
"Audubon Parkway": "AU"
},
"overrideByName": {
"Merritt Parkway": {
"spriteBlank": "shield_us_ct_parkway_merritt"
}
}
}
textColor
: determines what color to draw the ref
on the shield.textHaloColor
: color to draw a knockout halo around the ref
text.padding
: padding around the ref
, which allows you to squeeze the text into a smaller space within the shield.spriteBlank
: specify the name of an image in the sprite sheet to use as the shield background. This can either be a single string or an array of strings if there are multiple options for different width. If it's an array of strings, they must be ordered from narrowest to widest, and the engine will choose the narrowest shield graphic that fits the text at a reasonable size.noref
: specify alternate attributes to apply in the event that no ref
is supplied. This allows you to use one graphic for numbered routes and a separate unitary graphic for non-numbered routes within the same network. Supports spriteBlank
, colorLighten
, and colorDarken
.shapeBlank
: specify that a shield should be drawn as a common shape (rectangle, ellipse, pentagon, etc), with colors and dimensions as specified. See the drawn shield shapes section for available drawing options.modifiers
: specify that one or more short text strings (up to 4 characters) should be drawn above the shield. This is specified as an array, and text will be drawn in order from top to bottom.textLayout
: specify how text should be inscribed within the padded bounds of the shield. The text will be drawn at the maximum size allowed by this constraint. See the text layout functions section for text layout options.colorLighten
: specify that the shield artwork should be lightened (multiplied) by the specified color. This means that black areas will be recolor with this color and white areas will remain the same. Alpha values will remain unmodified.colorDarken
: specify that the shield artwork should be darkened by the specified color. This means that white areas will be recolor with this color and black areas will remain the same. Alpha values will remain unmodified.overrideByRef
: specify that a specific ref
within a network
should have different shield properties than other routes in the network, with one entry per special-case ref
. Supported options are spriteBlank
, textColor
, and colorLighten
.refsByName
: specify that a name
with the specified key should be treated as a ref
with the specified value.overrideByName
: specify that particular name
should use a specific spriteBlank
which differs from the rest of the network.The shield specification allows for the handling of special cases. For example, in OSM Americana, we wanted to create special shields for the Kentucky Parkway System. This network used a particularly ugly set of shields that looked something like this:
The Americana team wanted to draw a series of shields that used two-letter codes to represent each of the Parkways, so that it would look like this:
However, these two-letter codes weren't actually used as route numbers on shields, so it wasn't appropriate to add them to the ref=*
tag in OpenStreetMap. Instead, the team used the refsByName
property, and then defined what two-letter code is assigned to each named route network as follows:
"US:KY:Parkway": {
"spriteBlank":"shield_us_ky_parkway",
"textColor":"#003f87",
"padding": {
"left":2,
"right":2,
"top":2,
"bottom":6
},
"refsByName": {
"Audubon Parkway":"AU",
"Bluegrass Parkway":"BG",
"Bluegrass Pkwy":"BG",
"Cumberland Parkway":"LN",
"Cumberland Pkwy":"LN",
"Hal Rogers Parkway":"HR",
"Hal Rogers Pkwy":"HR",
"Mountain Parkway":"MP",
"Mountain Pkwy":"MP",
"Purchase Parkway":"JC",
"Purchase Pkwy":"JC",
"Western Kentucky Parkway":"WK",
"Western Kentucky Pkwy":"WK"
}
},
Another special case is when select routes within a network need to be styled differently. For example, Georgia State Route 520 is signed with a green-colored shield, while the default color for Georgia state highways is black. The shield assembly below shows an intersection and concurrency with both styles of Georgia state route:
This effect can be achieved by overriding the text and sprite color in the route definition as follows. For multiple special case refs, add multiple entries.
"overrideByRef": {
"520": {
"textColor": "#006747",
"colorLighten": "#006747",
}
}
Text is laid out on shields in accordance with the specified textLayout
value. The text will be drawn, measured, and expanded until it hits the edge of a text layout constraint. For example, an ellipse
constraint would fill a padded shield like this, with the text drawn from the center and expanding until it reaches the ellipse:
Not all constraints are center-specified. For example, the southHalfEllipse
constraint would grow from the top of the shield as follows:
The supported text constraints are:
ellipse
rect
roundedRect
southHalfEllipse
If shapeBlank
is specified, the shield will be drawn as a shape. This needs to be specified with a drawing function, drawFunc
and a params
block the describes how the shape will be drawn. The draw functions are as follows:
drawFunc | |
---|---|
diamond | |
ellipse | |
escutcheon | |
fishhead | |
hexagonVertical | |
hexagonHorizontal | |
octagonVertical | |
pentagon | |
roundedRectangle | |
trapezoid | |
triangle |
The following params
options can be specified:
angle
- applies to several shape types, indicates the key angle in degrees.fill
- specifies the internal fill color.outline
- specifies the outline color.outlineWidth
- specifies the width of the outline.pointUp
- applies to several shape types and specifies whether the pointy side is up.radius
- specifies the rounding radius, in pixels, to use for corners.radius1
- Corner radius of pointed side of pentagon (defaults to 2)radius2
- Corner radius of flat side of pentagon (defaults to 0)shortSideUp
- for trapezoid
only, a boolean which specifies whether the short side is up or down.In addition to the stock drawing functions, a custom draw function can be specified. paDot
and branson
are included as examples of this, for rendering the Allegheny County belt system and the Branson, Missouri colored route system. See the file src/custom_shields.mjs
for an example of how this is done.
FAQs
Generate highway shields for maplibre-gl-js maps
The npm package @americana/maplibre-shield-generator receives a total of 13 weekly downloads. As such, @americana/maplibre-shield-generator popularity was classified as not popular.
We found that @americana/maplibre-shield-generator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.