diff --git a/scripts/taginfo_template.json b/scripts/taginfo_template.json index d0363474c..824666cfb 100644 --- a/scripts/taginfo_template.json +++ b/scripts/taginfo_template.json @@ -553,6 +553,20 @@ "object_types": ["way"], "description": "🇮🇪 Roads belonging to non-primary routes are marked by a color-coded patch containing the ref=* tag.", "doc_url": "https://openmaptiles.org/schema/#network" + }, + { + "key": "highway", + "value": "busway", + "object_types": ["way"], + "description": "Busways are styled with a purple solid line.", + "doc_url": "https://openmaptiles.org/schema/#network" + }, + { + "key": "highway", + "value": "bus_guideway", + "object_types": ["way"], + "description": "Bus guideways are styled with a purple solid line.", + "doc_url": "https://openmaptiles.org/schema/#network" } ] } diff --git a/src/layer/index.js b/src/layer/index.js index 106f5d18d..0aa3d8ecd 100644 --- a/src/layer/index.js +++ b/src/layer/index.js @@ -111,6 +111,7 @@ export function build(locales) { lyrRoad.minor.fill(), lyrRoad.minorToll.fill(), + lyrRoad.busway.fill(), lyrRoad.tertiary.fill(), lyrRoad.tertiaryToll.fill(), lyrRoad.secondary.fill(), @@ -170,6 +171,7 @@ export function build(locales) { lyrRoad.minorBridge.fill(), lyrRoad.minorTollBridge.fill(), + lyrRoad.buswayBridge.fill(), lyrRoad.tertiaryBridge.fill(), lyrRoad.tertiaryTollBridge.fill(), lyrRoad.secondaryBridge.fill(), diff --git a/src/layer/road.js b/src/layer/road.js index 2902bde9f..5e98b1be8 100644 --- a/src/layer/road.js +++ b/src/layer/road.js @@ -19,6 +19,7 @@ const roadExp = 1.2; const roadHue = 0; const tollRoadHue = 48; +const buswayHue = 322; //Tunnel casing dash pattern const tunDashArray = [ @@ -80,7 +81,15 @@ const opacity = [ minZoomTertiary, [ ...classSelector, - ["motorway", "trunk", "primary", "secondary", "tertiary"], + [ + "motorway", + "trunk", + "primary", + "secondary", + "tertiary", + "busway", + "bus_guideway", + ], 1, 0, ], @@ -122,6 +131,8 @@ function filterRoad(brunnel, constraints) { "primary", "secondary", "tertiary", + "busway", + "bus_guideway", "minor", "service", ], @@ -179,7 +190,7 @@ const widthFactor = [ [...linkSelector, 0.45, 0.9], "secondary", [...linkSelector, 0.3, [...expresswaySelector, 0.7, 0.6]], - "tertiary", + ["tertiary", "busway", "bus_guideway"], [...linkSelector, 0.25, 0.5], "minor", 0.3, @@ -238,7 +249,7 @@ const roadCasingColorTunnel = [ ], `hsl(${roadHue}, 41%, 80%)`, ], - ["primary", "secondary", "tertiary"], + ["primary", "secondary", "tertiary", "busway", "bus_guideway"], "hsl(0, 0%, 80%)", "hsl(0, 0%, 90%)", ], @@ -286,6 +297,8 @@ const roadFillColorTunnel = [ `hsl(${tollRoadHue}, 77%, 90%)`, `hsl(${roadHue}, 77%, 90%)`, ], + ["busway", "bus_guideway"], + `hsl(${buswayHue}, 25%, 93%)`, [ ...tollSelector, `hsl(${tollRoadHue}, 100%, 95%)`, @@ -524,7 +537,14 @@ class RoadSimpleFill extends Road { ["all", ["==", getClass, "trunk"], isNotLink], [ "all", - ["in", getClass, ["literal", ["primary", "secondary", "tertiary"]]], + [ + "in", + getClass, + [ + "literal", + ["primary", "secondary", "tertiary", "busway", "bus_guideway"], + ], + ], isExpressway, ], ]; @@ -867,6 +887,35 @@ class TertiaryExpressway extends Tertiary { } } +class Busway extends Tertiary { + constructor() { + super(); + this.constraints = [ + "in", + getClass, + ["literal", ["busway", "bus_guideway"]], + ]; + + this.minZoomFill = minZoomTertiary; + this.minZoomCasing = minZoomTertiary; + + this.fillColor = [ + "interpolate", + ["exponential", roadExp], + ["zoom"], + this.minZoomFill, + `hsl(${buswayHue}, 25%, 75%)`, + this.minZoomFill + 2, + `hsl(${buswayHue}, 25%, 50%)`, + 14.9999, + `hsl(${buswayHue}, 25%, 50%)`, + 15, + `hsl(${buswayHue}, 25%, 80%)`, + ]; + this.surfaceColor = `hsl(${this.hue}, 0%, 80%)`; + } +} + class Minor extends Road { constructor() { super(); @@ -1048,6 +1097,14 @@ class TertiaryExpresswayBridge extends TertiaryExpressway { } } +class BuswayBridge extends Busway { + constructor() { + //undifferentiated + super(); + this.brunnel = "bridge"; + } +} + class MinorBridge extends Minor { constructor() { //undifferentiated @@ -1153,6 +1210,7 @@ export const secondaryExpressway = new SecondaryExpressway(); export const tertiary = new Tertiary(); export const tertiaryToll = new TertiaryToll(); export const tertiaryExpressway = new TertiaryExpressway(); +export const busway = new Busway(); export const minor = new Minor(); export const minorToll = new MinorToll(); @@ -1167,6 +1225,7 @@ export const secondaryExpresswayBridge = new SecondaryExpresswayBridge(); export const tertiaryBridge = new TertiaryBridge(); export const tertiaryTollBridge = new TertiaryTollBridge(); export const tertiaryExpresswayBridge = new TertiaryExpresswayBridge(); +export const buswayBridge = new BuswayBridge(); export const minorBridge = new MinorBridge(); export const minorTollBridge = new MinorTollBridge(); @@ -1265,6 +1324,11 @@ export const legendEntries = [ ], filter: isToll, }, + { + description: "Busway", + layers: [busway.fill().id, roadSimpleCasing.casing().id], + filter: ["==", getClass, "busway"], + }, { description: "Unpaved road", layers: [ diff --git a/src/layer/road_label.js b/src/layer/road_label.js new file mode 100644 index 000000000..332d88ebe --- /dev/null +++ b/src/layer/road_label.js @@ -0,0 +1,164 @@ +"use strict"; + +import * as Color from "../constants/color.js"; + +const textLayout = { + "text-font": ["Metropolis Light"], + "text-field": "{name:latin} {name:nonlatin}", + "text-max-angle": 20, + "symbol-placement": "line", +}; + +/** + * Returns layout properties that differ between an offset treatment at lower + * zoom levels versus an in-road treatment at higher zoom levels. + * + * @param {*} minHighZoom Lowest zoom level at which to apply the in-road + * treatment. Omit this parameter to always apply the offset treatment and + * never the in-road treatment. + */ +function zoomDependentLayout(minHighZoom) { + return { + "text-size": + typeof minHighZoom === "undefined" + ? 12 + : ["step", ["zoom"], 12, minHighZoom, 10], + "text-anchor": + typeof minHighZoom === "undefined" + ? "bottom" + : ["step", ["zoom"], "bottom", minHighZoom, "center"], + }; +} + +const textPaint = { + "text-color": "#333", + "text-halo-color": Color.backgroundFill, + "text-halo-blur": 0.5, + "text-halo-width": 2, +}; + +export const motorway = { + id: "motorway_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "motorway"]], + layout: Object.assign(zoomDependentLayout(), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const trunk = { + id: "trunk_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "trunk"]], + minzoom: 10, + layout: Object.assign(zoomDependentLayout(), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const primary = { + id: "primary_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "primary"]], + minzoom: 11, + layout: Object.assign(zoomDependentLayout(16), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const secondary = { + id: "secondary_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "secondary"]], + minzoom: 12, + layout: Object.assign(zoomDependentLayout(16), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const tertiary = { + id: "tertiary_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "tertiary"]], + minzoom: 13, + layout: Object.assign(zoomDependentLayout(17), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const busway = { + id: "busway_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "busway"]], + minzoom: 13, + layout: Object.assign(zoomDependentLayout(17), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const minor = { + id: "minor_label", + type: "symbol", + paint: textPaint, + filter: ["all", ["==", "class", "minor"]], + minzoom: 13, + layout: Object.assign(zoomDependentLayout(17), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const service = { + id: "service_label", + type: "symbol", + paint: textPaint, + filter: [ + "all", + ["==", "class", "service"], + ["!in", "service", "parking_aisle", "driveway"], + ], + minzoom: 14, + layout: Object.assign(zoomDependentLayout(17), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +export const smallService = { + id: "small_service_label", + type: "symbol", + paint: textPaint, + filter: [ + "all", + ["==", "class", "service"], + ["in", "service", "parking_aisle", "driveway"], + ], + minzoom: 15, + layout: Object.assign(zoomDependentLayout(), textLayout), + source: "openmaptiles", + "source-layer": "transportation_name", +}; + +// A spacer label on each bridge to push any waterway label away from the bridge. +// https://github.com/ZeLonewolf/openstreetmap-americana/issues/198 +export const bridgeSpacer = { + id: "bridge_spacer", + type: "symbol", + source: "openmaptiles", + "source-layer": "transportation", + filter: ["all", ["==", "brunnel", "bridge"], ["in", "$type", "LineString"]], + paint: { + "icon-opacity": 0, + }, + layout: { + "symbol-placement": "line", + "symbol-spacing": 2, + "icon-image": "dot_city", + "icon-allow-overlap": true, + "icon-size": 0.1, + }, +}; diff --git a/src/layer/transportation_label.js b/src/layer/transportation_label.js index ed3328475..5ea963582 100644 --- a/src/layer/transportation_label.js +++ b/src/layer/transportation_label.js @@ -8,7 +8,7 @@ const classSelector = ["match", ["get", "class"]]; const motorwayToTrunk = ["motorway", "trunk"]; const motorwayToPrimary = [...motorwayToTrunk, "primary"]; const motorwayToSecondary = [...motorwayToPrimary, "secondary"]; -const motorwayToMinor = [...motorwayToSecondary, "tertiary", "minor"]; +const motorwayToMinor = [...motorwayToSecondary, "tertiary", "minor", "busway"]; const motorwayToService = [...motorwayToMinor, "service"]; const majorConstruction = ["motorway_construction", "trunk_construction"]; @@ -145,7 +145,6 @@ export const label = { ], ], "symbol-sort-key": [ - // TODO busway ...classSelector, "aerialway", 0, @@ -157,7 +156,7 @@ export const label = { 3, "secondary", 4, - ["tertiary", "minor"], + ["tertiary", "minor", "busway"], 5, 6, ],