diff --git a/src/demo/demo_utils.ts b/src/demo/demo_utils.ts new file mode 100644 index 0000000..353d57d --- /dev/null +++ b/src/demo/demo_utils.ts @@ -0,0 +1,20 @@ +export function createRootEl( + width: number = window.innerWidth, + height: number = window.innerHeight, + margin: number = 0 +) { + width -= margin; + height -= margin; + + const div = document.createElement('div'); + + div.id = 'glide-gl'; + div.style.margin = `${margin / 2}px`; + div.style.width = `${width}px`; + div.style.height = `${height}px`; + div.style.position = `relative`; + div.style.overflow = 'hidden'; + document.body.appendChild(div); + + return div; +} diff --git a/src/demo/enabled_features.ts b/src/demo/enabled_features.ts new file mode 100644 index 0000000..6aa2da9 --- /dev/null +++ b/src/demo/enabled_features.ts @@ -0,0 +1,10 @@ +import { MapFeatureFlags } from '../map/flags'; +import { FontFormatType } from '../map/font/font_config'; + +export const ENABLED_FEATURE_FLAGS: MapFeatureFlags = { + debugLayer: false, + webglRendererDebug: false, + webglRendererUseShaderLines: true, + webglRendererFontFormatType: FontFormatType.texture, + enableObjectSelection: false, +}; diff --git a/src/demo/map_demo.ts b/src/demo/map_demo.ts index cf63e34..e20e200 100644 --- a/src/demo/map_demo.ts +++ b/src/demo/map_demo.ts @@ -9,35 +9,12 @@ import { BingImageTyleStyles, } from './map_styles'; import { MapTileRendererType } from '../map/renderer/renderer'; -import { FontFormatType } from '../map/font/font_config'; +import { createRootEl } from './demo_utils'; +import { ENABLED_FEATURE_FLAGS } from './enabled_features'; -const MAP_LOCATION_PARAM_NAME = 'l'; - -function createRootEl() { - const margin = 0; - const width = window.innerWidth - margin * 2 - 2; - const height = window.innerHeight - margin * 2 - 2; - - const div = document.createElement('div'); - - div.id = 'glide-gl'; - div.style.margin = `${margin}px`; - div.style.width = `${width}px`; - div.style.height = `${height}px`; - div.style.position = `relative`; - div.style.overflow = 'hidden'; - document.body.appendChild(div); - - window.addEventListener('resize', () => { - const width = window.innerWidth - margin * 2 - 2; - const height = window.innerHeight - margin * 2 - 2; - - div.style.width = `${width}px`; - div.style.height = `${height}px`; - }); +const MAP_ROOT_EL_MARGIN = 10; - return div; -} +const MAP_LOCATION_PARAM_NAME = 'l'; const getSafelocation = (zoom: number, lat: number, lng: number) => { return `${Number(zoom).toFixed(4)}/${Number(lat).toFixed(4)}/${Number(lng).toFixed(4)}`; @@ -88,7 +65,7 @@ function fireMapEvent(eventType: MapEventType) { let currentMap: GlideMap | undefined; export function renderMap() { - const rootDiv = createRootEl(); + const rootDiv = createRootEl(window.innerWidth, window.innerHeight, MAP_ROOT_EL_MARGIN); document.body.appendChild(rootDiv); const [zoom, lat, lng] = getStartMapLocation(); @@ -98,7 +75,7 @@ export function renderMap() { zoom, center: [lat, lng], rendrer: MapTileRendererType.webgl2, - tileStyles: SateliteTilesStyles, + tileStyles: MapboxVectorTileStyles, projection: 'mercator', controls: { compas: true, @@ -138,12 +115,17 @@ export function renderMap() { ], }, workerPool: 8, - featureFlags: { - debugLayer: true, - webglRendererDebug: false, - webglRendererFontFormatType: FontFormatType.texture, - enableObjectSelection: false, - }, + featureFlags: ENABLED_FEATURE_FLAGS, + }); + + window.addEventListener('resize', () => { + const width = window.innerWidth - MAP_ROOT_EL_MARGIN; + const height = window.innerHeight - MAP_ROOT_EL_MARGIN; + + rootDiv.style.width = `${width}px`; + rootDiv.style.height = `${height}px`; + + currentMap.resize(width, height); }); subscribeOnEvents(currentMap); diff --git a/src/demo/map_styles.ts b/src/demo/map_styles.ts index d9e0991..c25a0a6 100644 --- a/src/demo/map_styles.ts +++ b/src/demo/map_styles.ts @@ -31,7 +31,7 @@ const StyleFonts: { defaultFont: { type: FontFormatType.sdf, name: 'defaultFont', - pixelRatio: 2, + pixelRatio: 1, fontSize: 24, sourceType: FontSourceType.pbf, sourceUrl: @@ -41,6 +41,7 @@ const StyleFonts: { [256, 511], [1024, 1279], [8192, 8447], + // [19968, 20479], // chinese ], }, // roboto: { @@ -517,7 +518,9 @@ export const MapboxVectorTileStyles: DataTileStyles = { type: MapTileFeatureType.line, show: ['$lte', ['$get', 'properties.admin_level'], 7], color: ['$rgba', 120, 123, 140, 1], - width: 2, + width: 4, + borderWidth: 2, + borderColor: ['$rgba', 0, 0, 0, 1], }, maxzoom: 16, minzoom: 0, @@ -538,7 +541,9 @@ export const MapboxVectorTileStyles: DataTileStyles = { ['motorway', ['$rgba', 233, 201, 43, 1]], ['$default', ['$rgba', 215, 218, 226, 1]], ], - width: ['$switch', ['$get', 'properties.class'], ['primary', 4], ['$default', 2]], + width: ['$switch', ['$get', 'properties.class'], ['primary', 12], ['$default', 6]], + borderWidth: 2, + borderColor: ['$rgba', 0, 0, 0, 1], joinStyle: LineJoinStyle.round, }, minzoom: 6, @@ -652,7 +657,7 @@ export const MapboxVectorTileStyles: DataTileStyles = { borderColor: ['$rgba', 255, 255, 255, 1], text: ['$get', 'properties.house_num'], font: 'defaultFont', - fontSize: 14, + fontSize: 12, }, }, structureIcon: { @@ -787,7 +792,7 @@ export const SateliteTilesStyles: DataTileStyles = { color: ['$rgba', 0, 0, 0, 1], borderColor: ['$rgba', 255, 255, 255, 1], text: ['$get', 'properties.name'], - show: ['$lte', ['$get', 'properties.filterrank'], 3], + show: ['$lte', ['$get', 'properties.filterrank'], 0], font: 'defaultFont', fontSize: [ '$switch', @@ -803,6 +808,21 @@ export const SateliteTilesStyles: DataTileStyles = { maxzoom: 16, minzoom: 0, }, + housenum_label: { + source: 'dataSource', + sourceLayer: 'housenum_label', + styleLayerName: 'housenum_labelStyles', + zIndex: 4, + show: true, + feature: { + type: MapTileFeatureType.text, + color: ['$rgba', 0, 0, 0, 1], + borderColor: ['$rgba', 255, 255, 255, 1], + text: ['$get', 'properties.house_num'], + font: 'defaultFont', + fontSize: 12, + }, + }, }, glyphs: { iconsAtlas: { diff --git a/src/demo/mapbox-layers.json b/src/demo/mapbox-layers.json deleted file mode 100644 index 816daa1..0000000 --- a/src/demo/mapbox-layers.json +++ /dev/null @@ -1,477 +0,0 @@ -{ - "attribution": "© Mapbox © OpenStreetMap Improve this map", - "bounds": [ - -180, - -85, - 180, - 85 - ], - "center": [ - 0, - 0, - 0 - ], - "format": "pbf", - "language_options": { - "ar": "Arabic", - "ca": "Catalan", - "cs": "Czech", - "da": "Danish", - "de": "German", - "el": "Greek", - "en": "English", - "es": "Spanish", - "fa": "Farsi", - "fi": "Finnish", - "fr": "French", - "he": "Hebrew", - "hu": "Hungarian", - "id": "Indonesian", - "it": "Italian", - "ja": "Japanese", - "ka": "Georgian", - "ko": "Korean", - "local": "Renderable local language", - "lv": "Latvian", - "ms": "Malay", - "nb": "Norwegian BokmÃ¥l", - "nl": "Dutch", - "no": "Norwegian", - "pl": "Polish", - "pt": "Portuguese", - "ro": "Romanian", - "ru": "Russian", - "sk": "Slovak", - "sl": "Slovenian", - "sr": "Serbian", - "sv": "Swedish", - "th": "Thai", - "tl": "Tagalog", - "tr": "Turkish", - "uk": "Ukrainian", - "vi": "Vietnamese", - "zh-Hans": "Simplified Chinese", - "zh-Hant": "Traditional Chinese" - }, - "mapbox_logo": true, - "maskLevel": 9, - "maxzoom": 16, - "minzoom": 0, - "name": "Mapbox Bathymetry v2 + Mapbox Terrain v2 + Mapbox Streets v8", - "scheme": "xyz", - "tilejson": "2.2.0", - "tiles": [ - "https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2,mapbox.mapbox-bathymetry-v2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA", - "https://b.tiles.mapbox.com/v4/mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2,mapbox.mapbox-bathymetry-v2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA" - ], - "vector_layers": [ - { - "description": "", - "fields": { - "class": "One of: aboriginal_lands, agriculture, airport, cemetery, commercial_area, facility, glacier, grass, hospital, industrial, park, parking, piste, pitch, residential, rock, sand, school, scrub, wood", - "type": "OSM tag, more specific than class" - }, - "id": "landuse", - "minzoom": 5, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "class": "One of: river, canal, stream, stream_intermittent, ditch, drain", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "type": "One of: river, canal, stream, ditch, drain" - }, - "id": "waterway", - "minzoom": 7, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": {}, - "id": "water", - "minzoom": 0, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "ref": "Text. Identifier of the runway or taxiway", - "type": "One of: runway, taxiway, apron, helipad" - }, - "id": "aeroway", - "minzoom": 9, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "class": "One of: cliff, crosswalk, entrance, fence, gate, hedge, land", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "type": "The value of either the 'barrier' or 'man_made' tag from OSM, or for cliffs either cliff or earth_bank." - }, - "id": "structure", - "minzoom": 13, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "extrude": "String. Whether building should be extruded when rendering in 3D. One of: 'true', 'false'", - "height": "Number. Height of building or part of building.", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "min_height": "Number. Height of bottom of building or part of building, if it does not start at ground level.", - "type": "In most cases, values will be that of the primary key from OpenStreetMap tags.", - "underground": "Text. Whether building is underground. One of: 'true', 'false'" - }, - "id": "building", - "minzoom": 12, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "class": "One of: national_park, wetland, wetland_noveg", - "type": "OSM tag, more specific than class" - }, - "id": "landuse_overlay", - "minzoom": 5, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "bike_lane": "Text. Has a value if there is a bike lane that is part of the road itself. This is different from a separated cycle track, which will be shown as its own line. Possible values are 'right', 'left', 'both' (bike lane on right, left, or both sides of the street respectively), 'yes' (bike lane present but location not specified), 'no' (area was surveyed and confirmed to not have a bike lane), and null (presence of bike lane unknown).", - "class": "One of: 'motorway', 'motorway_link', 'trunk', 'primary', 'secondary', 'tertiary', 'trunk_link', 'primary_link', 'secondary_link', 'tertiary_link', 'street', 'street_limited', 'pedestrian', 'construction', 'track', 'service', 'ferry', 'path', 'golf', 'level_crossing', 'turning_circle', 'roundabout', 'mini_roundabout', 'turning_loop', 'traffic_signals'", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "lane_count": "Number. Number of lanes in the road", - "layer": "Number. Specifies z-ordering in the case of overlapping road segments. Common range is -5 to 5. Available from zoom level 13+.", - "len": "Number. Approximate length of the road segment in Mercator meters.", - "name": "Local name of the road", - "name_ar": "Arabic name of the road", - "name_de": "German name of the road", - "name_en": "English name of the road", - "name_es": "Spanish name of the road", - "name_fr": "French name of the road", - "name_it": "Italian name of the road", - "name_ja": "Japanese name of the road", - "name_ko": "Korean name of the road", - "name_pt": "Portuguese name of the road", - "name_ru": "Russian name of the road", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the road", - "name_zh-Hans": "Simplified Chinese name of the road", - "name_zh-Hant": "Traditional Chinese name of the road", - "oneway": "Text. Whether traffic on the road is one-way. One of: 'true', 'false'.", - "ref": "Text. Route number/code of the road.", - "reflen": "Number. How many characters long the ref tag is. Useful for shield styling.", - "shield": "Text. The shield style to use. See the vector tile documentation for a list of possible values.", - "shield_beta": "Text. The shield style to use if it doesn't exist in default shield values.", - "shield_text_color": "Text. The color of the text to use on the highway shield.", - "shield_text_color_beta": "Text. The color of the text to use on the beta highway shield.", - "structure": "Text. One of: 'none', 'bridge', 'tunnel', 'ford'. Available from zoom level 13+.", - "surface": "Whether the road is paved or not (if known). One of: 'paved', 'unpaved'", - "toll": "Whether a road is a toll road or not.", - "type": "In most cases, values will be that of the primary key from OpenStreetMap tags." - }, - "id": "road", - "minzoom": 3, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "admin_level": "Number, 0-2. The administrative level of the boundary", - "disputed": "Disputed boundaries are 'true', all others are 'false'.", - "iso_3166_1": "The ISO 3166-1 alpha-2 code(s) of the state(s) a boundary is part of. Format: 'AA' or 'AA-BB'", - "maritime": "Maritime boundaries are 'true', all others are 'false'.", - "worldview": "One of 'all', 'CN', 'IN', 'US'. Use for filtering boundaries to match different worldviews." - }, - "id": "admin", - "minzoom": 0, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "abbr": "Text. Local abbreviation of the place (available for type=state).", - "capital": "Admin level the city is a capital of, if any. One of: 2, 3, 4, 5, 6, null", - "class": "One of: country, state, settlement, or settlement_subdivision", - "filterrank": "Number, 0-5. Priority relative to nearby places. Useful for limiting label density.", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the place.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the road is in.", - "name": "Local name of the place", - "name_ar": "Arabic name of the place", - "name_de": "German name of the place", - "name_en": "English name of the place", - "name_es": "Spanish name of the place", - "name_fr": "French name of the place", - "name_it": "Italian name of the place", - "name_ja": "Japanese name of the place", - "name_ko": "Korean name of the place", - "name_pt": "Portuguese name of the place", - "name_ru": "Russian name of the place", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the place", - "name_zh-Hans": "Simplified Chinese name of the place", - "name_zh-Hant": "Traditional Chinese name of the place", - "symbolrank": "Number, 1-18. Useful for styling text & marker sizes.", - "text_anchor": "A hint for label placement at low zoom levels.", - "type": "One of: country, territory, sar, disputed_territory, state, city, town, village, hamlet, suburb, quarter, neighbourhood, island, islet, archipelago, residential, aboriginal_lands", - "worldview": "One of 'all', 'CN', 'IN', 'US'. Use for filtering boundaries to match different worldviews." - }, - "id": "place_label", - "minzoom": 0, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "class": "One of: military, civil", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "maki": "One of: airport, heliport, rocket", - "name": "Local name of the airport", - "name_ar": "Arabic name of the airport", - "name_de": "German name of the airport", - "name_en": "English name of the airport", - "name_es": "Spanish name of the airport", - "name_fr": "French name of the airport", - "name_it": "Italian name of the airport", - "name_ja": "Japanese name of the airport", - "name_ko": "Korean name of the airport", - "name_pt": "Portuguese name of the airport", - "name_ru": "Russian name of the airport", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the airport", - "name_zh-Hans": "Simplified Chinese name of the airport", - "name_zh-Hant": "Traditional Chinese name of the airport", - "ref": "A 3-4 character IATA, FAA, ICAO, or other reference code", - "sizerank": "A scale-dependent feature size ranking from 0 (large) to 16 (small)", - "worldview": "One of 'all', 'CN', 'IN', 'US'. Use for filtering boundaries to match different worldviews." - }, - "id": "airport_label", - "minzoom": 8, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "filterrank": "Number, 0-5. Priority relative to nearby features. Useful for limiting label density.", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "maki": "One of: rail, rail-metro, rail-light, entrance, bus, bicycle-share, ferry", - "mode": "One of: rail, metro_rail, light_rail, tram, bus, monorail, funicular, bicycle, ferry, narrow_gauge, preserved, miniature", - "name": "Local name of the transit stop", - "name_ar": "Arabic name of the transit stop", - "name_de": "German name of the transit stop", - "name_en": "English name of the transit stop", - "name_es": "Spanish name of the transit stop", - "name_fr": "French name of the transit stop", - "name_it": "Italian name of the transit stop", - "name_ja": "Japanese name of the transit stop", - "name_ko": "Korean name of the transit stop", - "name_pt": "Portuguese name of the transit stop", - "name_ru": "Russian name of the transit stop", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the transit stop", - "name_zh-Hans": "Simplified Chinese name of the transit stop", - "name_zh-Hant": "Traditional Chinese name of the transit stop", - "network": "The network(s) that the station serves. Useful for icon styling.", - "network_beta": "One of: jp-shinkansen, jp-shinkansen.jp-jr, jp-shinkansen.tokyo-metro, jp-shinkansen.osaka-subway, jp-shinkansen.jp-jr.tokyo-metro, jp-shinkansen.jp-jr.osaka-subway, jp-jr, jp-jr.tokyo-metro, jp-jr.osaka-subway", - "stop_type": "One of: station, stop, entrance" - }, - "id": "transit_stop_label", - "minzoom": 5, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "class": "One of: glacier, landform, water_feature, wetland, ocean, sea, river, water, reservoir, dock, canal, drain, ditch, stream, continent", - "elevation_ft": "Integer elevation in feet", - "elevation_m": "Integer elevation in meters", - "filterrank": "Number, 0-5. Priority relative to nearby features. Useful for limiting label density.", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "maki": "One of: 'mountain', 'volcano', 'waterfall'", - "name": "Local name of the natural feature", - "name_ar": "Arabic name of the natural feature", - "name_de": "German name of the natural feature", - "name_en": "English name of the natural feature", - "name_es": "Spanish name of the natural feature", - "name_fr": "French name of the natural feature", - "name_it": "Italian name of the natural feature", - "name_ja": "Japanese name of the natural feature", - "name_ko": "Korean name of the natural feature", - "name_pt": "Portuguese name of the natural feature", - "name_ru": "Russian name of the natural feature", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the natural feature", - "name_zh-Hans": "Simplified Chinese name of the natural feature", - "name_zh-Hant": "Traditional Chinese name of the natural feature", - "sizerank": "A scale-dependent feature size ranking from 0 (large) to 16 (small)", - "worldview": "One of 'all', 'CN', 'IN', 'US'. Use for filtering boundaries to match different worldviews." - }, - "id": "natural_label", - "minzoom": 0, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "brand": "String", - "category_en": "English category description of the POI", - "category_zh-Hans": "Simplified Chinese category description of the POI", - "class": "Text. Thematic groupings of POIs for filtering & styling.", - "filterrank": "Number, 0-5. Priority relative to nearby POIs. Useful for limiting label density.", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "maki": "The name of the Maki icon that should be used for the POI", - "maki_beta": "", - "maki_modifier": "", - "name": "Local name of the POI", - "name_ar": "Arabic name of the POI", - "name_de": "German name of the POI", - "name_en": "English name of the POI", - "name_es": "Spanish name of the POI", - "name_fr": "French name of the POI", - "name_it": "Italian name of the POI", - "name_ja": "Japanese name of the POI", - "name_ko": "Korean name of the POI", - "name_pt": "Portuguese name of the POI", - "name_ru": "Russian name of the POI", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the POI", - "name_zh-Hans": "Simplified Chinese name of the POI", - "name_zh-Hant": "Traditional Chinese name of the POI", - "sizerank": "A scale-dependent feature size ranking from 0 (large) to 16 (small)", - "type": "The original OSM tag value" - }, - "id": "poi_label", - "minzoom": 6, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "class": "The class of road the junction is on. Subset of classes in the road layer. One of: motorway, motorway_link, trunk, trunk_link, primary, secondary, tertiary, primary_link, secondary_link, tertiary_link, street, street_limited, construction, track, service, path, major_rail, minor_rail, service_rail.", - "filterrank": "Number, 0-5", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in.", - "maki_beta": "", - "name": "Local name of the motorway junction", - "name_ar": "Arabic name of the motorway junction", - "name_de": "German name of the motorway junction", - "name_en": "English name of the motorway junction", - "name_es": "Spanish name of the motorway junction", - "name_fr": "French name of the motorway junction", - "name_it": "Italian name of the motorway junction", - "name_ja": "Japanese name of the motorway junction", - "name_ko": "Korean name of the motorway junction", - "name_pt": "Portuguese name of the motorway junction", - "name_ru": "Russian name of the motorway junction", - "name_script": "Primary written script of the local name", - "name_vi": "Vietnamese name of the motorway junction", - "name_zh-Hans": "Simplified Chinese name of the motorway junction", - "name_zh-Hant": "Traditional Chinese name of the motorway junction", - "ref": "A short identifier", - "reflen": "The number of characters in the ref field.", - "type": "The type of road the junction is on. Subset of types in the road layer." - }, - "id": "motorway_junction", - "minzoom": 9, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "", - "fields": { - "house_num": "House number", - "iso_3166_1": "Text. The ISO 3166-1 alpha-2 code of the country/territory the feature is in.", - "iso_3166_2": "Text. The ISO 3166-2 code of the state/province/region the feature is in." - }, - "id": "housenum_label", - "minzoom": 16, - "source": "mapbox.mapbox-streets-v8", - "source_name": "Mapbox Streets v8" - }, - { - "description": "Generalized landcover classification", - "fields": { - "class": "One of: wood, scrub, grass, crop, snow" - }, - "id": "landcover", - "maxzoom": 22, - "minzoom": 0, - "source": "mapbox.mapbox-terrain-v2", - "source_name": "Mapbox Terrain v2" - }, - { - "description": "", - "fields": { - "class": "One of: shadow, highlight", - "level": "Brightness %. One of: 94, 90, 89, 78, 67, 56" - }, - "id": "hillshade", - "maxzoom": 22, - "minzoom": 0, - "source": "mapbox.mapbox-terrain-v2", - "source_name": "Mapbox Terrain v2" - }, - { - "description": "Elevation contour polygons", - "fields": { - "ele": "Integer. The elevation of the contour in meters", - "index": "Indicator for every 2nd, 5th, or 10th contour. Coastlines are given -1. One of: 2, 5, 10, -1, null" - }, - "id": "contour", - "maxzoom": 22, - "minzoom": 0, - "source": "mapbox.mapbox-terrain-v2", - "source_name": "Mapbox Terrain v2" - }, - { - "fields": { - "min_depth": "integer" - }, - "id": "depth", - "maxzoom": 7, - "minzoom": 0, - "source": "mapbox.mapbox-bathymetry-v2", - "source_name": "Mapbox Bathymetry v2" - } - ], - "worldview_default": "US", - "worldview_options": { - "AR": "Argentina", - "CN": "China", - "IN": "India", - "JP": "Japan", - "MA": "Morocco", - "RS": "Serbia", - "RU": "Russia", - "TR": "Turkey", - "US": "United States" - } -} \ No newline at end of file diff --git a/src/demo/mapbox-styles.json b/src/demo/mapbox-styles.json deleted file mode 100644 index 178cca9..0000000 --- a/src/demo/mapbox-styles.json +++ /dev/null @@ -1,12486 +0,0 @@ -{ - "name": "Mapbox Streets", - "sprite": "mapbox://sprites/mapbox/streets-v12", - "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", - "center": [ - -92.25, - 37.75 - ], - "zoom": 2, - "fog": { - "range": [ - 2, - 20 - ], - "color": "hsl(0, 0%, 100%)", - "high-color": "hsl(210, 100%, 80%)", - "space-color": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 5, - "hsl(210, 40%, 30%)", - 7, - "hsl(210, 100%, 80%)" - ], - "horizon-blend": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 5, - 0.02, - 7, - 0.08 - ], - "star-intensity": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 5, - 0.1, - 7, - 0 - ] - }, - "projection": { - "name": "globe" - }, - "visibility": "public", - "version": 8, - "layers": [ - { - "id": "land", - "type": "background", - "layout": {}, - "minzoom": 0, - "paint": { - "background-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 9, - "hsl(20, 20%, 95%)", - 11, - "hsl(20, 18%, 91%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, land" - } - }, - { - "id": "landcover", - "type": "fill", - "source": "composite", - "source-layer": "landcover", - "minzoom": 0, - "maxzoom": 12, - "filter": [ - "match", - [ - "get", - "class" - ], - [ - "scrub", - "grass" - ], - [ - "step", - [ - "zoom" - ], - true, - 8, - false - ], - true - ], - "layout": {}, - "paint": { - "fill-color": [ - "match", - [ - "get", - "class" - ], - "wood", - "hsla(115, 55%, 74%, 0.8)", - "snow", - "hsl(200, 70%, 90%)", - "hsl(110, 52%, 81%)" - ], - "fill-opacity": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 9, - 0.4, - 10, - [ - "match", - [ - "get", - "class" - ], - "crop", - 0, - 0.4 - ], - 11, - [ - "match", - [ - "get", - "class" - ], - "crop", - 0, - 0.4 - ], - 12, - 0 - ], - "fill-antialias": false - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, land" - } - }, - { - "id": "national-park", - "type": "fill", - "source": "composite", - "source-layer": "landuse_overlay", - "minzoom": 5, - "filter": [ - "==", - [ - "get", - "class" - ], - "national_park" - ], - "layout": {}, - "paint": { - "fill-color": "hsl(110, 41%, 78%)", - "fill-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 5, - 0, - 6, - 0.6, - 12, - 0.2 - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, land" - } - }, - { - "id": "landuse", - "type": "fill", - "source": "composite", - "source-layer": "landuse", - "minzoom": 5, - "filter": [ - "all", - [ - ">=", - [ - "to-number", - [ - "get", - "sizerank" - ] - ], - 0 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "agriculture", - "wood", - "grass", - "scrub", - "glacier", - "pitch", - "sand" - ], - [ - "step", - [ - "zoom" - ], - false, - 11, - true - ], - "residential", - [ - "step", - [ - "zoom" - ], - true, - 10, - false - ], - [ - "park", - "airport" - ], - [ - "step", - [ - "zoom" - ], - false, - 8, - [ - "case", - [ - "==", - [ - "get", - "sizerank" - ], - 1 - ], - true, - false - ], - 10, - true - ], - [ - "facility", - "industrial" - ], - [ - "step", - [ - "zoom" - ], - false, - 12, - true - ], - "cemetery", - [ - "step", - [ - "zoom" - ], - false, - 11, - true - ], - "school", - [ - "step", - [ - "zoom" - ], - false, - 11, - true - ], - "hospital", - [ - "step", - [ - "zoom" - ], - false, - 11, - true - ], - "commercial_area", - [ - "step", - [ - "zoom" - ], - false, - 11, - true - ], - false - ], - [ - "<=", - [ - "-", - [ - "to-number", - [ - "get", - "sizerank" - ] - ], - [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0, - 18, - 14 - ] - ], - 14 - ] - ], - "layout": {}, - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 15, - [ - "match", - [ - "get", - "class" - ], - "wood", - "hsla(115, 55%, 74%, 0.8)", - "scrub", - "hsla(110, 52%, 82%, 0.6)", - "agriculture", - "hsla(110, 55%, 88%, 0.6)", - "park", - "hsl(110, 60%, 80%)", - "grass", - "hsla(110, 55%, 88%, 0.6)", - "airport", - "hsl(225, 60%, 92%)", - "cemetery", - "hsl(110, 48%, 85%)", - "glacier", - "hsl(200, 70%, 90%)", - "hospital", - "hsl(0, 50%, 92%)", - "pitch", - "hsl(100, 70%, 85%)", - "sand", - "hsl(52, 65%, 86%)", - "school", - "hsl(40, 50%, 88%)", - "commercial_area", - "hsl(45, 55%, 93%)", - "residential", - "hsl(20, 7%, 97%)", - [ - "facility", - "industrial" - ], - "hsl(230, 20%, 90%)", - "hsl(20, 22%, 86%)" - ], - 16, - [ - "match", - [ - "get", - "class" - ], - "wood", - "hsla(115, 55%, 74%, 0.8)", - "scrub", - "hsla(110, 52%, 82%, 0.6)", - "agriculture", - "hsla(110, 55%, 88%, 0.6)", - "park", - "hsl(110, 60%, 80%)", - "grass", - "hsla(110, 55%, 88%, 0.6)", - "airport", - "hsl(225, 60%, 92%)", - "cemetery", - "hsl(110, 48%, 85%)", - "glacier", - "hsl(200, 70%, 90%)", - "hospital", - "hsl(0, 50%, 92%)", - "pitch", - "hsl(100, 70%, 85%)", - "sand", - "hsl(52, 65%, 86%)", - "school", - "hsl(40, 50%, 88%)", - "commercial_area", - "hsla(45, 55%, 93%, 0.5)", - [ - "facility", - "industrial" - ], - "hsl(230, 20%, 90%)", - "hsl(20, 22%, 86%)" - ] - ], - "fill-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 8, - [ - "match", - [ - "get", - "class" - ], - "residential", - 0.8, - 0.2 - ], - 10, - [ - "match", - [ - "get", - "class" - ], - "residential", - 0, - 1 - ] - ], - "fill-antialias": false - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, land" - } - }, - { - "id": "pitch-outline", - "type": "line", - "source": "composite", - "source-layer": "landuse", - "minzoom": 15, - "filter": [ - "==", - [ - "get", - "class" - ], - "pitch" - ], - "layout": {}, - "paint": { - "line-color": "hsl(100, 65%, 75%)" - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, land" - } - }, - { - "id": "waterway-shadow", - "type": "line", - "source": "composite", - "source-layer": "waterway", - "minzoom": 10, - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 11, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 11, - "round" - ] - }, - "paint": { - "line-color": "hsl(219, 100%, 79%)", - "line-width": [ - "interpolate", - [ - "exponential", - 1.3 - ], - [ - "zoom" - ], - 9, - [ - "match", - [ - "get", - "class" - ], - [ - "canal", - "river" - ], - 0.1, - 0 - ], - 20, - [ - "match", - [ - "get", - "class" - ], - [ - "canal", - "river" - ], - 8, - 3 - ] - ], - "line-translate": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 7, - [ - "literal", - [ - 0, - 0 - ] - ], - 16, - [ - "literal", - [ - -1, - -1 - ] - ] - ], - "line-translate-anchor": "viewport", - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 8, - 0, - 8.5, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, water" - } - }, - { - "id": "water-shadow", - "type": "fill", - "source": "composite", - "source-layer": "water", - "minzoom": 10, - "layout": {}, - "paint": { - "fill-color": "hsl(219, 100%, 79%)", - "fill-translate": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 7, - [ - "literal", - [ - 0, - 0 - ] - ], - 16, - [ - "literal", - [ - -1, - -1 - ] - ] - ], - "fill-translate-anchor": "viewport" - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, water" - } - }, - { - "id": "waterway", - "type": "line", - "source": "composite", - "source-layer": "waterway", - "minzoom": 8, - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 11, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 11, - "round" - ] - }, - "paint": { - "line-color": "hsl(200, 100%, 80%)", - "line-width": [ - "interpolate", - [ - "exponential", - 1.3 - ], - [ - "zoom" - ], - 9, - [ - "match", - [ - "get", - "class" - ], - [ - "canal", - "river" - ], - 0.1, - 0 - ], - 20, - [ - "match", - [ - "get", - "class" - ], - [ - "canal", - "river" - ], - 8, - 3 - ] - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 8, - 0, - 8.5, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, water" - } - }, - { - "id": "water", - "type": "fill", - "source": "composite", - "source-layer": "water", - "minzoom": 0, - "layout": {}, - "paint": { - "fill-color": "hsl(200, 100%, 80%)" - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, water" - } - }, - { - "id": "water-depth", - "type": "fill", - "source": "composite", - "source-layer": "depth", - "minzoom": 0, - "maxzoom": 8, - "layout": {}, - "paint": { - "fill-antialias": false, - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 6, - [ - "interpolate", - [ - "linear" - ], - [ - "get", - "min_depth" - ], - 0, - "hsla(200, 100%, 80%, 0.35)", - 200, - "hsla(200, 100%, 72%, 0.35)", - 7000, - "hsla(200, 100%, 64%, 0.35)" - ], - 8, - [ - "interpolate", - [ - "linear" - ], - [ - "get", - "min_depth" - ], - 0, - "hsla(200, 100%, 80%, 0)", - 200, - "hsla(200, 100%, 72%, 0)", - 7000, - "hsla(200, 100%, 60%, 0)" - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, water" - } - }, - { - "id": "hillshade", - "type": "fill", - "source": "composite", - "source-layer": "hillshade", - "filter": [ - "all", - [ - "step", - [ - "zoom" - ], - [ - "==", - [ - "get", - "class" - ], - "shadow" - ], - 11, - true - ], - [ - "match", - [ - "get", - "level" - ], - 89, - true, - 78, - [ - "step", - [ - "zoom" - ], - false, - 5, - true - ], - 67, - [ - "step", - [ - "zoom" - ], - false, - 9, - true - ], - 56, - [ - "step", - [ - "zoom" - ], - false, - 6, - true - ], - 94, - [ - "step", - [ - "zoom" - ], - false, - 11, - true - ], - 90, - [ - "step", - [ - "zoom" - ], - false, - 12, - true - ], - false - ] - ], - "minzoom": 0, - "maxzoom": 16, - "layout": {}, - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 14, - [ - "match", - [ - "get", - "class" - ], - "shadow", - "hsla(40, 41%, 21%, 0.06)", - "hsla(20, 20%, 100%, 0.12)" - ], - 16, - [ - "match", - [ - "get", - "class" - ], - "shadow", - "hsla(40, 41%, 21%, 0)", - "hsla(20, 20%, 100%, 0)" - ] - ], - "fill-antialias": false - }, - "metadata": { - "mapbox:featureComponent": "terrain", - "mapbox:group": "Terrain, land" - } - }, - { - "id": "land-structure-polygon", - "type": "fill", - "source": "composite", - "source-layer": "structure", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "land" - ], - [ - "==", - [ - "geometry-type" - ], - "Polygon" - ] - ], - "layout": {}, - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 9, - "hsl(20, 20%, 95%)", - 11, - "hsl(20, 18%, 91%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, built" - } - }, - { - "id": "land-structure-line", - "type": "line", - "source": "composite", - "source-layer": "structure", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "land" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": "square" - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.99 - ], - [ - "zoom" - ], - 14, - 0.75, - 20, - 40 - ], - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 9, - "hsl(20, 20%, 95%)", - 11, - "hsl(20, 18%, 91%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "land-and-water", - "mapbox:group": "Land & water, built" - } - }, - { - "id": "aeroway-polygon", - "type": "fill", - "source": "composite", - "source-layer": "aeroway", - "minzoom": 11, - "filter": [ - "all", - [ - "match", - [ - "get", - "type" - ], - [ - "runway", - "taxiway", - "helipad" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "Polygon" - ] - ], - "paint": { - "fill-color": "hsl(225, 52%, 87%)", - "fill-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 0, - 11, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, built" - } - }, - { - "id": "aeroway-line", - "type": "line", - "source": "composite", - "source-layer": "aeroway", - "minzoom": 9, - "filter": [ - "==", - [ - "geometry-type" - ], - "LineString" - ], - "paint": { - "line-color": "hsl(225, 52%, 87%)", - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 9, - [ - "match", - [ - "get", - "type" - ], - "runway", - 1, - 0.5 - ], - 18, - [ - "match", - [ - "get", - "type" - ], - "runway", - 80, - 20 - ] - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 0, - 11, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, built" - } - }, - { - "id": "building", - "type": "fill", - "source": "composite", - "source-layer": "building", - "minzoom": 15, - "filter": [ - "all", - [ - "!=", - [ - "get", - "type" - ], - "building:part" - ], - [ - "==", - [ - "get", - "underground" - ], - "false" - ] - ], - "layout": {}, - "paint": { - "fill-color": "hsl(20, 15%, 85%)", - "fill-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 15, - 0, - 16, - 1 - ], - "fill-outline-color": "hsl(20, 10%, 79%)" - }, - "metadata": { - "mapbox:featureComponent": "buildings", - "mapbox:group": "Buildings, built" - } - }, - { - "id": "building-underground", - "type": "fill", - "source": "composite", - "source-layer": "building", - "minzoom": 15, - "filter": [ - "all", - [ - "==", - [ - "get", - "underground" - ], - "true" - ], - [ - "==", - [ - "geometry-type" - ], - "Polygon" - ] - ], - "layout": {}, - "paint": { - "fill-color": "hsl(240, 60%, 92%)", - "fill-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 15, - 0, - 16, - 0.5 - ] - }, - "metadata": { - "mapbox:featureComponent": "buildings", - "mapbox:group": "Buildings, built" - } - }, - { - "id": "tunnel-minor-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "track" - ], - true, - "service", - [ - "step", - [ - "zoom" - ], - false, - 14, - true - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 13%, 72%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 18, - 10, - 22, - 100 - ], - "line-dasharray": [ - 3, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-street-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 13%, 72%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 14, - 1 - ], - "line-dasharray": [ - 3, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-minor-link-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary_link", - "secondary_link", - "tertiary_link" - ], - true, - false - ], - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.4, - 18, - 18, - 22, - 180 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 11, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-secondary-tertiary-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 11, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "secondary", - "tertiary" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 13%, 72%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0, - 18, - 26, - 22, - 260 - ], - "line-dasharray": [ - 3, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-primary-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 10, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "class" - ], - "primary" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 13%, 72%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 28, - 22, - 280 - ], - "line-dasharray": [ - 3, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-major-link-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ], - "line-dasharray": [ - 3, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-motorway-trunk-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ], - "line-dasharray": [ - 3, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels-case" - } - }, - { - "id": "tunnel-path", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "class" - ], - "path" - ], - [ - "!=", - [ - "get", - "type" - ], - "steps" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": {}, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 1, - 18, - 4 - ], - "line-color": "hsl(20, 32%, 95%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.75, - 1 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.75 - ] - ], - 17, - [ - "literal", - [ - 1, - 0.5 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., tunnels" - } - }, - { - "id": "tunnel-steps", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "type" - ], - "steps" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 1, - 16, - 1.6, - 18, - 6 - ], - "line-color": "hsl(20, 32%, 95%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.75, - 1 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.75 - ] - ], - 17, - [ - "literal", - [ - 0.3, - 0.3 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., tunnels" - } - }, - { - "id": "tunnel-pedestrian", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "class" - ], - "pedestrian" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 18, - 12 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.5, - 0.4 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.2 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., tunnels" - } - }, - { - "id": "tunnel-construction", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "class" - ], - "construction" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 2, - 18, - 20, - 22, - 200 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 0.4, - 0.8 - ] - ], - 15, - [ - "literal", - [ - 0.3, - 0.6 - ] - ], - 16, - [ - "literal", - [ - 0.2, - 0.3 - ] - ], - 17, - [ - "literal", - [ - 0.2, - 0.25 - ] - ], - 18, - [ - "literal", - [ - 0.15, - 0.15 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-minor", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "track" - ], - true, - "service", - [ - "step", - [ - "zoom" - ], - false, - 14, - true - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 18, - 10, - 22, - 100 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "street_limited", - "hsl(20, 22%, 94%)", - "hsl(0, 0%, 100%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-minor-link", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary_link", - "secondary_link", - "tertiary_link" - ], - true, - false - ], - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 13, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 13, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.4, - 18, - 18, - 22, - 180 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-major-link", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway_link", - "hsl(30, 100%, 80%)", - "hsl(50, 78%, 80%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-street", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "street_limited", - "hsl(20, 22%, 94%)", - "hsl(0, 0%, 100%)" - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-street-low", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "maxzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-secondary-tertiary", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "secondary", - "tertiary" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0, - 18, - 26, - 22, - 260 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-primary", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "class" - ], - "primary" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 28, - 22, - 280 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-motorway-trunk", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway", - "hsl(30, 100%, 80%)", - "hsl(50, 78%, 80%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-oneway-arrow-blue", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "==", - [ - "get", - "oneway" - ], - "true" - ], - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "street", - "street_limited", - "tertiary" - ], - true, - false - ], - 16, - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "tertiary", - "street", - "street_limited", - "primary_link", - "secondary_link", - "tertiary_link", - "service", - "track" - ], - true, - false - ] - ] - ], - "layout": { - "symbol-placement": "line", - "icon-image": [ - "step", - [ - "zoom" - ], - "oneway-small", - 18, - "oneway-large" - ], - "symbol-spacing": 200, - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "tunnel-oneway-arrow-white", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "tunnel" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "motorway_link", - "trunk", - "trunk_link" - ], - true, - false - ], - [ - "==", - [ - "get", - "oneway" - ], - "true" - ] - ], - "layout": { - "symbol-placement": "line", - "icon-image": [ - "step", - [ - "zoom" - ], - "oneway-white-small", - 18, - "oneway-white-large" - ], - "symbol-spacing": 200, - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, tunnels" - } - }, - { - "id": "ferry", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 8, - "filter": [ - "==", - [ - "get", - "type" - ], - "ferry" - ], - "paint": { - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 15, - "hsl(209, 93%, 73%)", - 17, - "hsl(234, 93%, 73%)" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 20, - 1 - ], - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 13, - [ - "literal", - [ - 12, - 4 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, ferries" - } - }, - { - "id": "ferry-auto", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 8, - "filter": [ - "==", - [ - "get", - "type" - ], - "ferry_auto" - ], - "paint": { - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 15, - "hsl(209, 93%, 73%)", - 17, - "hsl(234, 93%, 73%)" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 20, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, ferries" - } - }, - { - "id": "road-pedestrian-polygon-fill", - "type": "fill", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "path", - "pedestrian" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "case", - [ - "has", - "layer" - ], - [ - ">=", - [ - "get", - "layer" - ], - 0 - ], - true - ], - [ - "==", - [ - "geometry-type" - ], - "Polygon" - ] - ], - "paint": { - "fill-color": "hsl(20, 20%, 94%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-pedestrian-polygon-pattern", - "type": "fill", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "path", - "pedestrian" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "case", - [ - "has", - "layer" - ], - [ - ">=", - [ - "get", - "layer" - ], - 0 - ], - true - ], - [ - "==", - [ - "geometry-type" - ], - "Polygon" - ] - ], - "paint": { - "fill-pattern": "pedestrian-polygon", - "fill-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 16, - 0, - 17, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-path-bg", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "path" - ], - [ - "step", - [ - "zoom" - ], - [ - "!", - [ - "match", - [ - "get", - "type" - ], - [ - "steps", - "sidewalk", - "crossing" - ], - true, - false - ] - ], - 16, - [ - "!=", - [ - "get", - "type" - ], - "steps" - ] - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 2, - 18, - 7 - ], - "line-color": "hsl(220, 11%, 79%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-steps-bg", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "type" - ], - "steps" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": "round" - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 2, - 17, - 4.6, - 18, - 7 - ], - "line-color": "hsl(220, 11%, 79%)", - "line-opacity": 0.75 - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-pedestrian-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "pedestrian" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "case", - [ - "has", - "layer" - ], - [ - ">=", - [ - "get", - "layer" - ], - 0 - ], - true - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 2, - 18, - 14.5 - ], - "line-color": "hsl(220, 20%, 85%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-path", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "path" - ], - [ - "step", - [ - "zoom" - ], - [ - "!", - [ - "match", - [ - "get", - "type" - ], - [ - "steps", - "sidewalk", - "crossing" - ], - true, - false - ] - ], - 16, - [ - "!=", - [ - "get", - "type" - ], - "steps" - ] - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 13, - 0.5, - 14, - 1, - 15, - 1, - 18, - 4 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 4, - 0.3 - ] - ], - 15, - [ - "literal", - [ - 1.75, - 0.3 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.3 - ] - ], - 17, - [ - "literal", - [ - 1, - 0.25 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-steps", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "type" - ], - "steps" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": "round" - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 1, - 16, - 1.6, - 18, - 6 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.75, - 1 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.75 - ] - ], - 17, - [ - "literal", - [ - 0.3, - 0.3 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-pedestrian", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "pedestrian" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "case", - [ - "has", - "layer" - ], - [ - ">=", - [ - "get", - "layer" - ], - 0 - ], - true - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 18, - 12 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.5, - 0.4 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.2 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "golf-hole-line", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "==", - [ - "get", - "class" - ], - "golf" - ], - "paint": { - "line-color": "hsl(110, 29%, 70%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., surface" - } - }, - { - "id": "road-polygon", - "type": "fill", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "tertiary", - "primary_link", - "secondary_link", - "tertiary_link", - "trunk", - "trunk_link", - "street", - "street_limited", - "track", - "service" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "Polygon" - ] - ], - "paint": { - "fill-color": "hsl(0, 0%, 100%)", - "fill-outline-color": "hsl(220, 20%, 85%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "turning-feature-outline", - "type": "circle", - "source": "composite", - "source-layer": "road", - "minzoom": 15, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "turning_circle", - "turning_loop" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "Point" - ] - ], - "paint": { - "circle-radius": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 4.5, - 16, - 8, - 18, - 20, - 22, - 200 - ], - "circle-color": "hsl(0, 0%, 100%)", - "circle-stroke-width": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 15, - 0.8, - 16, - 1.2, - 18, - 2 - ], - "circle-stroke-color": "hsl(220, 20%, 85%)", - "circle-pitch-alignment": "map" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-minor-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "track" - ], - true, - "service", - [ - "step", - [ - "zoom" - ], - false, - 14, - true - ], - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 18, - 10, - 22, - 100 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-street-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-minor-link-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary_link", - "secondary_link", - "tertiary_link" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.4, - 18, - 18, - 22, - 180 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 11, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-secondary-tertiary-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 11, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "secondary", - "tertiary" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0, - 18, - 26, - 22, - 260 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-primary-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 10, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "primary" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 28, - 22, - 280 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-major-link-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 11, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-motorway-trunk-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 3, - "filter": [ - "all", - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - 5, - [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ] - ] - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "turning-feature", - "type": "circle", - "source": "composite", - "source-layer": "road", - "minzoom": 15, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "turning_circle", - "turning_loop" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "Point" - ] - ], - "paint": { - "circle-radius": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 4.5, - 16, - 8, - 18, - 20, - 22, - 200 - ], - "circle-color": "hsl(0, 0%, 100%)", - "circle-pitch-alignment": "map" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-construction", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "construction" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 2, - 18, - 20, - 22, - 200 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 0.4, - 0.8 - ] - ], - 15, - [ - "literal", - [ - 0.3, - 0.6 - ] - ], - 16, - [ - "literal", - [ - 0.2, - 0.3 - ] - ], - 17, - [ - "literal", - [ - 0.2, - 0.25 - ] - ], - 18, - [ - "literal", - [ - 0.15, - 0.15 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-minor", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "track" - ], - true, - "service", - [ - "step", - [ - "zoom" - ], - false, - 14, - true - ], - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 18, - 10, - 22, - 100 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-minor-link", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary_link", - "secondary_link", - "tertiary_link" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 13, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 13, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.4, - 18, - 18, - 22, - 180 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-major-link", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 13, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 13, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway_link", - "hsl(30, 100%, 70%)", - "hsl(50, 89%, 70%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-street", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "street_limited", - "hsl(20, 22%, 94%)", - "hsl(0, 0%, 100%)" - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-street-low", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 11, - "maxzoom": 14, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-secondary-tertiary", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 9, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "secondary", - "tertiary" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0, - 18, - 26, - 22, - 260 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-primary", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 6, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "primary" - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 28, - 22, - 280 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-motorway-trunk", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 3, - "filter": [ - "all", - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - 5, - [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ] - ] - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 13, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 13, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ], - "line-color": [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - "motorway", - "hsl(30, 88%, 64%)", - "trunk", - "hsl(50, 81%, 54%)", - "hsl(20, 18%, 100%)" - ], - 9, - [ - "match", - [ - "get", - "class" - ], - "motorway", - "hsl(30, 100%, 70%)", - "hsl(50, 89%, 70%)" - ] - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface" - } - }, - { - "id": "road-rail", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "major_rail", - "minor_rail" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ] - ], - "paint": { - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - "hsl(35, 25%, 82%)", - 16, - "hsl(220, 4%, 71%)" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 20, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, surface" - } - }, - { - "id": "road-rail-tracks", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "major_rail", - "minor_rail" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ] - ], - "paint": { - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - "hsl(35, 25%, 82%)", - 16, - "hsl(220, 4%, 71%)" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 4, - 20, - 8 - ], - "line-dasharray": [ - 0.1, - 15 - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13.75, - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, surface" - } - }, - { - "id": "level-crossing", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "==", - [ - "get", - "class" - ], - "level_crossing" - ], - "layout": { - "icon-image": "level-crossing", - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface-icons" - } - }, - { - "id": "road-oneway-arrow-blue", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "oneway" - ], - "true" - ], - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "tertiary", - "street", - "street_limited" - ], - true, - false - ], - 16, - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "tertiary", - "street", - "street_limited", - "primary_link", - "secondary_link", - "tertiary_link", - "service", - "track" - ], - true, - false - ] - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ] - ], - "layout": { - "symbol-placement": "line", - "icon-image": [ - "step", - [ - "zoom" - ], - "oneway-small", - 18, - "oneway-large" - ], - "symbol-spacing": 200, - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface-icons" - } - }, - { - "id": "road-oneway-arrow-white", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "oneway" - ], - "true" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk", - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "match", - [ - "get", - "structure" - ], - [ - "none", - "ford" - ], - true, - false - ] - ], - "layout": { - "symbol-placement": "line", - "icon-image": [ - "step", - [ - "zoom" - ], - "oneway-white-small", - 18, - "oneway-white-large" - ], - "symbol-spacing": 200, - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface-icons" - } - }, - { - "id": "crosswalks", - "type": "symbol", - "source": "composite", - "source-layer": "structure", - "minzoom": 17, - "filter": [ - "all", - [ - "==", - [ - "get", - "type" - ], - "crosswalk" - ], - [ - "==", - [ - "geometry-type" - ], - "Point" - ] - ], - "layout": { - "icon-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 16, - 0.1, - 18, - 0.2, - 19, - 0.5, - 22, - 1.5 - ], - "icon-image": [ - "step", - [ - "zoom" - ], - "crosswalk-small", - 18, - "crosswalk-large" - ], - "icon-rotate": [ - "get", - "direction" - ], - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, surface-icons" - } - }, - { - "id": "bridge-path-bg", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "path" - ], - [ - "step", - [ - "zoom" - ], - [ - "!", - [ - "match", - [ - "get", - "type" - ], - [ - "steps", - "sidewalk", - "crossing" - ], - true, - false - ] - ], - 16, - [ - "!=", - [ - "get", - "type" - ], - "steps" - ] - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 2, - 18, - 7 - ], - "line-color": "hsl(220, 11%, 79%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., barriers-bridges" - } - }, - { - "id": "bridge-steps-bg", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "type" - ], - "steps" - ], - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 2, - 17, - 4.6, - 18, - 7 - ], - "line-color": "hsl(220, 11%, 79%)", - "line-opacity": 0.75 - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., barriers-bridges" - } - }, - { - "id": "bridge-pedestrian-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "pedestrian" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 2, - 18, - 14.5 - ], - "line-color": "hsl(220, 20%, 85%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., barriers-bridges" - } - }, - { - "id": "bridge-path", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "path" - ], - [ - "!=", - [ - "get", - "type" - ], - "steps" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": {}, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 1, - 18, - 4 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 4, - 0.3 - ] - ], - 15, - [ - "literal", - [ - 1.75, - 0.3 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.3 - ] - ], - 17, - [ - "literal", - [ - 1, - 0.25 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., barriers-bridges" - } - }, - { - "id": "bridge-steps", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "type" - ], - "steps" - ], - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 15, - 1, - 16, - 1.6, - 18, - 6 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.75, - 1 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.75 - ] - ], - 17, - [ - "literal", - [ - 0.3, - 0.3 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., barriers-bridges" - } - }, - { - "id": "bridge-pedestrian", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "pedestrian" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 18, - 12 - ], - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 1, - 0 - ] - ], - 15, - [ - "literal", - [ - 1.5, - 0.4 - ] - ], - 16, - [ - "literal", - [ - 1, - 0.2 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., barriers-bridges" - } - }, - { - "id": "bridge-minor-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "track" - ], - true, - "service", - [ - "step", - [ - "zoom" - ], - false, - 14, - true - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 18, - 10, - 22, - 100 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-street-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-minor-link-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary_link", - "secondary_link", - "tertiary_link" - ], - true, - false - ], - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.4, - 18, - 18, - 22, - 180 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 11, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-secondary-tertiary-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 11, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "secondary", - "tertiary" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0, - 18, - 26, - 22, - 260 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 10, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-primary-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 10, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "primary" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 28, - 22, - 280 - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 10, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-major-link-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "<=", - [ - "get", - "layer" - ], - 1 - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-motorway-trunk-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "<=", - [ - "get", - "layer" - ], - 1 - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-construction", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "construction" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 2, - 18, - 20, - 22, - 200 - ], - "line-color": "hsl(220, 20%, 85%)", - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 0.4, - 0.8 - ] - ], - 15, - [ - "literal", - [ - 0.3, - 0.6 - ] - ], - 16, - [ - "literal", - [ - 0.2, - 0.3 - ] - ], - 17, - [ - "literal", - [ - 0.2, - 0.25 - ] - ], - 18, - [ - "literal", - [ - 0.15, - 0.15 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-minor", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "track" - ], - true, - "service", - [ - "step", - [ - "zoom" - ], - false, - 14, - true - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 18, - 10, - 22, - 100 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-minor-link", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "primary_link", - "secondary_link", - "tertiary_link" - ], - true, - false - ], - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.4, - 18, - 18, - 22, - 180 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-major-link", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "<=", - [ - "get", - "layer" - ], - 1 - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 13, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway_link", - "hsl(30, 100%, 70%)", - "hsl(50, 89%, 70%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-street", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "street_limited", - "hsl(20, 22%, 94%)", - "hsl(0, 0%, 100%)" - ], - "line-opacity": [ - "step", - [ - "zoom" - ], - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-street-low", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "maxzoom": 14, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "street", - "street_limited" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ], - "line-join": [ - "step", - [ - "zoom" - ], - "miter", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.5, - 18, - 20, - 22, - 200 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-secondary-tertiary", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "secondary", - "tertiary" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0, - 18, - 26, - 22, - 260 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-primary", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "class" - ], - "primary" - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 28, - 22, - 280 - ], - "line-color": "hsl(0, 0%, 100%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-motorway-trunk", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "<=", - [ - "get", - "layer" - ], - 1 - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway", - "hsl(30, 100%, 70%)", - "hsl(50, 89%, 70%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-major-link-2-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - ">=", - [ - "get", - "layer" - ], - 2 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.8, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-motorway-trunk-2-case", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - ">=", - [ - "get", - "layer" - ], - 2 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 22, - 2 - ], - "line-color": "hsl(220, 20%, 97%)", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-major-link-2", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - ">=", - [ - "get", - "layer" - ], - 2 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 13, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 12, - 0.8, - 18, - 20, - 22, - 200 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway_link", - "hsl(30, 100%, 70%)", - "hsl(50, 89%, 70%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-motorway-trunk-2", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - ">=", - [ - "get", - "layer" - ], - 2 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - true, - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "line-cap": [ - "step", - [ - "zoom" - ], - "butt", - 14, - "round" - ] - }, - "paint": { - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 3, - 0.8, - 18, - 30, - 22, - 300 - ], - "line-color": [ - "match", - [ - "get", - "class" - ], - "motorway", - "hsl(30, 100%, 70%)", - "hsl(50, 89%, 70%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-oneway-arrow-blue", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "==", - [ - "get", - "oneway" - ], - "true" - ], - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "tertiary", - "street", - "street_limited" - ], - true, - false - ], - 16, - [ - "match", - [ - "get", - "class" - ], - [ - "primary", - "secondary", - "tertiary", - "street", - "street_limited", - "primary_link", - "secondary_link", - "tertiary_link", - "service", - "track" - ], - true, - false - ] - ] - ], - "layout": { - "symbol-placement": "line", - "icon-image": [ - "step", - [ - "zoom" - ], - "oneway-small", - 18, - "oneway-large" - ], - "symbol-spacing": 200, - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-oneway-arrow-white", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk", - "motorway_link", - "trunk_link" - ], - true, - false - ], - [ - "==", - [ - "get", - "oneway" - ], - "true" - ] - ], - "layout": { - "symbol-placement": "line", - "icon-image": "oneway-white-small", - "symbol-spacing": 200, - "icon-rotation-alignment": "map", - "icon-allow-overlap": true, - "icon-ignore-placement": true - }, - "paint": {}, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, bridges" - } - }, - { - "id": "bridge-rail", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "major_rail", - "minor_rail" - ], - true, - false - ] - ], - "paint": { - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - "hsl(35, 25%, 82%)", - 16, - "hsl(220, 4%, 71%)" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 0.5, - 20, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, bridges" - } - }, - { - "id": "bridge-rail-tracks", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - [ - "get", - "structure" - ], - "bridge" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "major_rail", - "minor_rail" - ], - true, - false - ] - ], - "paint": { - "line-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - "hsl(35, 25%, 82%)", - 16, - "hsl(220, 4%, 71%)" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 4, - 20, - 8 - ], - "line-dasharray": [ - 0.1, - 15 - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13.75, - 0, - 14, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, bridges" - } - }, - { - "id": "aerialway", - "type": "line", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "==", - [ - "get", - "class" - ], - "aerialway" - ], - "paint": { - "line-color": "hsl(225, 60%, 58%)", - "line-width": [ - "interpolate", - [ - "exponential", - 1.5 - ], - [ - "zoom" - ], - 14, - 1, - 20, - 2 - ], - "line-dasharray": [ - 4, - 1 - ] - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, elevated" - } - }, - { - "id": "admin-1-boundary-bg", - "type": "line", - "source": "composite", - "source-layer": "admin", - "minzoom": 7, - "filter": [ - "all", - [ - "==", - [ - "get", - "admin_level" - ], - 1 - ], - [ - "==", - [ - "get", - "maritime" - ], - "false" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ] - ], - "paint": { - "line-color": "hsl(240, 100%, 100%)", - "line-width": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 3, - 12, - 6 - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 7, - 0, - 8, - 0.5 - ], - "line-dasharray": [ - 1, - 0 - ], - "line-blur": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 12, - 3 - ] - }, - "metadata": { - "mapbox:featureComponent": "admin-boundaries", - "mapbox:group": "Administrative boundaries, admin" - } - }, - { - "id": "admin-0-boundary-bg", - "type": "line", - "source": "composite", - "source-layer": "admin", - "minzoom": 1, - "filter": [ - "all", - [ - "==", - [ - "get", - "admin_level" - ], - 0 - ], - [ - "==", - [ - "get", - "maritime" - ], - "false" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ] - ], - "paint": { - "line-width": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 4, - 12, - 8 - ], - "line-color": "hsl(240, 100%, 100%)", - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 4, - 0.5 - ], - "line-blur": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 12, - 2 - ] - }, - "metadata": { - "mapbox:featureComponent": "admin-boundaries", - "mapbox:group": "Administrative boundaries, admin" - } - }, - { - "id": "admin-1-boundary", - "type": "line", - "source": "composite", - "source-layer": "admin", - "minzoom": 2, - "filter": [ - "all", - [ - "==", - [ - "get", - "admin_level" - ], - 1 - ], - [ - "==", - [ - "get", - "maritime" - ], - "false" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ] - ], - "layout": {}, - "paint": { - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 2, - 0 - ] - ], - 7, - [ - "literal", - [ - 2, - 2, - 6, - 2 - ] - ] - ], - "line-width": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0.3, - 12, - 1.5 - ], - "line-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 2, - 0, - 3, - 1 - ], - "line-color": "hsl(240, 50%, 65%)" - }, - "metadata": { - "mapbox:featureComponent": "admin-boundaries", - "mapbox:group": "Administrative boundaries, admin" - } - }, - { - "id": "admin-0-boundary", - "type": "line", - "source": "composite", - "source-layer": "admin", - "minzoom": 1, - "filter": [ - "all", - [ - "==", - [ - "get", - "admin_level" - ], - 0 - ], - [ - "==", - [ - "get", - "disputed" - ], - "false" - ], - [ - "==", - [ - "get", - "maritime" - ], - "false" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ] - ], - "layout": {}, - "paint": { - "line-color": "hsl(240, 50%, 60%)", - "line-width": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0.5, - 12, - 2 - ], - "line-dasharray": [ - 10, - 0 - ] - }, - "metadata": { - "mapbox:featureComponent": "admin-boundaries", - "mapbox:group": "Administrative boundaries, admin" - } - }, - { - "id": "admin-0-boundary-disputed", - "type": "line", - "source": "composite", - "source-layer": "admin", - "minzoom": 1, - "filter": [ - "all", - [ - "==", - [ - "get", - "disputed" - ], - "true" - ], - [ - "==", - [ - "get", - "admin_level" - ], - 0 - ], - [ - "==", - [ - "get", - "maritime" - ], - "false" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ] - ], - "paint": { - "line-color": "hsl(240, 50%, 60%)", - "line-width": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0.5, - 12, - 2 - ], - "line-dasharray": [ - "step", - [ - "zoom" - ], - [ - "literal", - [ - 3, - 2, - 5 - ] - ], - 7, - [ - "literal", - [ - 2, - 1.5 - ] - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "admin-boundaries", - "mapbox:group": "Administrative boundaries, admin" - } - }, - { - "id": "building-entrance", - "type": "symbol", - "source": "composite", - "source-layer": "structure", - "minzoom": 18, - "filter": [ - "==", - [ - "get", - "class" - ], - "entrance" - ], - "layout": { - "icon-image": "marker", - "text-field": [ - "get", - "ref" - ], - "text-size": 10, - "text-offset": [ - 0, - -0.5 - ], - "text-font": [ - "DIN Pro Italic", - "Arial Unicode MS Regular" - ] - }, - "paint": { - "text-color": "hsl(20, 8%, 52%)", - "text-halo-color": "hsl(20, 13%, 92%)", - "text-halo-width": 1, - "icon-opacity": 0.4 - }, - "metadata": { - "mapbox:featureComponent": "buildings", - "mapbox:group": "Buildings, building-labels" - } - }, - { - "id": "building-number-label", - "type": "symbol", - "source": "composite", - "source-layer": "housenum_label", - "minzoom": 17, - "layout": { - "text-field": [ - "get", - "house_num" - ], - "text-font": [ - "DIN Pro Italic", - "Arial Unicode MS Regular" - ], - "text-padding": 4, - "text-max-width": 7, - "text-size": 10 - }, - "paint": { - "text-color": "hsl(20, 8%, 52%)", - "text-halo-color": "hsl(20, 13%, 92%)", - "text-halo-width": 1 - }, - "metadata": { - "mapbox:featureComponent": "buildings", - "mapbox:group": "Buildings, building-labels" - } - }, - { - "id": "block-number-label", - "type": "symbol", - "source": "composite", - "source-layer": "place_label", - "minzoom": 16, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "settlement_subdivision" - ], - [ - "==", - [ - "get", - "type" - ], - "block" - ] - ], - "layout": { - "text-field": [ - "get", - "name" - ], - "text-font": [ - "DIN Pro Italic", - "Arial Unicode MS Regular" - ], - "text-max-width": 7, - "text-size": 11 - }, - "paint": { - "text-color": "hsl(20, 18%, 57%)", - "text-halo-color": "hsl(20, 17%, 100%)", - "text-halo-width": 0.5, - "text-halo-blur": 0.5 - }, - "metadata": { - "mapbox:featureComponent": "buildings", - "mapbox:group": "Buildings, building-labels" - } - }, - { - "id": "road-label", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 10, - "filter": [ - "all", - [ - "has", - "name" - ], - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk", - "primary", - "secondary", - "tertiary" - ], - true, - false - ], - 12, - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk", - "primary", - "secondary", - "tertiary", - "street", - "street_limited" - ], - true, - false - ], - 15, - [ - "match", - [ - "get", - "class" - ], - [ - "path", - "pedestrian", - "golf", - "ferry", - "aerialway" - ], - false, - true - ] - ] - ], - "layout": { - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk", - "primary", - "secondary", - "tertiary" - ], - 10, - [ - "motorway_link", - "trunk_link", - "primary_link", - "secondary_link", - "tertiary_link", - "street", - "street_limited" - ], - 9, - 6.5 - ], - 18, - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk", - "primary", - "secondary", - "tertiary" - ], - 16, - [ - "motorway_link", - "trunk_link", - "primary_link", - "secondary_link", - "tertiary_link", - "street", - "street_limited" - ], - 14, - 13 - ] - ], - "text-max-angle": 30, - "text-font": [ - "DIN Pro Regular", - "Arial Unicode MS Regular" - ], - "symbol-placement": "line", - "text-padding": 1, - "text-rotation-alignment": "map", - "text-pitch-alignment": "viewport", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-letter-spacing": 0.01 - }, - "paint": { - "text-color": "hsl(0,0%, 0%)", - "text-halo-color": [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - "hsla(20, 25%, 100%, 0.75)", - "hsl(20, 25%, 100%)" - ], - "text-halo-width": 1, - "text-halo-blur": 1 - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, road-labels" - } - }, - { - "id": "road-intersection", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 15, - "filter": [ - "all", - [ - "==", - [ - "get", - "class" - ], - "intersection" - ], - [ - "has", - "name" - ] - ], - "layout": { - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "icon-image": "intersection", - "icon-text-fit": "both", - "icon-text-fit-padding": [ - 1, - 2, - 1, - 2 - ], - "text-size": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 15, - 9, - 18, - 12 - ], - "text-font": [ - "DIN Pro Bold", - "Arial Unicode MS Bold" - ] - }, - "paint": { - "text-color": "hsl(230, 57%, 64%)" - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, road-labels" - } - }, - { - "id": "road-number-shield", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 6, - "filter": [ - "all", - [ - "has", - "reflen" - ], - [ - "<=", - [ - "get", - "reflen" - ], - 6 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "pedestrian", - "service" - ], - false, - true - ], - [ - "step", - [ - "zoom" - ], - [ - "==", - [ - "geometry-type" - ], - "Point" - ], - 11, - [ - ">", - [ - "get", - "len" - ], - 5000 - ], - 12, - [ - ">", - [ - "get", - "len" - ], - 2500 - ], - 13, - [ - ">", - [ - "get", - "len" - ], - 1000 - ], - 14, - true - ] - ], - "layout": { - "text-size": 9, - "icon-image": [ - "case", - [ - "has", - "shield_beta" - ], - [ - "coalesce", - [ - "image", - [ - "concat", - [ - "get", - "shield_beta" - ], - "-", - [ - "to-string", - [ - "get", - "reflen" - ] - ] - ] - ], - [ - "image", - [ - "concat", - "default-", - [ - "to-string", - [ - "get", - "reflen" - ] - ] - ] - ] - ], - [ - "concat", - [ - "get", - "shield" - ], - "-", - [ - "to-string", - [ - "get", - "reflen" - ] - ] - ] - ], - "icon-rotation-alignment": "viewport", - "text-max-angle": 38, - "symbol-spacing": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 11, - 400, - 14, - 600 - ], - "text-font": [ - "DIN Pro Bold", - "Arial Unicode MS Bold" - ], - "symbol-placement": [ - "step", - [ - "zoom" - ], - "point", - 11, - "line" - ], - "text-rotation-alignment": "viewport", - "text-field": [ - "get", - "ref" - ], - "text-letter-spacing": 0.05 - }, - "paint": { - "text-color": [ - "case", - [ - "all", - [ - "has", - "shield_text_color_beta" - ], - [ - "to-boolean", - [ - "coalesce", - [ - "image", - [ - "concat", - [ - "get", - "shield_beta" - ], - "-", - [ - "to-string", - [ - "get", - "reflen" - ] - ] - ] - ], - "" - ] - ] - ], - [ - "match", - [ - "get", - "shield_text_color_beta" - ], - "white", - "hsl(0, 0%, 100%)", - "yellow", - "hsl(50, 100%, 70%)", - "orange", - "hsl(25, 100%, 75%)", - "blue", - "hsl(230, 57%, 44%)", - "red", - "hsl(0, 87%, 59%)", - "green", - "hsl(140, 74%, 37%)", - "hsl(230, 18%, 13%)" - ], - [ - "match", - [ - "get", - "shield_text_color" - ], - "white", - "hsl(0, 0%, 100%)", - "yellow", - "hsl(50, 100%, 70%)", - "orange", - "hsl(25, 100%, 75%)", - "blue", - "hsl(230, 57%, 44%)", - "red", - "hsl(0, 87%, 59%)", - "green", - "hsl(140, 74%, 37%)", - "hsl(230, 18%, 13%)" - ] - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, road-labels" - } - }, - { - "id": "road-exit-shield", - "type": "symbol", - "source": "composite", - "source-layer": "motorway_junction", - "minzoom": 14, - "filter": [ - "all", - [ - "has", - "reflen" - ], - [ - "<=", - [ - "get", - "reflen" - ], - 9 - ] - ], - "layout": { - "text-field": [ - "get", - "ref" - ], - "text-size": 9, - "icon-image": [ - "concat", - "motorway-exit-", - [ - "to-string", - [ - "get", - "reflen" - ] - ] - ], - "text-font": [ - "DIN Pro Bold", - "Arial Unicode MS Bold" - ] - }, - "paint": { - "text-color": "hsl(0, 0%, 100%)", - "text-translate": [ - 0, - 0 - ] - }, - "metadata": { - "mapbox:featureComponent": "road-network", - "mapbox:group": "Road network, road-labels" - } - }, - { - "id": "path-pedestrian-label", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 12, - "filter": [ - "all", - [ - "case", - [ - "has", - "layer" - ], - [ - ">=", - [ - "get", - "layer" - ], - 0 - ], - true - ], - [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "class" - ], - [ - "pedestrian" - ], - true, - false - ], - 15, - [ - "match", - [ - "get", - "class" - ], - [ - "path", - "pedestrian" - ], - true, - false - ] - ] - ], - "layout": { - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - [ - "match", - [ - "get", - "class" - ], - "pedestrian", - 9, - 6.5 - ], - 18, - [ - "match", - [ - "get", - "class" - ], - "pedestrian", - 14, - 13 - ] - ], - "text-max-angle": 30, - "text-font": [ - "DIN Pro Regular", - "Arial Unicode MS Regular" - ], - "symbol-placement": "line", - "text-padding": 1, - "text-rotation-alignment": "map", - "text-pitch-alignment": "viewport", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-letter-spacing": 0.01 - }, - "paint": { - "text-color": "hsl(0,0%, 0%)", - "text-halo-color": "hsl(20, 25%, 100%)", - "text-halo-width": 1, - "text-halo-blur": 1 - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., walking-cycling-labels" - } - }, - { - "id": "golf-hole-label", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 16, - "filter": [ - "==", - [ - "get", - "class" - ], - "golf" - ], - "layout": { - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-size": 12 - }, - "paint": { - "text-halo-color": "hsl(110, 65%, 65%)", - "text-halo-width": 0.5, - "text-halo-blur": 0.5, - "text-color": "hsl(110, 70%, 28%)" - }, - "metadata": { - "mapbox:featureComponent": "walking-cycling", - "mapbox:group": "Walking, cycling, etc., walking-cycling-labels" - } - }, - { - "id": "ferry-aerialway-label", - "type": "symbol", - "source": "composite", - "source-layer": "road", - "minzoom": 15, - "filter": [ - "match", - [ - "get", - "class" - ], - "aerialway", - true, - "ferry", - true, - false - ], - "layout": { - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.5, - 18, - 13 - ], - "text-max-angle": 30, - "text-font": [ - "DIN Pro Regular", - "Arial Unicode MS Regular" - ], - "symbol-placement": "line", - "text-padding": 1, - "text-rotation-alignment": "map", - "text-pitch-alignment": "viewport", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-letter-spacing": 0.01 - }, - "paint": { - "text-color": [ - "match", - [ - "get", - "class" - ], - "ferry", - "hsl(200, 68%, 60%)", - "hsl(225, 60%, 58%)" - ], - "text-halo-color": [ - "match", - [ - "get", - "class" - ], - "ferry", - "hsl(200, 100%, 80%)", - "hsl(20, 20%, 100%)" - ], - "text-halo-width": 1, - "text-halo-blur": 1 - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, ferry-aerialway-labels" - } - }, - { - "id": "waterway-label", - "type": "symbol", - "source": "composite", - "source-layer": "natural_label", - "minzoom": 13, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "canal", - "river", - "stream", - "disputed_canal", - "disputed_river", - "disputed_stream" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "text-font": [ - "DIN Pro Italic", - "Arial Unicode MS Regular" - ], - "text-max-angle": 30, - "symbol-spacing": [ - "interpolate", - [ - "linear", - 1 - ], - [ - "zoom" - ], - 15, - 250, - 17, - 400 - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 12, - 18, - 18 - ], - "symbol-placement": "line", - "text-pitch-alignment": "viewport", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - }, - "paint": { - "text-color": "hsl(200, 68%, 57%)", - "text-halo-color": "hsla(20, 17%, 100%, 0.5)" - }, - "metadata": { - "mapbox:featureComponent": "natural-features", - "mapbox:group": "Natural features, natural-labels" - } - }, - { - "id": "natural-line-label", - "type": "symbol", - "metadata": { - "mapbox:featureComponent": "natural-features", - "mapbox:group": "Natural features, natural-labels" - }, - "source": "composite", - "source-layer": "natural_label", - "minzoom": 4, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "glacier", - "landform", - "disputed_glacier", - "disputed_landform" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "<=", - [ - "get", - "filterrank" - ], - 2 - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "text-size": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - 18, - 5, - 12 - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - 18, - 13, - 12 - ] - ], - "text-max-angle": 30, - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "symbol-placement": "line-center", - "text-pitch-alignment": "viewport" - }, - "paint": { - "text-halo-width": 0.5, - "text-halo-color": "hsl(20, 17%, 100%)", - "text-halo-blur": 0.5, - "text-color": "hsl(210, 20%, 46%)" - } - }, - { - "id": "natural-point-label", - "type": "symbol", - "source": "composite", - "source-layer": "natural_label", - "minzoom": 4, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "dock", - "glacier", - "landform", - "water_feature", - "wetland", - "disputed_dock", - "disputed_glacier", - "disputed_landform", - "disputed_water_feature", - "disputed_wetland" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "<=", - [ - "get", - "filterrank" - ], - 2 - ], - [ - "==", - [ - "geometry-type" - ], - "Point" - ] - ], - "layout": { - "text-size": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - 18, - 5, - 12 - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - 18, - 13, - 12 - ] - ], - "icon-image": [ - "get", - "maki" - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-offset": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - [ - "literal", - [ - 0, - 0 - ] - ], - 5, - [ - "literal", - [ - 0, - 0.75 - ] - ] - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - [ - "literal", - [ - 0, - 0 - ] - ], - 13, - [ - "literal", - [ - 0, - 0.75 - ] - ] - ] - ], - "text-anchor": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - "center", - 5, - "top" - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - "center", - 13, - "top" - ] - ], - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - }, - "paint": { - "icon-opacity": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - 0, - 5, - 1 - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - 0, - 13, - 1 - ] - ], - "text-halo-color": "hsl(20, 20%, 100%)", - "text-halo-width": 0.5, - "text-halo-blur": 0.5, - "text-color": "hsl(210, 20%, 46%)" - }, - "metadata": { - "mapbox:featureComponent": "natural-features", - "mapbox:group": "Natural features, natural-labels" - } - }, - { - "id": "water-line-label", - "type": "symbol", - "metadata": { - "mapbox:featureComponent": "natural-features", - "mapbox:group": "Natural features, natural-labels" - }, - "source": "composite", - "source-layer": "natural_label", - "minzoom": 1, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "bay", - "ocean", - "reservoir", - "sea", - "water", - "disputed_bay", - "disputed_ocean", - "disputed_reservoir", - "disputed_sea", - "disputed_water" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "LineString" - ] - ], - "layout": { - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - [ - "*", - [ - "-", - 16, - [ - "sqrt", - [ - "get", - "sizerank" - ] - ] - ], - 1 - ], - 22, - [ - "*", - [ - "-", - 22, - [ - "sqrt", - [ - "get", - "sizerank" - ] - ] - ], - 1 - ] - ], - "text-max-angle": 30, - "text-letter-spacing": [ - "match", - [ - "get", - "class" - ], - "ocean", - 0.25, - [ - "sea", - "bay" - ], - 0.15, - 0 - ], - "text-font": [ - "DIN Pro Italic", - "Arial Unicode MS Regular" - ], - "symbol-placement": "line-center", - "text-pitch-alignment": "viewport", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - }, - "paint": { - "text-color": [ - "match", - [ - "get", - "class" - ], - [ - "bay", - "ocean", - "sea" - ], - "hsl(200, 96%, 57%)", - "hsl(200, 68%, 57%)" - ], - "text-halo-color": "hsla(20, 17%, 100%, 0.5)" - } - }, - { - "id": "water-point-label", - "type": "symbol", - "source": "composite", - "source-layer": "natural_label", - "minzoom": 1, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "bay", - "ocean", - "reservoir", - "sea", - "water", - "disputed_bay", - "disputed_ocean", - "disputed_reservoir", - "disputed_sea", - "disputed_water" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "==", - [ - "geometry-type" - ], - "Point" - ] - ], - "layout": { - "text-line-height": 1.3, - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - [ - "*", - [ - "-", - 16, - [ - "sqrt", - [ - "get", - "sizerank" - ] - ] - ], - 1 - ], - 22, - [ - "*", - [ - "-", - 22, - [ - "sqrt", - [ - "get", - "sizerank" - ] - ] - ], - 1 - ] - ], - "text-font": [ - "DIN Pro Italic", - "Arial Unicode MS Regular" - ], - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-letter-spacing": [ - "match", - [ - "get", - "class" - ], - "ocean", - 0.25, - [ - "bay", - "sea" - ], - 0.15, - 0.01 - ], - "text-max-width": [ - "match", - [ - "get", - "class" - ], - "ocean", - 4, - "sea", - 5, - [ - "bay", - "water" - ], - 7, - 10 - ] - }, - "paint": { - "text-color": [ - "match", - [ - "get", - "class" - ], - [ - "bay", - "ocean", - "sea" - ], - "hsl(200, 96%, 57%)", - "hsl(200, 68%, 57%)" - ], - "text-halo-color": "hsla(20, 17%, 100%, 0.5)" - }, - "metadata": { - "mapbox:featureComponent": "natural-features", - "mapbox:group": "Natural features, natural-labels" - } - }, - { - "id": "poi-label", - "type": "symbol", - "source": "composite", - "source-layer": "poi_label", - "minzoom": 6, - "filter": [ - "<=", - [ - "get", - "filterrank" - ], - [ - "+", - [ - "step", - [ - "zoom" - ], - 0, - 16, - 1, - 17, - 2 - ], - 3 - ] - ], - "layout": { - "text-size": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - 18, - 5, - 12 - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - 18, - 13, - 12 - ] - ], - "icon-image": [ - "case", - [ - "has", - "maki_beta" - ], - [ - "coalesce", - [ - "image", - [ - "get", - "maki_beta" - ] - ], - [ - "image", - [ - "get", - "maki" - ] - ] - ], - [ - "image", - [ - "get", - "maki" - ] - ] - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-offset": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - [ - "literal", - [ - 0, - 0 - ] - ], - 5, - [ - "literal", - [ - 0, - 0.8 - ] - ] - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - [ - "literal", - [ - 0, - 0 - ] - ], - 13, - [ - "literal", - [ - 0, - 0.8 - ] - ] - ] - ], - "text-anchor": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - "center", - 5, - "top" - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - "center", - 13, - "top" - ] - ], - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - }, - "paint": { - "icon-opacity": [ - "step", - [ - "zoom" - ], - [ - "step", - [ - "get", - "sizerank" - ], - 0, - 5, - 1 - ], - 17, - [ - "step", - [ - "get", - "sizerank" - ], - 0, - 13, - 1 - ] - ], - "text-halo-color": "hsl(20, 20%, 100%)", - "text-halo-width": 0.5, - "text-halo-blur": 0.5, - "text-color": [ - "match", - [ - "get", - "class" - ], - "food_and_drink", - "hsl(40, 95%, 43%)", - "park_like", - "hsl(110, 70%, 28%)", - "education", - "hsl(30, 50%, 43%)", - "medical", - "hsl(0, 70%, 58%)", - "sport_and_leisure", - "hsl(190, 60%, 48%)", - [ - "store_like", - "food_and_drink_stores" - ], - "hsl(210, 70%, 58%)", - [ - "commercial_services", - "motorist", - "lodging" - ], - "hsl(260, 70%, 63%)", - [ - "arts_and_entertainment", - "historic", - "landmark" - ], - "hsl(320, 70%, 63%)", - "hsl(210, 20%, 46%)" - ] - }, - "metadata": { - "mapbox:featureComponent": "point-of-interest-labels", - "mapbox:group": "Point of interest labels, poi-labels" - } - }, - { - "id": "transit-label", - "type": "symbol", - "source": "composite", - "source-layer": "transit_stop_label", - "minzoom": 12, - "filter": [ - "step", - [ - "zoom" - ], - [ - "all", - [ - "<=", - [ - "get", - "filterrank" - ], - 4 - ], - [ - "match", - [ - "get", - "mode" - ], - "rail", - true, - "metro_rail", - true, - false - ], - [ - "!=", - [ - "get", - "stop_type" - ], - "entrance" - ] - ], - 14, - [ - "all", - [ - "match", - [ - "get", - "mode" - ], - "rail", - true, - "metro_rail", - true, - false - ], - [ - "!=", - [ - "get", - "stop_type" - ], - "entrance" - ] - ], - 15, - [ - "all", - [ - "match", - [ - "get", - "mode" - ], - "rail", - true, - "metro_rail", - true, - "ferry", - true, - "light_rail", - true, - false - ], - [ - "!=", - [ - "get", - "stop_type" - ], - "entrance" - ] - ], - 16, - [ - "all", - [ - "match", - [ - "get", - "mode" - ], - "bus", - false, - true - ], - [ - "!=", - [ - "get", - "stop_type" - ], - "entrance" - ] - ], - 17, - [ - "!=", - [ - "get", - "stop_type" - ], - "entrance" - ], - 19, - true - ], - "layout": { - "text-size": 12, - "icon-image": [ - "get", - "network" - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-justify": [ - "match", - [ - "get", - "stop_type" - ], - "entrance", - "left", - "center" - ], - "text-offset": [ - "match", - [ - "get", - "stop_type" - ], - "entrance", - [ - "literal", - [ - 1, - 0 - ] - ], - [ - "literal", - [ - 0, - 0.8 - ] - ] - ], - "text-anchor": [ - "match", - [ - "get", - "stop_type" - ], - "entrance", - "left", - "top" - ], - "text-field": [ - "step", - [ - "zoom" - ], - "", - 13, - [ - "match", - [ - "get", - "mode" - ], - [ - "rail", - "metro_rail" - ], - [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "" - ], - 14, - [ - "match", - [ - "get", - "mode" - ], - [ - "bus", - "bicycle" - ], - "", - [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - ], - 18, - [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - ], - "text-letter-spacing": 0.01, - "text-max-width": [ - "match", - [ - "get", - "stop_type" - ], - "entrance", - 15, - 9 - ] - }, - "paint": { - "text-halo-color": "hsl(20, 20%, 100%)", - "text-color": [ - "match", - [ - "get", - "network" - ], - "tokyo-metro", - "hsl(180, 50%, 30%)", - "mexico-city-metro", - "hsl(25, 100%, 63%)", - [ - "barcelona-metro", - "delhi-metro", - "hong-kong-mtr", - "milan-metro", - "osaka-subway" - ], - "hsl(0, 90%, 47%)", - [ - "boston-t", - "washington-metro" - ], - "hsl(230, 18%, 20%)", - [ - "chongqing-rail-transit", - "kiev-metro", - "singapore-mrt", - "taipei-metro" - ], - "hsl(140, 90%, 25%)", - "hsl(225, 60%, 58%)" - ], - "text-halo-blur": 0.5, - "text-halo-width": 0.5 - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, transit-labels" - } - }, - { - "id": "airport-label", - "type": "symbol", - "source": "composite", - "source-layer": "airport_label", - "minzoom": 8, - "filter": [ - "match", - [ - "get", - "class" - ], - [ - "military", - "civil", - "disputed_military", - "disputed_civil" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - "layout": { - "text-line-height": 1.1, - "text-size": [ - "step", - [ - "get", - "sizerank" - ], - 18, - 9, - 12 - ], - "icon-image": [ - "get", - "maki" - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-offset": [ - 0, - 0.8 - ], - "text-rotation-alignment": "viewport", - "text-anchor": "top", - "text-field": [ - "step", - [ - "get", - "sizerank" - ], - [ - "case", - [ - "has", - "ref" - ], - [ - "concat", - [ - "get", - "ref" - ], - " -\n", - [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - ], - [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ] - ], - 15, - [ - "get", - "ref" - ] - ], - "text-letter-spacing": 0.01, - "text-max-width": 9 - }, - "paint": { - "text-color": "hsl(225, 60%, 58%)", - "text-halo-color": "hsl(20, 20%, 100%)", - "text-halo-width": 1 - }, - "metadata": { - "mapbox:featureComponent": "transit", - "mapbox:group": "Transit, transit-labels" - } - }, - { - "id": "settlement-subdivision-label", - "type": "symbol", - "source": "composite", - "source-layer": "place_label", - "minzoom": 10, - "maxzoom": 15, - "filter": [ - "all", - [ - "match", - [ - "get", - "class" - ], - [ - "settlement_subdivision", - "disputed_settlement_subdivision" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "<=", - [ - "get", - "filterrank" - ], - 3 - ] - ], - "layout": { - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-transform": "uppercase", - "text-font": [ - "DIN Pro Regular", - "Arial Unicode MS Regular" - ], - "text-letter-spacing": [ - "match", - [ - "get", - "type" - ], - "suburb", - 0.15, - 0.05 - ], - "text-max-width": 7, - "text-padding": 3, - "text-size": [ - "interpolate", - [ - "cubic-bezier", - 0.5, - 0, - 1, - 1 - ], - [ - "zoom" - ], - 11, - [ - "match", - [ - "get", - "type" - ], - "suburb", - 11, - 10.5 - ], - 15, - [ - "match", - [ - "get", - "type" - ], - "suburb", - 15, - 14 - ] - ] - }, - "paint": { - "text-halo-color": "hsla(20, 25%, 100%, 0.75)", - "text-halo-width": 1, - "text-color": "hsl(220, 30%, 40%)", - "text-halo-blur": 0.5 - }, - "metadata": { - "mapbox:featureComponent": "place-labels", - "mapbox:group": "Place labels, place-labels" - } - }, - { - "id": "settlement-minor-label", - "type": "symbol", - "source": "composite", - "source-layer": "place_label", - "minzoom": 2, - "maxzoom": 13, - "filter": [ - "all", - [ - "<=", - [ - "get", - "filterrank" - ], - 3 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "settlement", - "disputed_settlement" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "step", - [ - "zoom" - ], - [ - ">", - [ - "get", - "symbolrank" - ], - 6 - ], - 4, - [ - ">=", - [ - "get", - "symbolrank" - ], - 7 - ], - 6, - [ - ">=", - [ - "get", - "symbolrank" - ], - 8 - ], - 7, - [ - ">=", - [ - "get", - "symbolrank" - ], - 10 - ], - 10, - [ - ">=", - [ - "get", - "symbolrank" - ], - 11 - ], - 11, - [ - ">=", - [ - "get", - "symbolrank" - ], - 13 - ], - 12, - [ - ">=", - [ - "get", - "symbolrank" - ], - 15 - ] - ] - ], - "layout": { - "symbol-sort-key": [ - "get", - "symbolrank" - ], - "icon-image": [ - "step", - [ - "zoom" - ], - [ - "case", - [ - "==", - [ - "get", - "capital" - ], - 2 - ], - "border-dot-13", - [ - "step", - [ - "get", - "symbolrank" - ], - "dot-11", - 9, - "dot-10", - 11, - "dot-9" - ] - ], - 8, - "" - ], - "text-font": [ - "DIN Pro Regular", - "Arial Unicode MS Regular" - ], - "text-radial-offset": [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "capital" - ], - 2, - 0.6, - 0.55 - ], - 8, - 0 - ], - "text-anchor": [ - "step", - [ - "zoom" - ], - [ - "get", - "text_anchor" - ], - 8, - "center" - ], - "text-justify": "auto", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-max-width": 7, - "text-line-height": 1.1, - "text-size": [ - "interpolate", - [ - "cubic-bezier", - 0.2, - 0, - 0.9, - 1 - ], - [ - "zoom" - ], - 3, - [ - "step", - [ - "get", - "symbolrank" - ], - 11, - 9, - 10 - ], - 6, - [ - "step", - [ - "get", - "symbolrank" - ], - 14, - 9, - 12, - 12, - 10 - ], - 8, - [ - "step", - [ - "get", - "symbolrank" - ], - 16, - 9, - 14, - 12, - 12, - 15, - 10 - ], - 13, - [ - "step", - [ - "get", - "symbolrank" - ], - 22, - 9, - 20, - 12, - 16, - 15, - 14 - ] - ] - }, - "paint": { - "text-color": "hsl(220, 30%, 0%)", - "text-halo-color": "hsl(20, 25%, 100%)", - "text-halo-width": 1, - "text-halo-blur": 1 - }, - "metadata": { - "mapbox:featureComponent": "place-labels", - "mapbox:group": "Place labels, place-labels" - } - }, - { - "id": "settlement-major-label", - "type": "symbol", - "source": "composite", - "source-layer": "place_label", - "minzoom": 2, - "maxzoom": 15, - "filter": [ - "all", - [ - "<=", - [ - "get", - "filterrank" - ], - 3 - ], - [ - "match", - [ - "get", - "class" - ], - [ - "settlement", - "disputed_settlement" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - [ - "step", - [ - "zoom" - ], - false, - 2, - [ - "<=", - [ - "get", - "symbolrank" - ], - 6 - ], - 4, - [ - "<", - [ - "get", - "symbolrank" - ], - 7 - ], - 6, - [ - "<", - [ - "get", - "symbolrank" - ], - 8 - ], - 7, - [ - "<", - [ - "get", - "symbolrank" - ], - 10 - ], - 10, - [ - "<", - [ - "get", - "symbolrank" - ], - 11 - ], - 11, - [ - "<", - [ - "get", - "symbolrank" - ], - 13 - ], - 12, - [ - "<", - [ - "get", - "symbolrank" - ], - 15 - ], - 13, - [ - ">=", - [ - "get", - "symbolrank" - ], - 11 - ], - 14, - [ - ">=", - [ - "get", - "symbolrank" - ], - 15 - ] - ] - ], - "layout": { - "symbol-sort-key": [ - "get", - "symbolrank" - ], - "icon-image": [ - "step", - [ - "zoom" - ], - [ - "case", - [ - "==", - [ - "get", - "capital" - ], - 2 - ], - "border-dot-13", - [ - "step", - [ - "get", - "symbolrank" - ], - "dot-11", - 9, - "dot-10", - 11, - "dot-9" - ] - ], - 8, - "" - ], - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-radial-offset": [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "capital" - ], - 2, - 0.6, - 0.55 - ], - 8, - 0 - ], - "text-anchor": [ - "step", - [ - "zoom" - ], - [ - "get", - "text_anchor" - ], - 8, - "center" - ], - "text-justify": [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "text_anchor" - ], - [ - "left", - "bottom-left", - "top-left" - ], - "left", - [ - "right", - "bottom-right", - "top-right" - ], - "right", - "center" - ], - 8, - "center" - ], - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-max-width": 7, - "text-line-height": 1.1, - "text-size": [ - "interpolate", - [ - "cubic-bezier", - 0.2, - 0, - 0.9, - 1 - ], - [ - "zoom" - ], - 3, - [ - "step", - [ - "get", - "symbolrank" - ], - 13, - 6, - 11 - ], - 6, - [ - "step", - [ - "get", - "symbolrank" - ], - 18, - 6, - 16, - 7, - 14 - ], - 8, - [ - "step", - [ - "get", - "symbolrank" - ], - 20, - 9, - 16, - 10, - 14 - ], - 15, - [ - "step", - [ - "get", - "symbolrank" - ], - 24, - 9, - 20, - 12, - 16, - 15, - 14 - ] - ] - }, - "paint": { - "text-color": "hsl(220, 30%, 0%)", - "text-halo-color": "hsl(20, 25%, 100%)", - "text-halo-width": 1, - "text-halo-blur": 1 - }, - "metadata": { - "mapbox:featureComponent": "place-labels", - "mapbox:group": "Place labels, place-labels" - } - }, - { - "id": "state-label", - "type": "symbol", - "source": "composite", - "source-layer": "place_label", - "minzoom": 3, - "maxzoom": 9, - "filter": [ - "match", - [ - "get", - "class" - ], - [ - "state", - "disputed_state" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - "layout": { - "text-size": [ - "interpolate", - [ - "cubic-bezier", - 0.85, - 0.7, - 0.65, - 1 - ], - [ - "zoom" - ], - 4, - [ - "step", - [ - "get", - "symbolrank" - ], - 9, - 6, - 8, - 7, - 7 - ], - 9, - [ - "step", - [ - "get", - "symbolrank" - ], - 21, - 6, - 16, - 7, - 14 - ] - ], - "text-transform": "uppercase", - "text-font": [ - "DIN Pro Bold", - "Arial Unicode MS Bold" - ], - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-letter-spacing": 0.15, - "text-max-width": 6 - }, - "paint": { - "text-color": "hsl(220, 30%, 0%)", - "text-halo-color": "hsl(20, 25%, 100%)", - "text-halo-width": 1, - "text-opacity": 0.5 - }, - "metadata": { - "mapbox:featureComponent": "place-labels", - "mapbox:group": "Place labels, place-labels" - } - }, - { - "id": "country-label", - "type": "symbol", - "source": "composite", - "source-layer": "place_label", - "minzoom": 1, - "maxzoom": 10, - "filter": [ - "match", - [ - "get", - "class" - ], - [ - "country", - "disputed_country" - ], - [ - "match", - [ - "get", - "worldview" - ], - [ - "all", - "US" - ], - true, - false - ], - false - ], - "layout": { - "icon-image": "", - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-line-height": 1.1, - "text-max-width": 6, - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-radial-offset": [ - "step", - [ - "zoom" - ], - 0.6, - 8, - 0 - ], - "text-justify": [ - "step", - [ - "zoom" - ], - [ - "match", - [ - "get", - "text_anchor" - ], - [ - "left", - "bottom-left", - "top-left" - ], - "left", - [ - "right", - "bottom-right", - "top-right" - ], - "right", - "center" - ], - 7, - "auto" - ], - "text-size": [ - "interpolate", - [ - "cubic-bezier", - 0.2, - 0, - 0.7, - 1 - ], - [ - "zoom" - ], - 1, - [ - "step", - [ - "get", - "symbolrank" - ], - 11, - 4, - 9, - 5, - 8 - ], - 9, - [ - "step", - [ - "get", - "symbolrank" - ], - 22, - 4, - 19, - 5, - 17 - ] - ] - }, - "paint": { - "icon-opacity": [ - "step", - [ - "zoom" - ], - [ - "case", - [ - "has", - "text_anchor" - ], - 1, - 0 - ], - 7, - 0 - ], - "text-color": "hsl(220, 30%, 0%)", - "text-halo-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 2, - "hsla(20, 25%, 100%, 0.75)", - 3, - "hsl(20, 25%, 100%)" - ], - "text-halo-width": 1.25 - }, - "metadata": { - "mapbox:featureComponent": "place-labels", - "mapbox:group": "Place labels, place-labels" - } - }, - { - "id": "continent-label", - "type": "symbol", - "source": "composite", - "source-layer": "natural_label", - "minzoom": 0.75, - "maxzoom": 3, - "filter": [ - "==", - [ - "get", - "class" - ], - "continent" - ], - "layout": { - "text-field": [ - "coalesce", - [ - "get", - "name_en" - ], - [ - "get", - "name" - ] - ], - "text-line-height": 1.1, - "text-max-width": 6, - "text-font": [ - "DIN Pro Medium", - "Arial Unicode MS Regular" - ], - "text-size": [ - "interpolate", - [ - "exponential", - 0.5 - ], - [ - "zoom" - ], - 0, - 10, - 2.5, - 15 - ], - "text-transform": "uppercase", - "text-letter-spacing": 0.05 - }, - "paint": { - "text-color": "hsl(220, 30%, 0%)", - "text-halo-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "hsla(20, 25%, 100%, 0.75)", - 3, - "hsl(20, 25%, 100%)" - ], - "text-halo-width": 1.5, - "text-opacity": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - 0.8, - 1.5, - 0.5, - 2.5, - 0 - ] - }, - "metadata": { - "mapbox:featureComponent": "place-labels", - "mapbox:group": "Place labels, place-labels" - } - } - ], - "sources": { - "composite": { - "url": "mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2,mapbox.mapbox-bathymetry-v2", - "type": "vector" - } - }, - "created": "1970-01-01T00:00:00.000Z", - "modified": "1970-01-01T00:00:00.000Z", - "owner": "mapbox", - "id": "streets-v12", - "draft": false -} \ No newline at end of file diff --git a/src/demo/webgl/webgl_line.ts b/src/demo/webgl/webgl_line.ts new file mode 100644 index 0000000..c44a686 --- /dev/null +++ b/src/demo/webgl/webgl_line.ts @@ -0,0 +1,91 @@ +import { WebGlScene } from './webgl_scene'; +import { createRootEl } from '../demo_utils'; +import { ENABLED_FEATURE_FLAGS } from '../enabled_features'; +import { MapTileFeatureType } from '../../map/tile/tile'; +import { LineJoinStyle, LineCapStyle, LineFillStyle } from '../../map/renderer/webgl/objects/line/line'; +import { WebGlSceneCamera } from '../../map/renderer/webgl/webgl_camera'; + +export async function renderWebglLineExample() { + const rootEl = createRootEl(window.innerWidth, window.innerHeight, 10); + document.body.appendChild(rootEl); + + const scene = new WebGlScene(rootEl, ENABLED_FEATURE_FLAGS); + + await scene.init(); + + const width = scene.getWidth(); + const height = scene.getHeight(); + + // horisontal line + // scene.addObject({ + // type: MapTileFeatureType.line, + // id: 1, + // color: [0, 0, 1, 1], + // vertecies: [ + // [-width / 4, 0], + // [width / 4, 0], + // ], + // width: 20, + // borderWidth: 10, + // borderColor: [1, 0, 0, 1], + // fill: LineFillStyle.solid, + // join: LineJoinStyle.round, + // cap: LineCapStyle.round, + // }); + + // vertical line + scene.addObject({ + type: MapTileFeatureType.line, + id: 2, + color: [1, 0, 0, 1], + vertecies: [ + [0, -height / 4], + [0, height / 4], + [width / 2 - 20, height / 4], + [width / 2 - 20, -height / 4], + [0, -height / 4], + ], + width: 20, + borderWidth: 10, + borderColor: [0, 0, 0, 1], + fill: LineFillStyle.solid, + join: LineJoinStyle.round, + cap: LineCapStyle.round, + }); + + scene.addObject({ + type: MapTileFeatureType.line, + id: 2, + color: [1, 0, 0, 1], + vertecies: [ + [width / 4, height / 4], + [-width / 4, -height / 4], + ], + width: 20, + borderWidth: 10, + borderColor: [0, 0, 0, 1], + fill: LineFillStyle.solid, + join: LineJoinStyle.round, + cap: LineCapStyle.round, + }); + + // scene.addObject({ + // type: MapTileFeatureType.line, + // id: 2, + // color: [1, 0, 0, 1], + // vertecies: [ + // [width / 4, -height / 4], + // [-width / 4, height / 4], + // ], + // width: 20, + // borderWidth: 10, + // borderColor: [0, 0, 0, 1], + // fill: LineFillStyle.solid, + // join: LineJoinStyle.round, + // cap: LineCapStyle.round, + // }); + + const sceneCamera = new WebGlSceneCamera(width, height, 0, 0, 1, 0); + + scene.render(sceneCamera); +} diff --git a/src/demo/webgl/webgl_point.ts b/src/demo/webgl/webgl_point.ts new file mode 100644 index 0000000..4ebac8d --- /dev/null +++ b/src/demo/webgl/webgl_point.ts @@ -0,0 +1,32 @@ +import { WebGlScene } from './webgl_scene'; +import { createRootEl } from '../demo_utils'; +import { ENABLED_FEATURE_FLAGS } from '../enabled_features'; +import { MapTileFeatureType } from '../../map/tile/tile'; +import { WebGlSceneCamera } from '../../map/renderer/webgl/webgl_camera'; + +export async function renderWebglPointExample() { + const rootEl = createRootEl(window.innerWidth, window.innerHeight, 10); + document.body.appendChild(rootEl); + + const scene = new WebGlScene(rootEl, ENABLED_FEATURE_FLAGS); + + await scene.init(); + + const width = scene.getWidth(); + const height = scene.getHeight(); + + scene.addObject({ + type: MapTileFeatureType.point, + id: 1, + color: [1.0, 0.0, 0.0, 1.0], + center: [0, 0], + radius: 10, + components: 128, + borderWidth: 2, + borderColor: [0.0, 0.0, 0.0, 1.0], + }); + + const sceneCamera = new WebGlSceneCamera(width, height, 0, 0, 1, 0); + + scene.render(sceneCamera); +} diff --git a/src/demo/webgl/webgl_scene.ts b/src/demo/webgl/webgl_scene.ts new file mode 100644 index 0000000..ee79065 --- /dev/null +++ b/src/demo/webgl/webgl_scene.ts @@ -0,0 +1,158 @@ +import { WebGlSceneCamera } from '../../map/renderer/webgl/webgl_camera'; +import { WebGlRenderer, WebGlRendererOptions } from '../../map/renderer/webgl/webgl_renderer'; +import { WebGlObject, WebGlObjectBufferredGroup } from '../../map/renderer/webgl/objects/object/object'; +import { MapFeatureFlags } from '../../map/flags'; +import { MapTileRendererType } from '../../map/renderer/renderer'; +import { FontManager } from '../../map/font/font_manager'; +import { GlyphsManager } from '../../map/glyphs/glyphs_manager'; +import { MapTileFeatureType } from '../../map/tile/tile'; +import { FontFormatType } from '../../map/font/font_config'; + +import { WebGlPoint } from '../../map/renderer/webgl/objects/point/point'; +import { WebGlPolygon } from '../../map/renderer/webgl/objects/polygon/polygon'; +import { WebGlLine } from '../../map/renderer/webgl/objects/line/line'; +import { WebGlImage } from '../../map/renderer/webgl/objects/image/image'; +import { WebGlGlyph } from '../../map/renderer/webgl/objects/glyph/glyph'; +import { WebGlText } from '../../map/renderer/webgl/objects/text/text'; + +import { ImageGroupBuilder } from '../../map/renderer/webgl/objects/image/image_group_builder'; +import { PointGroupBuilder } from '../../map/renderer/webgl/objects/point/point_builder'; +import { PolygonGroupBuilder } from '../../map/renderer/webgl/objects/polygon/polygon_builder'; +import { LineGroupBuilder } from '../../map/renderer/webgl/objects/line/line_builder'; +import { GlyphGroupBuilder } from '../../map/renderer/webgl/objects/glyph/glyph_group_builder'; +import { TextVectorBuilder } from '../../map/renderer/webgl/objects/text_vector/text_vector_builder'; +import { TextTextureGroupBuilder } from '../../map/renderer/webgl/objects/text_texture/text_texture_builder'; +import { LineShaiderBuilder } from '../../map/renderer/webgl/objects/line_shader/line_shader_builder'; + +export class WebGlScene { + private readonly renderer: WebGlRenderer; + private readonly fontManager: FontManager; + private readonly textureManager: GlyphsManager; + private readonly objects: WebGlObject[] = []; + private width: number; + private height: number; + + constructor( + private readonly htmlElement: HTMLElement, + private readonly featureFlags: MapFeatureFlags, + private readonly devicePixelRatio: number = window.devicePixelRatio + ) { + this.width = htmlElement.offsetWidth; + this.height = htmlElement.offsetHeight; + this.fontManager = new FontManager(featureFlags); + this.textureManager = new GlyphsManager(featureFlags); + + this.renderer = new WebGlRenderer( + htmlElement, + featureFlags, + MapTileRendererType.webgl2, + this.devicePixelRatio, + this.fontManager, + this.textureManager + ); + } + + async init() { + await Promise.all([this.fontManager.init(), this.textureManager.init()]).then(() => this.renderer.init()); + } + + resize(width: number, height: number) { + this.width = width; + this.height = height; + + this.renderer.resize(width, height); + } + + getWidth(): number { + return this.width; + } + + getHeight() { + return this.height; + } + + getWebglObjectGroups(camera: WebGlSceneCamera, objects: WebGlObject[]): WebGlObjectBufferredGroup[] { + const pointBuidler = new PointGroupBuilder(this.featureFlags, this.devicePixelRatio); + const polygonGroupBuilder = new PolygonGroupBuilder(this.featureFlags, this.devicePixelRatio); + const lineBuilder = this.featureFlags.webglRendererUseShaderLines + ? new LineShaiderBuilder(this.featureFlags, this.devicePixelRatio) + : new LineGroupBuilder(this.featureFlags, this.devicePixelRatio); + const glyphGroupBuilder = new GlyphGroupBuilder( + this.featureFlags, + this.devicePixelRatio, + this.textureManager.getMappingState() + ); + const textBuilder = + this.featureFlags.webglRendererFontFormatType === FontFormatType.vector + ? new TextVectorBuilder(this.featureFlags, this.devicePixelRatio, this.fontManager) + : new TextTextureGroupBuilder(this.featureFlags, this.devicePixelRatio, this.fontManager); + const imageGroupBuilder = new ImageGroupBuilder(this.featureFlags, this.devicePixelRatio); + + for (const obj of objects) { + switch (obj.type) { + case MapTileFeatureType.point: { + pointBuidler.addObject(obj as WebGlPoint); + continue; + } + case MapTileFeatureType.polygon: { + polygonGroupBuilder.addObject(obj as WebGlPolygon); + continue; + } + case MapTileFeatureType.line: { + lineBuilder.addObject(obj as WebGlLine); + continue; + } + case MapTileFeatureType.glyph: { + glyphGroupBuilder.addObject(obj as WebGlGlyph); + continue; + } + case MapTileFeatureType.text: { + textBuilder.addObject(obj as WebGlText); + continue; + } + case MapTileFeatureType.image: { + imageGroupBuilder.addObject(obj as WebGlImage); + continue; + } + } + } + + const objectGroups: WebGlObjectBufferredGroup[] = []; + + if (!pointBuidler.isEmpty()) { + objectGroups.push(pointBuidler.build(camera, 'points')); + } + + if (!polygonGroupBuilder.isEmpty()) { + objectGroups.push(polygonGroupBuilder.build(camera, 'polygons')); + } + + if (!lineBuilder.isEmpty()) { + objectGroups.push(lineBuilder.build(camera, 'lines')); + } + + if (!glyphGroupBuilder.isEmpty()) { + objectGroups.push(glyphGroupBuilder.build(camera, 'glyphs')); + } + + if (!textBuilder.isEmpty()) { + objectGroups.push(textBuilder.build(camera, 'texts')); + } + + if (!imageGroupBuilder.isEmpty()) { + objectGroups.push(imageGroupBuilder.build(camera, 'images')); + } + + return objectGroups; + } + + addObject(obj: T) { + this.objects.push(obj); + } + + render(camera: WebGlSceneCamera, renderOptions: WebGlRendererOptions = {}) { + const objectGroups = this.getWebglObjectGroups(camera, this.objects); + + this.renderer.render(objectGroups, camera, renderOptions); + } +} diff --git a/src/index.ts b/src/index.ts index 7fa7f64..c5d37f0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,24 @@ import { renderMap } from './demo/map_demo'; +import { renderWebglPointExample } from './demo/webgl/webgl_point'; +import { renderWebglLineExample } from './demo/webgl/webgl_line'; + +const ROUTE_MAP: Record void> = { + '/': () => { + renderMap(); + }, + '': () => { + renderMap(); + }, + '/webgl/point': () => { + renderWebglPointExample(); + }, + '/webgl/line': () => { + renderWebglLineExample(); + }, +}; window.addEventListener('load', () => { - renderMap(); + const route = window.location.hash.split('?')[0].slice(1); + + ROUTE_MAP[route](); }); diff --git a/src/map/flags.ts b/src/map/flags.ts index 0616b67..103cfd8 100644 --- a/src/map/flags.ts +++ b/src/map/flags.ts @@ -7,6 +7,9 @@ export interface MapFeatureFlags { /** Log all debug events of webgl rendrer. */ webglRendererDebug?: boolean; + /** Use new approach with shader lines. */ + webglRendererUseShaderLines?: boolean; + webglRendererFontFormatType?: FontFormatType; // Enables maps object selection behaviour. diff --git a/src/map/font/font_helper_sdf.ts b/src/map/font/font_helper_sdf.ts index f27adb1..f65a190 100644 --- a/src/map/font/font_helper_sdf.ts +++ b/src/map/font/font_helper_sdf.ts @@ -13,6 +13,7 @@ import { arrayBufferToImageBitmapTextureSource, arrayBufferToSharebleTextureSour export const DEFAULT_GLYPH_BORDER = 3; export const SDF_SCALE = 2; +export const SPACE_CHAR_CODE = ' '.charCodeAt(0); // https://github.com/mapbox/node-fontnik/blob/master/proto/glyphs.proto export enum SdfAtlasSourceProtobuf { @@ -61,8 +62,15 @@ export async function getFontAtlasFromSdfConfig( const url = config.sourceUrl.replace('{range}', `${range[0]}-${range[1]}`); return fetch(url) - .then(res => res.arrayBuffer()) - .then(arrayBuffer => populateSdfAtlasFromPbf(arrayBuffer, fontAtlas, config, ctx)); + .then(res => { + if (res.status === 200) { + return res.arrayBuffer(); + } + + throw new Error(res.statusText); + }) + .then(arrayBuffer => populateSdfAtlasFromPbf(arrayBuffer, fontAtlas, config, ctx)) + .catch(() => {}); }) ); } else { @@ -71,6 +79,24 @@ export async function getFontAtlasFromSdfConfig( .then(arrayBuffer => populateSdfAtlasFromPbf(arrayBuffer, fontAtlas, config, ctx)); } + if (!fontAtlas.glyphs[SPACE_CHAR_CODE]) { + // create SDF Glyph for space char. + fontAtlas.glyphs[SPACE_CHAR_CODE] = { + type: FontFormatType.sdf, + char: ' ', + charCode: SPACE_CHAR_CODE, + source: new Uint8ClampedArray(new Array(config.fontSize).map(i => 0)), + width: config.fontSize * 0.5, + height: 1, + x: 0, + y: 0, + actualBoundingBoxAscent: 0, + actualBoundingBoxDescent: 0, + fontSize: config.fontSize, + pixelRatio: config.pixelRatio || 1, + }; + } + const textureSource = await createTextureFromSdfGlyphs(fontAtlas, debugMode); fontAtlas.sources.push({ index: 0, source: textureSource, name: 'text' }); diff --git a/src/map/map.ts b/src/map/map.ts index fa48385..aa18e97 100644 --- a/src/map/map.ts +++ b/src/map/map.ts @@ -3,10 +3,10 @@ import { Evented } from './evented'; import { MapPan, MapPanEvents } from './pan/map_pan'; import { MapCamera } from './camera/map_camera'; import { Projection, ProjectionType, getProjectionFromType } from './geo/projection/projection'; -import { MapTileRendererType, Renderer } from './renderer/renderer'; +import { MapTileRendererType, MapTileRenderer } from './renderer/renderer'; import { RenderQueue } from './renderer/render_queue/render_queue'; import { TilesGrid, TilesGridEvent } from './tile/tile_grid'; -import { WebGlRenderer } from './renderer/webgl/webgl_renderer'; +import { WebGlMapTileRenderer } from './renderer/webgl/webgl_map_tile_renderer'; import { MapParentControl, MapControlPosition } from './controls/parent_control'; import { CompassControl } from './controls/compass_control'; import { ZoomControl } from './controls/zoom_control'; @@ -101,7 +101,7 @@ export class GlideMap extends Evented { private renderQueue: RenderQueue; private fontManager: FontManager; private glyphsManager: GlyphsManager; - private renderer: Renderer; + private renderer: MapTileRenderer; private projection: Projection; private mapOptions: MapOptions; private stats: Stats; @@ -129,7 +129,14 @@ export class GlideMap extends Evented { this.height = this.rootEl.offsetHeight; this.stats = new Stats(); - this.setup(this.featureFlags, this.mapOptions, this.mapOptions.tileStyles); + this.setup( + this.featureFlags, + this.mapOptions, + this.mapOptions.tileStyles, + this.mapOptions.center, + this.mapOptions.zoom, + this.mapOptions.rotation + ); this.init().then(() => { this.rerender(); }); @@ -167,7 +174,14 @@ export class GlideMap extends Evented { setStyles(mapStyle: DataTileStyles) { this.destroy(); - this.setup(this.featureFlags, this.mapOptions, mapStyle); + this.setup( + this.featureFlags, + this.mapOptions, + mapStyle, + this.projection.fromXY(this.camera.getPosition()), + this.camera.getZoom(), + this.camera.getRotation() + ); this.init().then(() => { this.rerender(); }); @@ -177,7 +191,14 @@ export class GlideMap extends Evented { return this.styles; } - private setup(featureFlags: MapFeatureFlags, mapOptions: MapOptions, styles: DataTileStyles) { + private setup( + featureFlags: MapFeatureFlags, + mapOptions: MapOptions, + styles: DataTileStyles, + center: [number, number], + zoom: number, + rotation: number + ) { this.minZoom = mapOptions.tileStyles.minzoom || 1; this.maxZoom = mapOptions.tileStyles.maxzoom || 15; this.pixelRatio = mapOptions.devicePixelRatio || window.devicePixelRatio; @@ -188,9 +209,9 @@ export class GlideMap extends Evented { this.projection = getProjectionFromType(mapOptions.projection); this.camera = new MapCamera( featureFlags, - this.projection.fromLngLat(mapOptions.center), - mapOptions.zoom, - mapOptions.rotation, + this.projection.fromLngLat(center), + zoom, + rotation, this.width, this.height, styles.tileSize, @@ -224,9 +245,12 @@ export class GlideMap extends Evented { const viewMatrix = this.camera.getProjectionMatrix(); const objectId = this.renderer.getObjectId( tiles, - viewMatrix, - zoom, - this.styles.tileSize, + { + viewMatrix: viewMatrix as [number, number, number, number, number, number, number, number, number], + distance: Math.pow(2, zoom) * this.styles.tileSize, + width: this.width, + height: this.height, + }, clippedWebGlSpaceCoords[0], clippedWebGlSpaceCoords[1] ); @@ -343,6 +367,15 @@ export class GlideMap extends Evented { return this.camera.getProjectionMatrix(); } + resize(width: number, height: number) { + this.width = width; + this.height = height; + + this.camera.resize(this.width, this.height); + this.renderer.resize(this.width, this.height); + this.render(); + } + rerender(pruneCache = false): Promise { const zoom = this.getZoom(); this.tilesGrid.updateTiles(this.camera, zoom, this.width, this.height); @@ -365,7 +398,16 @@ export class GlideMap extends Evented { const zoom = this.getZoom(); const viewMatrix = this.camera.getProjectionMatrix(); - this.renderer.render(tiles, viewMatrix, zoom, this.styles.tileSize, { pruneCache }); + this.renderer.render( + tiles, + { + viewMatrix: viewMatrix as [number, number, number, number, number, number, number, number, number], + distance: Math.pow(2, zoom) * this.styles.tileSize, + width: this.width, + height: this.height, + }, + { pruneCache } + ); this.statsWidget.style.display = 'none'; @@ -379,10 +421,10 @@ export class GlideMap extends Evented { } } - private getRenderer(rendererType: MapTileRendererType): Renderer { + private getRenderer(rendererType: MapTileRendererType): MapTileRenderer { switch (rendererType) { case MapTileRendererType.webgl: - return new WebGlRenderer( + return new WebGlMapTileRenderer( this.rootEl, this.featureFlags, MapTileRendererType.webgl, @@ -391,7 +433,7 @@ export class GlideMap extends Evented { this.glyphsManager ); case MapTileRendererType.webgl2: - return new WebGlRenderer( + return new WebGlMapTileRenderer( this.rootEl, this.featureFlags, MapTileRendererType.webgl2, diff --git a/src/map/renderer/renderer.ts b/src/map/renderer/renderer.ts index 9302258..d4e67c5 100644 --- a/src/map/renderer/renderer.ts +++ b/src/map/renderer/renderer.ts @@ -1,4 +1,3 @@ -import { mat3 } from 'gl-matrix'; import { MapTile } from '../tile/tile'; export enum MapTileRendererType { @@ -9,31 +8,23 @@ export enum MapTileRendererType { // webgpu = 'webgpu', } -export interface MapStyles { - disabledLayers?: string[]; - layers: Record; +export interface SceneCamera { + readonly width: number; + readonly height: number; + readonly distance: number; + readonly viewMatrix: [number, number, number, number, number, number, number, number, number]; } -export interface RenderOptions { - pruneCache?: boolean; - readPixelRenderMode?: boolean; -} +export interface RenderOptions {} -export interface Renderer { +export interface MapTileRenderer { init(): Promise; destroy(): void; resize(width: number, height: number): void; - render(tiles: MapTile[], viewMatrix: mat3, zoom: number, tileSize: number, renderOptions?: RenderOptions): void; + render(tiles: MapTile[], camera: SceneCamera, renderOptions?: RenderOptions): void; - getObjectId( - tiles: MapTile[], - viewMatrix: mat3, - zoom: number, - tileSize: number, - x: number, - y: number - ): number | undefined; + getObjectId(tiles: MapTile[], camera: SceneCamera, x: number, y: number): number | undefined; } diff --git a/src/map/renderer/webgl/objects/glyph/glyph_group_builder.ts b/src/map/renderer/webgl/objects/glyph/glyph_group_builder.ts index 747a4cb..deb44e1 100644 --- a/src/map/renderer/webgl/objects/glyph/glyph_group_builder.ts +++ b/src/map/renderer/webgl/objects/glyph/glyph_group_builder.ts @@ -1,10 +1,9 @@ -import { mat3 } from 'gl-matrix'; import { WebGlGlyph, WebGlGlyphBufferredGroup } from './glyph'; import { WebGlObjectAttributeType } from '../object/object'; +import { SceneCamera } from '../../../renderer'; import { ObjectGroupBuilder } from '../object/object_group_builder'; import { GlyphsManagerMappingState } from '../../../../glyphs/glyphs_manager'; import { MapTileFeatureType } from '../../../../tile/tile'; -import { Projection } from '../../../../geo/projection/projection'; import { MapFeatureFlags } from '../../../../flags'; import { createdSharedArrayBuffer } from '../../utils/array_buffer'; import { integerToVector4 } from '../../utils/number2vec'; @@ -13,40 +12,17 @@ const TRANSPARENT_COLOR = [0, 0, 0, 0]; export class GlyphGroupBuilder extends ObjectGroupBuilder { constructor( - protected readonly projectionViewMat: mat3, - protected readonly canvasWidth: number, - protected readonly canvasHeight: number, - protected readonly pixelRatio: number, - protected readonly zoom: number, - protected readonly minZoom: number, - protected readonly maxZoom: number, - protected readonly tileSize: number, - protected readonly projection: Projection, protected readonly featureFlags: MapFeatureFlags, + protected readonly pixelRatio: number, private readonly glyphTextureMapping: GlyphsManagerMappingState ) { - super( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); - } - - addObject(glyph: WebGlGlyph): void { - this.objects.push([glyph, 0]); + super(featureFlags, pixelRatio); } - build(): WebGlGlyphBufferredGroup { + build(camera: SceneCamera, name: string, zIndex = 0): WebGlGlyphBufferredGroup { let textureAtlasName: string; const filteredGlyphs: WebGlGlyph[] = []; - for (const [glyph] of this.objects) { + for (const glyph of this.objects) { textureAtlasName = glyph.atlas; const textureAtlas = this.glyphTextureMapping[glyph.atlas]; const glyphMapping = textureAtlas.mapping[glyph.name]; @@ -72,12 +48,12 @@ export class GlyphGroupBuilder extends ObjectGroupBuilder { const textureWidth = textureAtlas.width; const textureHeight = textureAtlas.height; - const glyphScaledWidth = this.scalarScale(glyphMapping.width / glyphMapping.pixelRatio); - const glyphScaledHeight = this.scalarScale(glyphMapping.height / glyphMapping.pixelRatio); - const marginTop = this.scalarScale((glyph.margin?.top || 0) / this.pixelRatio); - const marginLeft = this.scalarScale((glyph.margin?.left || 0) / this.pixelRatio); + const glyphScaledWidth = this.scalarScale(glyphMapping.width / glyphMapping.pixelRatio, camera.distance); + const glyphScaledHeight = this.scalarScale(glyphMapping.height / glyphMapping.pixelRatio, camera.distance); + const marginTop = this.scalarScale((glyph.margin?.top || 0) / this.pixelRatio, camera.distance); + const marginLeft = this.scalarScale((glyph.margin?.left || 0) / this.pixelRatio, camera.distance); - let [x1, y1] = this.projection.fromLngLat([glyph.center[0], glyph.center[1]]); + let [x1, y1] = [glyph.center[0], glyph.center[1]]; x1 = x1 - glyphScaledWidth / 2 + marginTop; y1 = y1 - glyphScaledHeight / 2 + marginLeft; const x2 = x1 + glyphScaledWidth; @@ -109,6 +85,8 @@ export class GlyphGroupBuilder extends ObjectGroupBuilder { return { type: MapTileFeatureType.glyph, + name, + zIndex, size, numElements: verteciesBuffer.length / 2, atlas: textureAtlasName, diff --git a/src/map/renderer/webgl/objects/glyph/glyph_shaders.ts b/src/map/renderer/webgl/objects/glyph/glyph_shaders.ts index 3ef1781..725384e 100644 --- a/src/map/renderer/webgl/objects/glyph/glyph_shaders.ts +++ b/src/map/renderer/webgl/objects/glyph/glyph_shaders.ts @@ -1,18 +1,15 @@ -import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS, MERCATOR_PROJECTION_UTILS } from '../object/object_shaders'; +import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} ${FEATURE_FLAGS_UTILS} uniform mat3 u_matrix; - uniform float u_zoom; uniform float u_width; uniform float u_height; - uniform float u_tile_size; attribute vec2 a_position; attribute vec2 a_texCoord; diff --git a/src/map/renderer/webgl/objects/image/image_group_builder.ts b/src/map/renderer/webgl/objects/image/image_group_builder.ts index c4a79ae..976032a 100644 --- a/src/map/renderer/webgl/objects/image/image_group_builder.ts +++ b/src/map/renderer/webgl/objects/image/image_group_builder.ts @@ -1,18 +1,14 @@ import { WebGlObjectAttributeType } from '../object/object'; +import { SceneCamera } from '../../../renderer'; import { ObjectGroupBuilder } from '../object/object_group_builder'; import { integerToVector4 } from '../../utils/number2vec'; import { MapTileFeatureType } from '../../../../tile/tile'; import { WebGlImage, WebGlImageBufferredGroup } from './image'; import { createdSharedArrayBuffer } from '../../utils/array_buffer'; -import { TextureSourceType } from '../../../../texture/texture'; const TRANSPARENT_COLOR = [0, 0, 0, 0]; export class ImageGroupBuilder extends ObjectGroupBuilder { - addObject(image: WebGlImage): void { - this.objects.push([image, 0]); - } - - build(): WebGlImageBufferredGroup { + build(camera: SceneCamera, name: string, zIndex = 0): WebGlImageBufferredGroup { const verteciesBuffer: number[] = []; const texcoordBuffer: number[] = []; const colorBuffer: number[] = []; @@ -23,17 +19,17 @@ export class ImageGroupBuilder extends ObjectGroupBuilder { let textureWidth: number; let textureHeight: number; - for (const [image] of this.objects) { + for (const image of this.objects) { const colorId = integerToVector4(image.id); textureSource = image.source; textureWidth = image.width * image.pixelRatio; textureHeight = image.height * image.pixelRatio; - const marginTop = this.scalarScale((image.margin?.top || 0) / this.pixelRatio); - const marginLeft = this.scalarScale((image.margin?.left || 0) / this.pixelRatio); + const marginTop = this.scalarScale((image.margin?.top || 0) / this.pixelRatio, camera.distance); + const marginLeft = this.scalarScale((image.margin?.left || 0) / this.pixelRatio, camera.distance); - let [x1, y1] = this.projection.fromLngLat([image.bbox[0][0], image.bbox[0][1]]); - let [x4, y4] = this.projection.fromLngLat([image.bbox[1][0], image.bbox[1][1]]); + let [x1, y1] = [image.bbox[0][0], image.bbox[0][1]]; + let [x4, y4] = [image.bbox[1][0], image.bbox[1][1]]; x1 = x1 + marginLeft; y1 = y1 + marginTop; x4 = x4 + marginLeft; @@ -60,6 +56,8 @@ export class ImageGroupBuilder extends ObjectGroupBuilder { return { type: MapTileFeatureType.image, + name, + zIndex, size, numElements: verteciesBuffer.length / 2, texture: textureSource, diff --git a/src/map/renderer/webgl/objects/image/image_shader.ts b/src/map/renderer/webgl/objects/image/image_shader.ts index 3ef1781..725384e 100644 --- a/src/map/renderer/webgl/objects/image/image_shader.ts +++ b/src/map/renderer/webgl/objects/image/image_shader.ts @@ -1,18 +1,15 @@ -import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS, MERCATOR_PROJECTION_UTILS } from '../object/object_shaders'; +import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} ${FEATURE_FLAGS_UTILS} uniform mat3 u_matrix; - uniform float u_zoom; uniform float u_width; uniform float u_height; - uniform float u_tile_size; attribute vec2 a_position; attribute vec2 a_texCoord; diff --git a/src/map/renderer/webgl/objects/line/line.ts b/src/map/renderer/webgl/objects/line/line.ts index 44f2237..d422fa0 100644 --- a/src/map/renderer/webgl/objects/line/line.ts +++ b/src/map/renderer/webgl/objects/line/line.ts @@ -9,23 +9,23 @@ import { // checkout https://wwwtyro.net/2019/11/18/instanced-lines.html export enum LineJoinStyle { - miter = 'miter', - round = 'round', - bevel = 'bevel', + miter = 0, + round = 1, + bevel = 2, } // checkout https://wwwtyro.net/2019/11/18/instanced-lines.html export enum LineCapStyle { - butt = 'butt', - round = 'round', - square = 'square', + butt = 0, + round = 1, + square = 2, } export enum LineFillStyle { - solid = 'solid', - dashed = 'dashed', - dotted = 'dotted', - dotdashed = 'dotdashed', + solid = 0, + dashed = 1, + dotted = 2, + dotdashed = 3, } export interface WebGlLine extends WebGlObject { @@ -34,8 +34,6 @@ export interface WebGlLine extends WebGlObject { color: vec4; width: number; vertecies: Array; - // vertecies: Array>; - // TODO: support this fill: LineFillStyle; join: LineJoinStyle; diff --git a/src/map/renderer/webgl/objects/line/line_builder.ts b/src/map/renderer/webgl/objects/line/line_builder.ts index 4574175..ea76bcc 100644 --- a/src/map/renderer/webgl/objects/line/line_builder.ts +++ b/src/map/renderer/webgl/objects/line/line_builder.ts @@ -1,10 +1,12 @@ import { vec2 } from 'gl-matrix'; import { WebGlObjectAttributeType } from '../object/object'; +import { SceneCamera } from '../../../renderer'; import { ObjectGroupBuilder } from '../object/object_group_builder'; import { LineJoinStyle, WebGlLine, WebGlLineBufferredGroup } from './line'; import { MapTileFeatureType } from '../../../../tile/tile'; import { createdSharedArrayBuffer } from '../../utils/array_buffer'; import { integerToVector4 } from '../../utils/number2vec'; +import { addXTimes } from '../../utils/array_utils'; const LINE_POSITION: Array<[number, number]> = [ [0, -0.5], @@ -67,42 +69,36 @@ const ROUND_JOIN_POSITION: Array<[number, number]> = [ ]; export class LineGroupBuilder extends ObjectGroupBuilder { - addObject(line: WebGlLine) { - const objectSize = this.verticesFromLine(this.vertecies, line.vertecies, line.width, line.join); - - this.objects.push([line, objectSize]); - } - - build(): WebGlLineBufferredGroup { - const numElements = this.vertecies.length / 2; + build(camera: SceneCamera, name: string, zIndex = 0): WebGlLineBufferredGroup { + const vertecies: number[] = []; const colorBuffer: number[] = []; const widthBuffer: number[] = []; const borderWidthBuffer: number[] = []; const borderColorBuffer: number[] = []; const selectionColorBuffer: number[] = []; - let currentObjectIndex = 0; - let currentObject: WebGlLine = this.objects[currentObjectIndex][0]; - let currentOffset = this.objects[currentObjectIndex][1]; - - for (let i = 0; i < numElements; i++) { - if (i > currentOffset) { - currentObjectIndex++; - currentObject = this.objects[currentObjectIndex][0]; - currentOffset += this.objects[currentObjectIndex][1]; - } + for (const line of this.objects) { + const numberOfAddedVertecies = this.verticesFromLine(camera, vertecies, line.vertecies, line.width, line.join); + const xTimes = numberOfAddedVertecies / 2; - colorBuffer.push(...(currentObject.color || [0, 0, 0, 1])); - widthBuffer.push(currentObject.width); - borderWidthBuffer.push(currentObject.borderWidth); - borderColorBuffer.push(...currentObject.borderColor); - selectionColorBuffer.push(...integerToVector4(currentObject.id)); + addXTimes(colorBuffer, [...line.color], xTimes); + addXTimes(widthBuffer, line.width, xTimes); + addXTimes(borderWidthBuffer, line.borderWidth, xTimes); + addXTimes(borderColorBuffer, [...line.borderColor], xTimes); + addXTimes(selectionColorBuffer, integerToVector4(line.id), xTimes); } return { type: MapTileFeatureType.line, + name, + zIndex, size: this.objects.length, - numElements, + numElements: vertecies.length / 2, + vertecies: { + type: WebGlObjectAttributeType.FLOAT, + size: 3, + buffer: createdSharedArrayBuffer(vertecies), + }, color: { type: WebGlObjectAttributeType.FLOAT, size: 4, @@ -113,11 +109,6 @@ export class LineGroupBuilder extends ObjectGroupBuilder { size: 1, buffer: createdSharedArrayBuffer(widthBuffer), }, - vertecies: { - type: WebGlObjectAttributeType.FLOAT, - size: 3, - buffer: createdSharedArrayBuffer(this.vertecies), - }, borderWidth: { type: WebGlObjectAttributeType.FLOAT, size: 1, @@ -137,6 +128,7 @@ export class LineGroupBuilder extends ObjectGroupBuilder { } verticesFromLine( + camera: SceneCamera, result: number[], coordinates: Array<[number, number] | vec2>, lineWidth: number, @@ -144,22 +136,28 @@ export class LineGroupBuilder extends ObjectGroupBuilder { ): number { const start = result.length; - this.lineToTriangles(result, coordinates[0], coordinates[1], lineWidth); + this.lineToTriangles(camera, result, coordinates[0], coordinates[1], lineWidth); for (let i = 2; i < coordinates.length; i++) { if (joinStyle === LineJoinStyle.round) { - this.roundJoinToTriangles(result, coordinates[i - 1], lineWidth); + this.roundJoinToTriangles(camera, result, coordinates[i - 1], lineWidth); } - this.lineToTriangles(result, coordinates[i - 1], coordinates[i], lineWidth); + this.lineToTriangles(camera, result, coordinates[i - 1], coordinates[i], lineWidth); } return result.length - start; } - lineToTriangles(result: number[], p1: [number, number] | vec2, p2: [number, number] | vec2, lineWidth: number) { - const scaledLineWidth = this.scalarScale(lineWidth); - const p1Projected = vec2.fromValues(...this.projection.fromLngLat(p1)); - const p2Projected = vec2.fromValues(...this.projection.fromLngLat(p2)); + lineToTriangles( + camera: SceneCamera, + result: number[], + p1: [number, number] | vec2, + p2: [number, number] | vec2, + lineWidth: number + ) { + const scaledLineWidth = this.scalarScale(lineWidth, camera.distance); + const p1Projected = vec2.fromValues(p1[0], p1[1]); + const p2Projected = vec2.fromValues(p2[0], p2[1]); const xBasis = vec2.create(); vec2.subtract(xBasis, p2Projected, p1Projected); @@ -181,9 +179,15 @@ export class LineGroupBuilder extends ObjectGroupBuilder { } } - roundJoinToTriangles(result: number[], center: [number, number] | vec2, lineWidth: number, componets = 16) { - const scaledLineWidth = this.scalarScale(lineWidth); - const centerVec = vec2.fromValues(...this.projection.fromLngLat(center)); + roundJoinToTriangles( + camera: SceneCamera, + result: number[], + center: [number, number] | vec2, + lineWidth: number, + componets = 16 + ) { + const scaledLineWidth = this.scalarScale(lineWidth, camera.distance); + const centerVec = vec2.fromValues(center[0], center[1]); for (const pos of ROUND_JOIN_POSITION) { const res = vec2.create(); diff --git a/src/map/renderer/webgl/objects/line/line_shaders.ts b/src/map/renderer/webgl/objects/line/line_shaders.ts index 95e47b0..0e9b24a 100644 --- a/src/map/renderer/webgl/objects/line/line_shaders.ts +++ b/src/map/renderer/webgl/objects/line/line_shaders.ts @@ -1,24 +1,15 @@ -import { - FEATURE_FLAGS_UTILS, - DEFAULT_FRAGMENT_SHADER_SOURCE, - CLIP_UTILS, - MAT_UTILS, - MERCATOR_PROJECTION_UTILS, -} from '../object/object_shaders'; +import { FEATURE_FLAGS_UTILS, DEFAULT_FRAGMENT_SHADER_SOURCE, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} ${FEATURE_FLAGS_UTILS} uniform mat3 u_matrix; - uniform float u_zoom; uniform float u_width; uniform float u_height; - uniform float u_tile_size; attribute vec2 point_a; attribute vec4 a_color; diff --git a/src/map/renderer/webgl/objects/line_shader/line.ts b/src/map/renderer/webgl/objects/line_shader/line.ts new file mode 100644 index 0000000..0799548 --- /dev/null +++ b/src/map/renderer/webgl/objects/line_shader/line.ts @@ -0,0 +1,20 @@ +import { MapTileFeatureType } from '../../../../tile/tile'; +import { WebGlObjectBufferredGroup, WebGlObjectAttributeDescriptor, WebGlObjectAttributeType } from '../object/object'; + +export interface WebGlShaderLineBufferredGroup extends WebGlObjectBufferredGroup { + type: MapTileFeatureType.line; + size: number; // group size | number of instances; + numElements: number; // number of elements + vertecies: WebGlObjectAttributeDescriptor; // Array; + + prevPoint: WebGlObjectAttributeDescriptor; // Array; + currPoint: WebGlObjectAttributeDescriptor; // Array; + nextPoint: WebGlObjectAttributeDescriptor; // Array; + // angle, width, borderWidth, + lineProps: WebGlObjectAttributeDescriptor; // Array; + // [fillType, capType, joinType] + renderStyles: WebGlObjectAttributeDescriptor; // Array; + color: WebGlObjectAttributeDescriptor; // Array; + borderColor: WebGlObjectAttributeDescriptor; // Array; + selectionColor: WebGlObjectAttributeDescriptor; // Array; +} diff --git a/src/map/renderer/webgl/objects/line_shader/line_shader_builder.ts b/src/map/renderer/webgl/objects/line_shader/line_shader_builder.ts new file mode 100644 index 0000000..5f8e0a4 --- /dev/null +++ b/src/map/renderer/webgl/objects/line_shader/line_shader_builder.ts @@ -0,0 +1,192 @@ +import { vec2 } from 'gl-matrix'; +import { WebGlObjectAttributeType } from '../object/object'; +import { SceneCamera } from '../../../renderer'; +import { ObjectGroupBuilder } from '../object/object_group_builder'; +import { LineJoinStyle, WebGlLine } from '../line/line'; +import { WebGlShaderLineBufferredGroup } from './line'; +import { MapTileFeatureType } from '../../../../tile/tile'; +import { createdSharedArrayBuffer } from '../../utils/array_buffer'; +import { integerToVector4 } from '../../utils/number2vec'; +import { addXTimes } from '../../utils/array_utils'; + +const getBbox = (p1: [number, number] | vec2, p2: [number, number] | vec2): [number, number, number, number] => { + const minX = Math.min(p1[0], p2[0]); + const minY = Math.min(p1[1], p2[1]); + const maxX = Math.max(p1[0], p2[0]); + const maxY = Math.max(p1[1], p2[1]); + + return [minX, minY, maxX, maxY]; +}; + +export class LineShaiderBuilder extends ObjectGroupBuilder { + build(camera: SceneCamera, name: string, zIndex = 0): WebGlShaderLineBufferredGroup { + const vertecies: number[] = []; + const prevPoint: number[] = []; + const currPoint: number[] = []; + const nextPoint: number[] = []; + // angle, width, borderWidth, + const lineProps: number[] = []; + // fill, cap, join + const renderStyles: number[] = []; + const color: number[] = []; + const borderColor: number[] = []; + const selectionColor: number[] = []; + + for (const line of this.objects) { + const halfWidth = + (this.scalarScale(line.borderWidth, camera.distance) + this.scalarScale(line.width, camera.distance)) / 2; + const idAsVector4 = integerToVector4(line.id); + + for (let i = 1; i < line.vertecies.length; i++) { + const aPoint = line.vertecies[i - 1]; + const bPoint = line.vertecies[i]; + const cPoint = i + 1 === line.vertecies.length ? line.vertecies[i] : line.vertecies[i + 1]; + const [minx, miny, maxx, maxy] = getBbox(aPoint, bPoint); + + const x1 = minx - halfWidth; + const y1 = maxy + halfWidth; + + const x2 = maxx + halfWidth; + const y2 = maxy + halfWidth; + + const x3 = minx - halfWidth; + const y3 = miny - halfWidth; + + const x4 = maxx + halfWidth; + const y4 = miny - halfWidth; + + vertecies.push( + // first triangle + x1, + y1, + x2, + y2, + x3, + y3, + // second triangle + x3, + y3, + x2, + y2, + x4, + y4 + ); + + addXTimes(prevPoint, [aPoint[0], aPoint[1]], 6); + addXTimes(currPoint, [bPoint[0], bPoint[1]], 6); + addXTimes(nextPoint, [cPoint[0], cPoint[1]], 6); + addXTimes(lineProps, [0, line.width, line.borderWidth], 6); + addXTimes(renderStyles, [line.fill, line.cap, line.join], 6); + addXTimes(color, [line.color[0], line.color[1], line.color[2], line.color[3]], 6); + addXTimes(borderColor, [line.borderColor[0], line.borderColor[1], line.borderColor[2], line.borderColor[3]], 6); + addXTimes(selectionColor, idAsVector4, 6); + } + } + + return { + type: MapTileFeatureType.line, + name, + zIndex, + size: this.objects.length, + numElements: vertecies.length / 2, + vertecies: { + type: WebGlObjectAttributeType.FLOAT, + size: 2, + buffer: createdSharedArrayBuffer(vertecies), + }, + prevPoint: { + type: WebGlObjectAttributeType.FLOAT, + size: 2, + buffer: createdSharedArrayBuffer(prevPoint), + }, + currPoint: { + type: WebGlObjectAttributeType.FLOAT, + size: 2, + buffer: createdSharedArrayBuffer(currPoint), + }, + nextPoint: { + type: WebGlObjectAttributeType.FLOAT, + size: 2, + buffer: createdSharedArrayBuffer(nextPoint), + }, + lineProps: { + type: WebGlObjectAttributeType.FLOAT, + size: 3, + buffer: createdSharedArrayBuffer(lineProps), + }, + renderStyles: { + type: WebGlObjectAttributeType.FLOAT, + size: 3, + buffer: createdSharedArrayBuffer(renderStyles), + }, + color: { + type: WebGlObjectAttributeType.FLOAT, + size: 4, + buffer: createdSharedArrayBuffer(color), + }, + borderColor: { + type: WebGlObjectAttributeType.FLOAT, + size: 4, + buffer: createdSharedArrayBuffer(borderColor), + }, + selectionColor: { + type: WebGlObjectAttributeType.FLOAT, + size: 4, + buffer: createdSharedArrayBuffer(selectionColor), + }, + }; + } + + getDistanceBetweenPoints(p1: [number, number], p2: [number, number]): number { + return Math.sqrt(Math.pow(p2[0] - p1[0], 2.0) + Math.pow(p2[1] - p1[1], 2.0)); + } + + getPointAlignmentToLine(lineEquation: [number, number], point: [number, number]): number { + const k = lineEquation[0]; + const b = lineEquation[1]; + // creating line start (a) and end (b) points based on k and b. + const lA = [-1.0, -k + b]; + const lB = [1.0, k + b]; + + return (lB[0] - lA[0]) * (point[1] - lA[1]) - (lB[1] - lA[1]) * (point[0] - lA[0]); + } + + // returns k and b -> y = kx + b; + getLineEquation(p1: [number, number], p2: [number, number]): [number, number] { + const k = (p1[1] - p2[1]) / (p1[0] - p2[0]); + const b = p1[1] - k * p1[1]; + + return [k, b]; + } + + getPerpendicularLineEquation(lineEquation: [number, number], point: [number, number]): [number, number] { + const k1 = lineEquation[0]; + const k2 = -1.0 / k1; + const b2 = point[1] - k2 * point[0]; + + return [k2, b2]; + } + + getDistanceFromLine(lineEquation: [number, number], point: [number, number]): number { + const perpendicular = this.getPerpendicularLineEquation(lineEquation, point); + const k1 = lineEquation[0]; + const b1 = lineEquation[1]; + const k2 = perpendicular[0]; + const b2 = perpendicular[1]; + + // intersection point + const x = (b2 - b1) / (k1 - k2); + const y = k2 * x + b2; + + return this.getDistanceBetweenPoints(point, [x, y]); + } + + getPointFromPerpendicular( + lineEquation: [number, number], + linePoint: [number, number], + distance: number + ): [number, number] { + const angle = Math.PI / 2; + return [linePoint[0] + distance * Math.cos(angle), linePoint[1] + distance * Math.sin(angle)]; + } +} diff --git a/src/map/renderer/webgl/objects/line_shader/line_shader_program.ts b/src/map/renderer/webgl/objects/line_shader/line_shader_program.ts new file mode 100644 index 0000000..490aa26 --- /dev/null +++ b/src/map/renderer/webgl/objects/line_shader/line_shader_program.ts @@ -0,0 +1,90 @@ +import { WebGlShaderLineBufferredGroup } from './line'; +import ShaderLineShaders from './line_shader_shaders'; +import { ObjectProgram, DrawObjectGroupOptions } from '../object/object_program'; +import { ExtendedWebGLRenderingContext } from '../../webgl_context'; +import { MapFeatureFlags } from '../../../../flags'; +import { WebGlBuffer, createWebGlBuffer } from '../../utils/webgl_buffer'; + +export class LineShaderProgram extends ObjectProgram { + protected vertecies: WebGlBuffer; + protected prevPoint: WebGlBuffer; + protected currPoint: WebGlBuffer; + protected nextPoint: WebGlBuffer; + protected lineProps: WebGlBuffer; + protected renderStyles: WebGlBuffer; + protected color: WebGlBuffer; + protected borderColor: WebGlBuffer; + + protected u_renderType: WebGLUniformLocation; + + protected vao: WebGLVertexArrayObjectOES; + + constructor( + protected readonly gl: ExtendedWebGLRenderingContext, + protected readonly featureFlags: MapFeatureFlags, + protected readonly vertexShaderSource: string = ShaderLineShaders.vertext, + protected readonly fragmentShaderSource: string = ShaderLineShaders.fragment + ) { + super(gl, featureFlags, vertexShaderSource, fragmentShaderSource); + } + + protected setupBuffer(): void { + const gl = this.gl; + + this.gl.bindVertexArray(this.vao); + + this.vertecies = createWebGlBuffer(gl, { location: 0, size: 2 }); + this.prevPoint = createWebGlBuffer(gl, { location: 1, size: 2 }); + this.currPoint = createWebGlBuffer(gl, { location: 2, size: 2 }); + this.nextPoint = createWebGlBuffer(gl, { location: 3, size: 2 }); + this.lineProps = createWebGlBuffer(gl, { location: 4, size: 3 }); + this.renderStyles = createWebGlBuffer(gl, { location: 5, size: 3 }); + this.color = createWebGlBuffer(gl, { location: 6, size: 4 }); + this.borderColor = createWebGlBuffer(gl, { location: 7, size: 4 }); + + this.gl.bindVertexArray(null); + } + + public async onInit(): Promise {} + + public onLink(): void { + const gl = this.gl; + + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + } + + public onUnlink() { + const gl = this.gl; + + gl.disable(gl.BLEND); + } + + protected setupUniforms() { + super.setupUniforms(); + this.u_renderType = this.gl.getUniformLocation(this.program, 'u_renderType'); + } + + drawObjectGroup(lineGroup: WebGlShaderLineBufferredGroup, options?: DrawObjectGroupOptions) { + const gl = this.gl; + + gl.bindVertexArray(this.vao); + + this.vertecies.bufferData(lineGroup.vertecies.buffer); + this.prevPoint.bufferData(lineGroup.prevPoint.buffer); + this.currPoint.bufferData(lineGroup.currPoint.buffer); + this.nextPoint.bufferData(lineGroup.nextPoint.buffer); + this.lineProps.bufferData(lineGroup.lineProps.buffer); + this.renderStyles.bufferData(lineGroup.renderStyles.buffer); + this.color.bufferData(options?.readPixelRenderMode ? lineGroup.selectionColor.buffer : lineGroup.color.buffer); + this.borderColor.bufferData( + options?.readPixelRenderMode ? lineGroup.selectionColor.buffer : lineGroup.borderColor.buffer + ); + + // draw line + gl.uniform1f(this.u_renderType, 0); + gl.drawArrays(gl.TRIANGLES, 0, lineGroup.numElements); + + gl.bindVertexArray(null); + } +} diff --git a/src/map/renderer/webgl/objects/line_shader/line_shader_shaders.ts b/src/map/renderer/webgl/objects/line_shader/line_shader_shaders.ts new file mode 100644 index 0000000..ea8ea5f --- /dev/null +++ b/src/map/renderer/webgl/objects/line_shader/line_shader_shaders.ts @@ -0,0 +1,174 @@ +import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; + +export default { + vertext: ` + precision highp float; + ${CLIP_UTILS} + ${MAT_UTILS} + ${FEATURE_FLAGS_UTILS} + + uniform mat3 u_matrix; + uniform float u_width; + uniform float u_height; + uniform float u_tile_size; + uniform float u_renderType; + + attribute vec2 a_vertecies; + attribute vec2 a_prevPoint; + attribute vec2 a_currPoint; + attribute vec2 a_nextPoint; + attribute vec3 a_lineProps; + attribute vec3 a_renderStyles; + attribute vec4 a_color; + attribute vec4 a_borderColor; + attribute vec2 a_lineStripVertecies; + attribute vec2 a_pointVertecies; + + // varying vec2 v_vertecies; + varying vec2 v_prevPoint; + varying vec2 v_currPoint; + varying vec2 v_nextPoint; + varying vec3 v_lineProps; + varying vec3 v_renderStyles; + varying vec4 v_color; + varying vec4 v_borderColor; + varying vec2 v_point; + + void main() { + v_prevPoint = applyMatrix(u_matrix, clipSpace(a_prevPoint)); + v_currPoint = applyMatrix(u_matrix, clipSpace(a_currPoint)); + v_nextPoint = applyMatrix(u_matrix, clipSpace(a_nextPoint)); + v_lineProps = a_lineProps; + v_renderStyles = a_renderStyles; + v_color = a_color; + v_borderColor = a_borderColor; + + gl_Position = vec4(applyMatrix(u_matrix, clipSpace(a_vertecies.xy)), 0, 1); + v_point = gl_Position.xy / gl_Position.w; + } + `, + fragment: ` + precision highp float; + + uniform mat3 u_matrix; + uniform float u_width; + uniform float u_height; + uniform float u_tile_size; + uniform float u_renderType; + + // varying vec2 v_vertecies; + varying vec2 v_prevPoint; + varying vec2 v_currPoint; + varying vec2 v_nextPoint; + varying vec3 v_lineProps; // [angleDegree, line.width, line.borderWidth] + varying vec3 v_renderStyles; // [line.fill, line.cap, line.join] + varying vec4 v_color; + varying vec4 v_borderColor; + varying vec2 v_point; + + float getPointAlignmentToLine(vec2 lineEquation, vec2 point) { + float k = lineEquation.x; + float b = lineEquation.y; + // creating line start (a) and end (b) points based on k and b. + vec2 lA = vec2(-1.0, -k + b); + vec2 lB = vec2(1.0, k + b); + + return (lB.x - lA.x) * (point.y - lA.y) - (lB.y - lA.y) * (point.x - lA.x); + } + + // returns k and b -> y = kx + b; + vec2 getLineEquation(vec2 p1, vec2 p2) { + float k = (p1.y - p2.y) / (p1.x - p2.x); + float b = p1.y - k * p1.x; + + return vec2(k, b); + } + + vec2 getPerpendicularLineEquation(vec2 lineEquation, vec2 point) { + float k1 = lineEquation.x; + float k2 = -1.0 / k1; + float b2 = point.y - k2 * point.x; + + return vec2(k2, b2); + } + + float getDistanceFromLine(vec2 lineEquation, vec2 point) { + vec2 perpendicular = getPerpendicularLineEquation(lineEquation, point); + float k1 = lineEquation.x; + float b1 = lineEquation.y; + float k2 = perpendicular.x; + float b2 = perpendicular.y; + + // intersection point + float x = (b2 - b1) / (k1 - k2); + float y = k2 * x + b2; + + return length(point - vec2(x, y)); + } + + bool belongToLine(vec2 lineEquation, float lineWidth, vec2 point) { + return getDistanceFromLine(lineEquation, point) <= lineWidth; + } + + void main() { + vec2 resolution = vec2(u_width, u_height); + vec2 point = (gl_FragCoord.xy / resolution) - 1.0; + float lineWidth = v_lineProps.y / u_width / 2.0; + float borderWidth = v_lineProps.z / u_width / 2.0; + + vec2 lineEquation = getLineEquation(v_prevPoint, v_currPoint); + vec2 perpendicularLeftLineEquation = getPerpendicularLineEquation(lineEquation, v_prevPoint); + vec2 perpendicularRightLineEquation = getPerpendicularLineEquation(lineEquation, v_currPoint); + float pointAlignmentForLeftEdge = getPointAlignmentToLine(perpendicularLeftLineEquation, point); + float pointAlignmentForRightEdge = getPointAlignmentToLine(perpendicularRightLineEquation, point); + bool isLeftCap = pointAlignmentForLeftEdge <= 0.0 && pointAlignmentForRightEdge <= 0.0; + bool isRightCap = pointAlignmentForLeftEdge >= 0.0 && pointAlignmentForRightEdge >= 0.0; + + vec2 nextLineEquation = getLineEquation(v_currPoint, v_nextPoint); + bool isJoin = belongToLine(nextLineEquation, lineWidth + borderWidth, point) && belongToLine(lineEquation, lineWidth + borderWidth, point); + + if (isJoin) { + // Render join + float distanceToCurrentLine = getDistanceFromLine(lineEquation, point); + float distanceToNextLine = getDistanceFromLine(nextLineEquation, point); + + if (distanceToCurrentLine <= lineWidth || distanceToNextLine <= lineWidth) { + gl_FragColor = v_color; + } else if (distanceToCurrentLine > lineWidth && distanceToCurrentLine <= lineWidth + borderWidth) { + gl_FragColor = v_borderColor; + } else if (distanceToNextLine > lineWidth && distanceToNextLine <= lineWidth + borderWidth) { + gl_FragColor = v_borderColor; + } + } else if (isLeftCap || isRightCap) { + // Render Cap + + float distanceToEdge = length(point - (isLeftCap ? v_prevPoint: v_currPoint)); + bool isCapBody = distanceToEdge <= lineWidth; + bool isBorder = (distanceToEdge > lineWidth) && (distanceToEdge <= lineWidth + borderWidth); + + if (isCapBody) { + gl_FragColor = v_color; + } else if (isBorder) { + gl_FragColor = v_borderColor; + } + } else { + // Render body + + vec2 p1 = v_prevPoint; + vec2 p2 = v_currPoint; + vec2 p3 = point; + vec2 p12 = p2 - p1; + vec2 p13 = p3 - p1; + vec2 p4 = p1 + normalize(p12) * (dot(p12, p13) / length(p12)); + + float pointDistance = length(p4 - p3); + + if (pointDistance <= lineWidth) { + gl_FragColor = v_color; + } else if (pointDistance > lineWidth && pointDistance <= (lineWidth + borderWidth)) { + gl_FragColor = v_borderColor; + } + } + } + `, +}; diff --git a/src/map/renderer/webgl/objects/object/object.ts b/src/map/renderer/webgl/objects/object/object.ts index d7280dd..b750bf9 100644 --- a/src/map/renderer/webgl/objects/object/object.ts +++ b/src/map/renderer/webgl/objects/object/object.ts @@ -1,11 +1,14 @@ import { MapTileFeatureType } from '../../../../tile/tile'; export interface WebGlObject { + id: number; type: MapTileFeatureType; } export interface WebGlObjectBufferredGroup { type: MapTileFeatureType; + name: string; + zIndex: number; } export interface WebGlObjectAttributeDescriptor { diff --git a/src/map/renderer/webgl/objects/object/object_group_builder.ts b/src/map/renderer/webgl/objects/object/object_group_builder.ts index e4973ce..9dc4ee5 100644 --- a/src/map/renderer/webgl/objects/object/object_group_builder.ts +++ b/src/map/renderer/webgl/objects/object/object_group_builder.ts @@ -1,74 +1,33 @@ -import { vec2, mat3, vec3 } from 'gl-matrix'; +import { vec2, vec3 } from 'gl-matrix'; import { WebGlObject, WebGlObjectBufferredGroup } from './object'; -import { Projection } from '../../../../geo/projection/projection'; import { MapFeatureFlags } from '../../../../flags'; +import { SceneCamera } from '../../../renderer'; export abstract class ObjectGroupBuilder { - protected objects: Array<[ObjectType, number]> = []; - protected vertecies: number[] = []; + protected objects: Array = []; - constructor( - protected readonly projectionViewMat: mat3, - protected readonly canvasWidth: number, - protected readonly canvasHeight: number, - protected readonly pixelRatio: number, - protected readonly zoom: number, - protected readonly minZoom: number, - protected readonly maxZoom: number, - protected readonly tileSize: number, - protected readonly projection: Projection, - protected readonly featureFlags: MapFeatureFlags - ) {} + constructor(protected readonly featureFlags: MapFeatureFlags, protected readonly pixelRatio: number) {} - abstract addObject(obj: ObjectType): void; + addObject(obj: ObjectType): void { + this.objects.push(obj); + } isEmpty(): boolean { return this.objects.length === 0; } - protected getTileZoom(): number | undefined { - let tileZoom = Math.round(this.zoom); - - return this.clampZoom(tileZoom); - } - - protected clampZoom(zoom: number) { - const minZoom = this.minZoom; - const maxZoom = this.maxZoom; - - if (zoom < minZoom) { - return minZoom; - } - - if (maxZoom < zoom) { - return maxZoom; - } - - return zoom; - } - /** - * @deprecated Use `scalarZoom` instead; * Scales value for webgl canvas value according to the current zoom and tileSize. * */ - scalarScale(val: number): number { + scalarScale(val: number, distance: number): number { // return this.tileSize * Math.pow(2, zoom); - return val / (Math.pow(2, this.zoom) * this.tileSize); - } - - scalarZoom(val: number): number { - return Math.log(val / this.tileSize) / Math.LN2; - // return val / (Math.pow(2, this.zoom) * this.tileSize); - } - - scalarScale_2(val: number): number { - return this.tileSize * Math.pow(2, val); + return val / distance; } - applyProjectionViewMatrix(point: [number, number] | vec2): [number, number] { + applyProjectionViewMatrix(camera: SceneCamera, point: [number, number] | vec2): [number, number] { const result = vec3.create(); - vec3.transformMat3(result, vec3.fromValues(point[0], point[1], 1), this.projectionViewMat); + vec3.transformMat3(result, vec3.fromValues(point[0], point[1], 1), camera.viewMatrix); return [result[0], result[1]]; } @@ -77,7 +36,11 @@ export abstract class ObjectGroupBuilder { return [-1.0 + position[0] * 2.0, +1.0 - position[1] * 2.0]; } - abstract build(): Promise | WebGlObjectBufferredGroup; + abstract build( + camera: SceneCamera, + name: string, + zIndex: number + ): Promise | WebGlObjectBufferredGroup; clear(): void { this.objects = []; diff --git a/src/map/renderer/webgl/objects/object/object_program.ts b/src/map/renderer/webgl/objects/object/object_program.ts index 75b9bf6..4374dbb 100644 --- a/src/map/renderer/webgl/objects/object/object_program.ts +++ b/src/map/renderer/webgl/objects/object/object_program.ts @@ -16,7 +16,6 @@ export abstract class ObjectProgram { // uniform locations protected u_matrixLocation: WebGLUniformLocation; - protected u_zoomLocation: WebGLUniformLocation; protected u_widthLocation: WebGLUniformLocation; protected u_heightLocation: WebGLUniformLocation; protected u_tile_sizeLocation: WebGLUniformLocation; @@ -95,10 +94,8 @@ export abstract class ObjectProgram { protected setupUniforms() { this.u_matrixLocation = this.gl.getUniformLocation(this.program, 'u_matrix'); - this.u_zoomLocation = this.gl.getUniformLocation(this.program, 'u_zoom'); this.u_widthLocation = this.gl.getUniformLocation(this.program, 'u_width'); this.u_heightLocation = this.gl.getUniformLocation(this.program, 'u_height'); - this.u_tile_sizeLocation = this.gl.getUniformLocation(this.program, 'u_tile_size'); this.u_is_read_pixel_render_modeLocation = this.gl.getUniformLocation(this.program, 'u_is_read_pixel_render_mode'); this.u_feature_flagsLocations = {}; @@ -127,10 +124,6 @@ export abstract class ObjectProgram { this.gl.uniformMatrix3fv(this.u_matrixLocation, false, matrix); } - setZoom(zoom: number) { - this.gl.uniform1f(this.u_zoomLocation, zoom); - } - setWidth(width: number) { this.gl.uniform1f(this.u_widthLocation, width); } @@ -139,10 +132,6 @@ export abstract class ObjectProgram { this.gl.uniform1f(this.u_heightLocation, height); } - setTileSize(tileSize: number) { - this.gl.uniform1f(this.u_tile_sizeLocation, tileSize); - } - setReadPixelRenderMode(isReadPixelRenderMode: boolean) { this.gl.uniform1i(this.u_is_read_pixel_render_modeLocation, isReadPixelRenderMode ? 1 : 0); } diff --git a/src/map/renderer/webgl/objects/object/object_shaders.ts b/src/map/renderer/webgl/objects/object/object_shaders.ts index e982314..7f6fd7e 100644 --- a/src/map/renderer/webgl/objects/object/object_shaders.ts +++ b/src/map/renderer/webgl/objects/object/object_shaders.ts @@ -53,32 +53,32 @@ export const MAT_UTILS = ` } `; -export const MERCATOR_PROJECTION_UTILS = ` - #define PI 3.141592653589793 - #define HALF_PI PI/2.0 - #define QUARTER_PI PI/4.0 - #define RAD_TO_DEG 180.0/PI - #define DEG_TO_RAD PI/180.0 - - float mercatorXfromLng(float lng) { - return (180.0 + lng) / 360.0; - } - - float mercatorYfromLat(float lat) { - return (180.0 - (RAD_TO_DEG * log(tan(QUARTER_PI + (lat * PI) / 360.0)))) / 360.0; - } - - vec2 mercatorProject(vec2 lngLat) { - float x = mercatorXfromLng(lngLat.x); - float y = mercatorYfromLat(lngLat.y); - - return vec2(x, y); - } - - vec2 mercatorProject(vec3 lngLat) { - float x = mercatorXfromLng(lngLat.x); - float y = mercatorYfromLat(lngLat.y); - - return vec2(x, y); - } -`; +// export const MERCATOR_PROJECTION_UTILS = ` +// #define PI 3.141592653589793 +// #define HALF_PI PI/2.0 +// #define QUARTER_PI PI/4.0 +// #define RAD_TO_DEG 180.0/PI +// #define DEG_TO_RAD PI/180.0 + +// float mercatorXfromLng(float lng) { +// return (180.0 + lng) / 360.0; +// } + +// float mercatorYfromLat(float lat) { +// return (180.0 - (RAD_TO_DEG * log(tan(QUARTER_PI + (lat * PI) / 360.0)))) / 360.0; +// } + +// vec2 mercatorProject(vec2 lngLat) { +// float x = mercatorXfromLng(lngLat.x); +// float y = mercatorYfromLat(lngLat.y); + +// return vec2(x, y); +// } + +// vec2 mercatorProject(vec3 lngLat) { +// float x = mercatorXfromLng(lngLat.x); +// float y = mercatorYfromLat(lngLat.y); + +// return vec2(x, y); +// } +// `; diff --git a/src/map/renderer/webgl/objects/point/point.ts b/src/map/renderer/webgl/objects/point/point.ts index 5e25ad5..b17e6ab 100644 --- a/src/map/renderer/webgl/objects/point/point.ts +++ b/src/map/renderer/webgl/objects/point/point.ts @@ -15,8 +15,6 @@ export interface WebGlPoint extends WebGlObject { radius: number; components?: number; margin?: PointMargin; - - // TODO: support this borderWidth: number; borderColor: vec4 | [number, number, number, number]; } @@ -32,6 +30,7 @@ export interface WebGlPointBufferredGroup extends WebGlObjectBufferredGroup { numElements: number; // number of elements color: WebGlObjectAttributeDescriptor; // Array; vertecies: WebGlObjectAttributeDescriptor; // Array; + borderVertecies: WebGlObjectAttributeDescriptor; // Array; borderWidth: WebGlObjectAttributeDescriptor; // Array; borderColor: WebGlObjectAttributeDescriptor; // Array; selectionColor: WebGlObjectAttributeDescriptor; // Array; diff --git a/src/map/renderer/webgl/objects/point/point_builder.ts b/src/map/renderer/webgl/objects/point/point_builder.ts index 462170c..c455457 100644 --- a/src/map/renderer/webgl/objects/point/point_builder.ts +++ b/src/map/renderer/webgl/objects/point/point_builder.ts @@ -1,60 +1,55 @@ import { vec2 } from 'gl-matrix'; import { WebGlObjectAttributeType } from '../object/object'; +import { SceneCamera } from '../../../renderer'; import { ObjectGroupBuilder } from '../object/object_group_builder'; import { WebGlPoint, WebGlPointBufferredGroup } from './point'; import { MapTileFeatureType } from '../../../../tile/tile'; import { createdSharedArrayBuffer } from '../../utils/array_buffer'; import { integerToVector4 } from '../../utils/number2vec'; +import { addXTimes } from '../../utils/array_utils'; export class PointGroupBuilder extends ObjectGroupBuilder { - addObject(point: WebGlPoint) { - const objectSize = verticesFromPoint( - this.vertecies, - this.projection.fromLngLat([point.center[0], point.center[1]]), - this.scalarScale(point.radius), - point.components - ); - - this.objects.push([point, objectSize]); - } - - build(): WebGlPointBufferredGroup { - const numElements = this.vertecies.length / 2; + build(camera: SceneCamera, name: string, zIndex = 0): WebGlPointBufferredGroup { + const vertecies: number[] = []; + const borderVertecies: number[] = []; const colorBuffer: number[] = []; const borderWidthBuffer: number[] = []; const borderColorBuffer: number[] = []; const selectionColorBuffer: number[] = []; - let currentObjectIndex = 0; - let currentObject: WebGlPoint = this.objects[currentObjectIndex][0]; - let currentOffset = this.objects[currentObjectIndex][1]; - - for (let i = 0; i < numElements; i++) { - if (i > currentOffset) { - currentObjectIndex++; - currentObject = this.objects[currentObjectIndex][0]; - currentOffset += this.objects[currentObjectIndex][1]; - } + for (const point of this.objects) { + const scaledRadius = this.scalarScale(point.radius, camera.distance); + const scaledBorderWidth = this.scalarScale(point.borderWidth, camera.distance); + const numberOfAddedVertecies = verticesFromPoint(vertecies, point.center, scaledRadius, point.components); + const xTimes = numberOfAddedVertecies / 2; - colorBuffer.push(...currentObject.color); - borderWidthBuffer.push(currentObject.borderWidth); - borderColorBuffer.push(...currentObject.borderColor); - selectionColorBuffer.push(...integerToVector4(currentObject.id)); + verticesFromPoint(borderVertecies, point.center, scaledRadius + scaledBorderWidth, point.components); + addXTimes(colorBuffer, [...point.color], xTimes); + addXTimes(borderWidthBuffer, point.borderWidth, xTimes); + addXTimes(borderColorBuffer, [...point.borderColor], xTimes); + addXTimes(selectionColorBuffer, integerToVector4(point.id), xTimes); } return { type: MapTileFeatureType.point, + name, + zIndex, size: this.objects.length, - numElements, - color: { + numElements: vertecies.length / 2, + vertecies: { type: WebGlObjectAttributeType.FLOAT, - size: 4, - buffer: createdSharedArrayBuffer(colorBuffer), + size: 2, + buffer: createdSharedArrayBuffer(vertecies), }, - vertecies: { + borderVertecies: { type: WebGlObjectAttributeType.FLOAT, size: 2, - buffer: createdSharedArrayBuffer(this.vertecies), + buffer: createdSharedArrayBuffer(borderVertecies), + }, + color: { + type: WebGlObjectAttributeType.FLOAT, + size: 4, + buffer: createdSharedArrayBuffer(colorBuffer), }, borderWidth: { type: WebGlObjectAttributeType.FLOAT, diff --git a/src/map/renderer/webgl/objects/point/point_program.ts b/src/map/renderer/webgl/objects/point/point_program.ts index 5ac499d..511c3da 100644 --- a/src/map/renderer/webgl/objects/point/point_program.ts +++ b/src/map/renderer/webgl/objects/point/point_program.ts @@ -25,11 +25,18 @@ export class PointProgram extends ObjectProgram { gl.bindVertexArray(this.vao); + // draw background + this.positionBuffer.bufferData(objectGroup.borderVertecies.buffer); + this.colorBuffer.bufferData( + options?.readPixelRenderMode ? objectGroup.selectionColor.buffer : objectGroup.borderColor.buffer + ); + gl.drawArrays(gl.TRIANGLES, 0, objectGroup.numElements); + + // draw circle this.positionBuffer.bufferData(objectGroup.vertecies.buffer); this.colorBuffer.bufferData( options?.readPixelRenderMode ? objectGroup.selectionColor.buffer : objectGroup.color.buffer ); - gl.drawArrays(gl.TRIANGLES, 0, objectGroup.numElements); gl.bindVertexArray(null); diff --git a/src/map/renderer/webgl/objects/point/point_shaders.ts b/src/map/renderer/webgl/objects/point/point_shaders.ts index 0e7da09..ddc262f 100644 --- a/src/map/renderer/webgl/objects/point/point_shaders.ts +++ b/src/map/renderer/webgl/objects/point/point_shaders.ts @@ -1,24 +1,15 @@ -import { - FEATURE_FLAGS_UTILS, - DEFAULT_FRAGMENT_SHADER_SOURCE, - CLIP_UTILS, - MAT_UTILS, - MERCATOR_PROJECTION_UTILS, -} from '../object/object_shaders'; +import { FEATURE_FLAGS_UTILS, DEFAULT_FRAGMENT_SHADER_SOURCE, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} ${FEATURE_FLAGS_UTILS} uniform mat3 u_matrix; - uniform float u_zoom; uniform float u_width; uniform float u_height; - uniform float u_tile_size; uniform bool u_is_read_pixel_render_mode; attribute vec2 a_position; diff --git a/src/map/renderer/webgl/objects/polygon/polygon_builder.ts b/src/map/renderer/webgl/objects/polygon/polygon_builder.ts index 500c9c4..2f54982 100644 --- a/src/map/renderer/webgl/objects/polygon/polygon_builder.ts +++ b/src/map/renderer/webgl/objects/polygon/polygon_builder.ts @@ -1,57 +1,48 @@ import { vec2 } from 'gl-matrix'; import earcut from 'earcut'; import { WebGlObjectAttributeType } from '../object/object'; +import { SceneCamera } from '../../../renderer'; import { ObjectGroupBuilder } from '../object/object_group_builder'; import { WebGlPolygon, WebGlPolygonBufferredGroup } from './polygon'; import { MapTileFeatureType } from '../../../../tile/tile'; import { createdSharedArrayBuffer } from '../../utils/array_buffer'; import { integerToVector4 } from '../../utils/number2vec'; +import { addXTimes } from '../../utils/array_utils'; export class PolygonGroupBuilder extends ObjectGroupBuilder { - addObject(polygon: WebGlPolygon) { - const objectSize = verticesFromPolygon(this.vertecies, polygon.vertecies); - - this.objects.push([polygon, objectSize]); - } - - build(): WebGlPolygonBufferredGroup { - const numElements = this.vertecies.length / 2; + build(camera: SceneCamera, name: string, zIndex = 0): WebGlPolygonBufferredGroup { + const vertecies: number[] = []; const colorBuffer: number[] = []; const borderWidthBuffer: number[] = []; const borderColorBuffer: number[] = []; const selectionColorBuffer: number[] = []; - let currentObjectIndex = 0; - let currentObject: WebGlPolygon = this.objects[currentObjectIndex][0]; - let currentOffset = this.objects[currentObjectIndex][1]; + for (const polygon of this.objects) { + const numberOfAddedVertecies = verticesFromPolygon(vertecies, polygon.vertecies); + const xTimes = numberOfAddedVertecies / 2; - for (let i = 0; i < numElements; i++) { - if (i > currentOffset) { - currentObjectIndex++; - currentObject = this.objects[currentObjectIndex][0]; - currentOffset += this.objects[currentObjectIndex][1]; - } - - colorBuffer.push(...(currentObject.color || [0, 0, 0, 1])); - borderWidthBuffer.push(currentObject.borderWidth); - borderColorBuffer.push(...currentObject.borderColor); - selectionColorBuffer.push(...integerToVector4(currentObject.id)); + addXTimes(colorBuffer, [...polygon.color], xTimes); + addXTimes(borderWidthBuffer, polygon.borderWidth, xTimes); + addXTimes(borderColorBuffer, [...polygon.borderColor], xTimes); + addXTimes(borderColorBuffer, integerToVector4(polygon.id), xTimes); } return { type: MapTileFeatureType.polygon, + name, + zIndex, size: this.objects.length, - numElements, + numElements: vertecies.length / 2, + vertecies: { + type: WebGlObjectAttributeType.FLOAT, + size: 2, + buffer: createdSharedArrayBuffer(vertecies), + }, color: { type: WebGlObjectAttributeType.FLOAT, size: 4, buffer: createdSharedArrayBuffer(colorBuffer), }, - vertecies: { - type: WebGlObjectAttributeType.FLOAT, - size: 2, - buffer: createdSharedArrayBuffer(this.vertecies), - }, borderWidth: { type: WebGlObjectAttributeType.FLOAT, size: 1, diff --git a/src/map/renderer/webgl/objects/polygon/polygon_shaders.ts b/src/map/renderer/webgl/objects/polygon/polygon_shaders.ts index d46081a..ddc262f 100644 --- a/src/map/renderer/webgl/objects/polygon/polygon_shaders.ts +++ b/src/map/renderer/webgl/objects/polygon/polygon_shaders.ts @@ -1,24 +1,15 @@ -import { - FEATURE_FLAGS_UTILS, - DEFAULT_FRAGMENT_SHADER_SOURCE, - CLIP_UTILS, - MAT_UTILS, - MERCATOR_PROJECTION_UTILS, -} from '../object/object_shaders'; +import { FEATURE_FLAGS_UTILS, DEFAULT_FRAGMENT_SHADER_SOURCE, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} ${FEATURE_FLAGS_UTILS} uniform mat3 u_matrix; - uniform float u_zoom; uniform float u_width; uniform float u_height; - uniform float u_tile_size; uniform bool u_is_read_pixel_render_mode; attribute vec2 a_position; @@ -28,7 +19,7 @@ export default { void main() { v_color = a_color; - gl_Position = vec4(applyMatrix(u_matrix, clipSpace(mercatorProject(a_position))), 0, 1); + gl_Position = vec4(applyMatrix(u_matrix, clipSpace(a_position)), 0, 1); } `, fragment: DEFAULT_FRAGMENT_SHADER_SOURCE, diff --git a/src/map/renderer/webgl/objects/text_texture/text_texture_builder.ts b/src/map/renderer/webgl/objects/text_texture/text_texture_builder.ts index 38f8002..0552778 100644 --- a/src/map/renderer/webgl/objects/text_texture/text_texture_builder.ts +++ b/src/map/renderer/webgl/objects/text_texture/text_texture_builder.ts @@ -1,5 +1,6 @@ -import { vec4, mat3 } from 'gl-matrix'; +import { vec4 } from 'gl-matrix'; import { WebGlText } from '../text/text'; +import { SceneCamera } from '../../../renderer'; import { WebGlTextTextureBufferredGroup } from './text_texture'; import { WebGlObjectAttributeType } from '../object/object'; import { ObjectGroupBuilder } from '../object/object_group_builder'; @@ -28,41 +29,22 @@ export interface GlyphMapping { export class TextTextureGroupBuilder extends ObjectGroupBuilder { constructor( - protected readonly projectionViewMat: mat3, - protected readonly canvasWidth: number, - protected readonly canvasHeight: number, - protected readonly pixelRatio: number, - protected readonly zoom: number, - protected readonly minZoom: number, - protected readonly maxZoom: number, - protected readonly tileSize: number, - protected readonly projection: Projection, protected readonly featureFlags: MapFeatureFlags, + protected readonly pixelRatio: number, private readonly fontManager: FontManager ) { - super( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); + super(featureFlags, pixelRatio); } addObject(text: WebGlText): void { - if (!text.text || text.text === ' ') { + if (!text.text) { return; } - this.objects.push([text, 0]); + this.objects.push(text); } - build(): WebGlTextTextureBufferredGroup { + build(camera: SceneCamera, name: string, zIndex = 0): WebGlTextTextureBufferredGroup { const size = this.objects.length; const verteciesBuffer: number[] = []; const texcoordBuffer: number[] = []; @@ -73,17 +55,17 @@ export class TextTextureGroupBuilder extends ObjectGroupBuilder { const texture = fontAtlas.sources[0]; let numElements = 0; - for (const [text] of this.objects) { + for (const text of this.objects) { let offset = 0; for (const char of text.text) { const glyphMapping = this.getGlyphMapping(text, char, fontAtlas); const scaleFactor = text.fontSize / glyphMapping.glyph.fontSize / glyphMapping.glyph.pixelRatio; - const textScaledWidth = this.scalarScale(glyphMapping.glyph.width) * scaleFactor; - const textScaledHeight = this.scalarScale(glyphMapping.glyph.height) * scaleFactor; - const ascend = this.scalarScale(glyphMapping.glyph.actualBoundingBoxAscent) * scaleFactor; + const textScaledWidth = this.scalarScale(glyphMapping.glyph.width, camera.distance) * scaleFactor; + const textScaledHeight = this.scalarScale(glyphMapping.glyph.height, camera.distance) * scaleFactor; + const ascend = this.scalarScale(glyphMapping.glyph.actualBoundingBoxAscent, camera.distance) * scaleFactor; // vertex coordinates - let [x1, y1] = this.projection.fromLngLat([text.center[0], text.center[1]]); + let [x1, y1] = text.center; x1 = offset + x1; y1 = y1 - ascend; const x2 = x1 + textScaledWidth; @@ -130,6 +112,8 @@ export class TextTextureGroupBuilder extends ObjectGroupBuilder { return { type: MapTileFeatureType.text, + name, + zIndex, size, numElements, textureIndex: 0, diff --git a/src/map/renderer/webgl/objects/text_texture/text_texture_program.ts b/src/map/renderer/webgl/objects/text_texture/text_texture_program.ts index 1f2e561..6770639 100644 --- a/src/map/renderer/webgl/objects/text_texture/text_texture_program.ts +++ b/src/map/renderer/webgl/objects/text_texture/text_texture_program.ts @@ -36,7 +36,8 @@ export class TextTextureProgram extends ObjectProgram { const gl = this.gl; gl.enable(gl.BLEND); - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); + gl.depthMask(false); } @@ -67,9 +68,9 @@ export class TextTextureProgram extends ObjectProgram { protected async setupTexture() { const gl = this.gl; - const fontAtlas = this.fontManager.getFontAtlas('defaultFont') as TextureFontAtlas; + const fontAtlas = this.fontManager.getFontAtlas('defaultFont') as TextureFontAtlas | undefined; - for (const source of Object.values(fontAtlas.sources)) { + for (const source of Object.values(fontAtlas?.sources || {})) { this.fontTextures.push( createTexture(gl, { name: 'text_atlas_' + source.name, @@ -78,8 +79,8 @@ export class TextTextureProgram extends ObjectProgram { unpackPremultiplyAlpha: true, wrapS: gl.CLAMP_TO_EDGE, wrapT: gl.CLAMP_TO_EDGE, - minFilter: gl.NEAREST, - magFilter: gl.NEAREST, + minFilter: gl.LINEAR, + magFilter: gl.LINEAR, source: await toImageBitmapTexture(source.source), }) ); @@ -104,7 +105,7 @@ export class TextTextureProgram extends ObjectProgram { gl.drawArrays(gl.TRIANGLES, 0, textGroup.numElements); } else { // draw text border - gl.uniform1f(this.u_border_widthLocation, 0.65); + gl.uniform1f(this.u_border_widthLocation, 0.6); this.colorBuffer.bufferData(textGroup.borderColor.buffer); gl.drawArrays(gl.TRIANGLES, 0, textGroup.numElements); diff --git a/src/map/renderer/webgl/objects/text_texture/text_texture_shaders.ts b/src/map/renderer/webgl/objects/text_texture/text_texture_shaders.ts index ec736cf..b66e0db 100644 --- a/src/map/renderer/webgl/objects/text_texture/text_texture_shaders.ts +++ b/src/map/renderer/webgl/objects/text_texture/text_texture_shaders.ts @@ -1,18 +1,15 @@ -import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS, MERCATOR_PROJECTION_UTILS } from '../object/object_shaders'; +import { FEATURE_FLAGS_UTILS, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} ${FEATURE_FLAGS_UTILS} uniform mat3 u_matrix; - uniform float u_zoom; uniform float u_width; uniform float u_height; - uniform float u_tile_size; attribute vec2 a_position; attribute vec2 a_texCoord; @@ -29,6 +26,7 @@ export default { } `, fragment: ` + #define GAMMA 0.01 precision highp float; uniform sampler2D u_texture; @@ -40,20 +38,14 @@ export default { varying vec4 v_color; void main() { - float font_size = 10.0; - float gamma = 1.4142 / font_size; if (u_is_read_pixel_render_mode) { gl_FragColor = v_color; } else if (u_is_sfd_mode) { float dist = texture2D(u_texture, v_texCoord).a; - float alpha = v_color.a * smoothstep(u_border_width - gamma, u_border_width + gamma, dist); + float alpha = v_color.a * smoothstep(u_border_width - GAMMA, u_border_width + GAMMA, dist); - if (alpha == 0.0) { - gl_FragColor = vec4(0.0, 0.0, 0.0, alpha); - } else { - gl_FragColor = vec4(v_color.r, v_color.g, v_color.b, alpha); - } + gl_FragColor = vec4(v_color.r, v_color.g, v_color.b, alpha); } else { gl_FragColor = texture2D(u_texture, v_texCoord); } diff --git a/src/map/renderer/webgl/objects/text_vector/text_vector_builder.ts b/src/map/renderer/webgl/objects/text_vector/text_vector_builder.ts index 7a21d27..fc6cdbc 100644 --- a/src/map/renderer/webgl/objects/text_vector/text_vector_builder.ts +++ b/src/map/renderer/webgl/objects/text_vector/text_vector_builder.ts @@ -1,5 +1,5 @@ -import { mat3 } from 'gl-matrix'; import { MapFeatureFlags } from '../../../../flags'; +import { SceneCamera } from '../../../renderer'; import { getVerticiesFromChar } from './text_vector_utils'; import { WebGlText } from '../text/text'; import { WebGlTextVectorBufferredGroup } from './text_vector'; @@ -11,6 +11,7 @@ import { MapTileFeatureType } from '../../../../tile/tile'; import { Projection } from '../../../../geo/projection/projection'; import { createdSharedArrayBuffer } from '../../utils/array_buffer'; import { integerToVector4 } from '../../utils/number2vec'; +import { addXTimes } from '../../utils/array_utils'; interface CharVerticesData { vertices: number[]; @@ -28,72 +29,42 @@ const FONT_CHAR_CACHE: Record> = {}; export class TextVectorBuilder extends ObjectGroupBuilder { constructor( - protected readonly projectionViewMat: mat3, - protected readonly canvasWidth: number, - protected readonly canvasHeight: number, - protected readonly pixelRatio: number, - protected readonly zoom: number, - protected readonly minZoom: number, - protected readonly maxZoom: number, - protected readonly tileSize: number, - protected readonly projection: Projection, protected readonly featureFlags: MapFeatureFlags, + protected readonly pixelRatio: number, private readonly fontManager: FontManager ) { - super( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); - } - - addObject(text: WebGlText) { - const objectSize = this.verticesFromText(this.vertecies, this.fontManager, text); - - this.objects.push([text, objectSize]); + super(featureFlags, pixelRatio); } - build(): WebGlTextVectorBufferredGroup { - const numElements = this.vertecies.length / 2; + build(camera: SceneCamera, name: string, zIndex = 0): WebGlTextVectorBufferredGroup { + const vertecies: number[] = []; const colorBuffer: number[] = []; const selectionColorBuffer: number[] = []; - let currentObjectIndex = 0; - let currentObject: WebGlText = this.objects[currentObjectIndex][0]; - let currentOffset = this.objects[currentObjectIndex][1]; - - for (let i = 0; i < numElements; i++) { - if (i > currentOffset) { - currentObjectIndex++; - currentObject = this.objects[currentObjectIndex][0]; - currentOffset += this.objects[currentObjectIndex][1]; - } + for (const text of this.objects) { + const numberOfAddedVertecies = this.verticesFromText(vertecies, camera, this.fontManager, text); + const xTimes = numberOfAddedVertecies / 2; - colorBuffer.push(...currentObject.color); - selectionColorBuffer.push(...integerToVector4(currentObject.id)); + addXTimes(colorBuffer, [...text.color], xTimes); + addXTimes(selectionColorBuffer, integerToVector4(text.id), xTimes); } return { type: MapTileFeatureType.text, + name, + zIndex, size: this.objects.length, - numElements, + numElements: vertecies.length / 2, + vertecies: { + type: WebGlObjectAttributeType.FLOAT, + size: 2, + buffer: createdSharedArrayBuffer(vertecies), + }, color: { type: WebGlObjectAttributeType.FLOAT, size: 4, buffer: createdSharedArrayBuffer(colorBuffer), }, - vertecies: { - type: WebGlObjectAttributeType.FLOAT, - size: 2, - buffer: createdSharedArrayBuffer(this.vertecies), - }, selectionColor: { type: WebGlObjectAttributeType.FLOAT, size: 4, @@ -102,7 +73,7 @@ export class TextVectorBuilder extends ObjectGroupBuilder { }; } - verticesFromText(result: number[], fontManager: FontManager, text: WebGlText): number { + verticesFromText(result: number[], camera: SceneCamera, fontManager: FontManager, text: WebGlText): number { const start = result.length; if (!text.text) { @@ -133,11 +104,11 @@ export class TextVectorBuilder extends ObjectGroupBuilder { textData.height = Math.max(textData.height, charVerticiesData.height); } - const scaledHeight = this.scalarScale(textData.height / this.tileSize) * text.fontSize; + const scaledHeight = this.scalarScale(textData.height, camera.distance) * text.fontSize; let scaledTextWidth = 0; for (const { vertices: charVertices, width } of textData.chars) { - const scaledWidth = this.scalarScale(width / this.tileSize) * text.fontSize; + const scaledWidth = this.scalarScale(width, camera.distance) * text.fontSize; let minX = Infinity; let maxX = -Infinity; diff --git a/src/map/renderer/webgl/objects/text_vector/text_vector_shaders.ts b/src/map/renderer/webgl/objects/text_vector/text_vector_shaders.ts index 9d7679a..77df08c 100644 --- a/src/map/renderer/webgl/objects/text_vector/text_vector_shaders.ts +++ b/src/map/renderer/webgl/objects/text_vector/text_vector_shaders.ts @@ -1,22 +1,15 @@ -import { - DEFAULT_FRAGMENT_SHADER_SOURCE, - CLIP_UTILS, - MAT_UTILS, - MERCATOR_PROJECTION_UTILS, -} from '../object/object_shaders'; +import { DEFAULT_FRAGMENT_SHADER_SOURCE, CLIP_UTILS, MAT_UTILS } from '../object/object_shaders'; export default { vertext: ` precision highp float; ${CLIP_UTILS} ${MAT_UTILS} - ${MERCATOR_PROJECTION_UTILS} attribute vec2 a_position; attribute vec4 a_color; uniform mat3 u_matrix; - uniform float u_zoom; uniform bool u_is_read_pixel_render_mode; varying vec4 v_color; @@ -28,7 +21,7 @@ export default { v_color = vec4(0.0, 0.0, 0.0, 1.0); } - gl_Position = vec4(applyMatrix(u_matrix, clipSpace(mercatorProject(a_position))), 0, 1); + gl_Position = vec4(applyMatrix(u_matrix, clipSpace(a_position)), 0, 1); } `, fragment: DEFAULT_FRAGMENT_SHADER_SOURCE, diff --git a/src/map/renderer/webgl/tile/weblg_tile_processor_debug.ts b/src/map/renderer/webgl/tile/weblg_tile_processor_debug.ts index c3d4d84..56ac0b6 100644 --- a/src/map/renderer/webgl/tile/weblg_tile_processor_debug.ts +++ b/src/map/renderer/webgl/tile/weblg_tile_processor_debug.ts @@ -1,6 +1,5 @@ import tilebelt from '@mapbox/tilebelt'; import geometryCenter from '@turf/center'; -import { mat3 } from 'gl-matrix'; // Common import { MercatorProjection } from '../../../geo/projection/mercator_projection'; import { FontManager } from '../../../font/font_manager'; @@ -12,6 +11,7 @@ import { FetchTileOptions } from '../../../tile/tile_source_processor'; // Styles import { DataTileSource, DataLayerStyle } from '../../../styles/styles'; // WebGl objects +import { SceneCamera } from '../../renderer'; import { LineGroupBuilder } from '../objects/line/line_builder'; import { LineJoinStyle, LineCapStyle, LineFillStyle } from '../objects/line/line'; import { TextVectorBuilder } from '../objects/text_vector/text_vector_builder'; @@ -30,69 +30,37 @@ export async function DebugTile2WebglLayers( zoom, tileSize, featureFlags, - projectionViewMat: projectionViewMatSource, + projectionViewMat, fontManagerState, }: FetchTileOptions, abortController: AbortController, onLayerReady: (tileLayer: WebGlMapLayer) => void ): Promise { - const minZoom = tileStyles.minzoom || 0; - const maxZoom = tileStyles.maxzoom || 0; const [x, y, z] = tileId.split('/').map(Number); const projection = new MercatorProjection(); - const projectionViewMat = mat3.fromValues(...projectionViewMatSource); + const camera: SceneCamera = { + width: canvasWidth, + height: canvasHeight, + distance: Math.pow(2, zoom) * tileSize, + viewMatrix: projectionViewMat, + }; const fontManager = new FontManager(featureFlags, {}, fontManagerState); const tileLayers: WebGlMapLayer[] = []; const tilePolygon = tilebelt.tileToGeoJSON([x, y, z]); const tileCenter = geometryCenter(tilePolygon).geometry.coordinates as [number, number]; const tileBbox = tilePolygon.coordinates[0] as Array<[number, number]>; - const lineGroupBuilder = new LineGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); + const lineGroupBuilder = new LineGroupBuilder(featureFlags, pixelRatio); const textTextureGroupBuilder = featureFlags.webglRendererFontFormatType === FontFormatType.vector - ? new TextVectorBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags, - fontManager - ) - : new TextTextureGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags, - fontManager - ); + ? new TextVectorBuilder(featureFlags, pixelRatio, fontManager) + : new TextTextureGroupBuilder(featureFlags, pixelRatio, fontManager); textTextureGroupBuilder.addObject({ id: 1, type: MapTileFeatureType.text, text: tileId, - center: tileCenter, + center: projection.fromLngLat(tileCenter), font: 'defaultFont', fontSize: 24, borderWidth: 1, @@ -109,7 +77,7 @@ export async function DebugTile2WebglLayers( type: MapTileFeatureType.line, color: [1, 0, 0, 1], borderColor: [0, 0, 0, 1], - vertecies: tileBbox, + vertecies: tileBbox.map(p => projection.fromLngLat(p)), width: 3, borderWidth: 0, fill: LineFillStyle.solid, @@ -117,7 +85,10 @@ export async function DebugTile2WebglLayers( cap: LineCapStyle.square, }); - const debugObjectGroups = [textTextureGroupBuilder.build(), lineGroupBuilder.build()]; + const debugObjectGroups = [ + textTextureGroupBuilder.build(camera, `${tileId}_debugLayer_text`, 99), + lineGroupBuilder.build(camera, `${tileId}_debugLayer_line`, 99), + ]; const debugLayer: WebGlMapLayer = { source: 'debug', layerName: 'debugLayer', diff --git a/src/map/renderer/webgl/tile/weblg_tile_processor_image.ts b/src/map/renderer/webgl/tile/weblg_tile_processor_image.ts index 539cc2e..6934e50 100644 --- a/src/map/renderer/webgl/tile/weblg_tile_processor_image.ts +++ b/src/map/renderer/webgl/tile/weblg_tile_processor_image.ts @@ -1,4 +1,4 @@ -import { mat3, vec2 } from 'gl-matrix'; +import { vec2 } from 'gl-matrix'; import tilebelt from '@mapbox/tilebelt'; // Common import { MercatorProjection } from '../../../geo/projection/mercator_projection'; @@ -10,6 +10,7 @@ import { WebGlMapLayer } from './webgl_tile'; import { DataLayerStyle, ImageStyle, ImageTileSource } from '../../../styles/styles'; import { compileStatement } from '../../../styles/style_statement_utils'; // WebGl objects +import { SceneCamera } from '../../renderer'; import { ImageGroupBuilder } from '../objects/image/image_group_builder'; import { ImageBitmapTextureSource } from '../../../texture/texture'; import { blobToBitmapImageTextureSource } from '../../../texture/texture_utils'; @@ -26,17 +27,20 @@ export async function ImageTile2WebglLayers( pixelRatio, zoom, tileSize, - projectionViewMat: projectionViewMatSource, + projectionViewMat, featureFlags, }: FetchTileOptions, abortController: AbortController, onLayerReady: (tileLayer: WebGlMapLayer) => void ): Promise { - const minZoom = tileStyles.minzoom || 0; - const maxZoom = tileStyles.maxzoom || 0; const [x, y, z] = tileId.split('/').map(Number); const projection = new MercatorProjection(); - const projectionViewMat = mat3.fromValues(...projectionViewMatSource); + const camera: SceneCamera = { + width: canvasWidth, + height: canvasHeight, + distance: Math.pow(2, zoom) * tileSize, + viewMatrix: projectionViewMat, + }; const tileLayers: WebGlMapLayer[] = []; const sourceArrayBuffer = await fetch(tileURL, { signal: abortController.signal }).then(res => res.blob()); @@ -56,25 +60,14 @@ export async function ImageTile2WebglLayers( continue; } - const imageGroupBuilder = new ImageGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); + const imageGroupBuilder = new ImageGroupBuilder(featureFlags, pixelRatio); imageGroupBuilder.addObject({ id: 0, type: MapTileFeatureType.image, name: tileId, bbox: [ - [tilebbox[0], tilebbox[1]], - [tilebbox[2], tilebbox[3]], + [...projection.fromLngLat([tilebbox[0], tilebbox[1]])], + [...projection.fromLngLat([tilebbox[2], tilebbox[3]])], ], topLeft: tilePolygon.coordinates[0][0] as vec2, source: textureSource, @@ -89,7 +82,9 @@ export async function ImageTile2WebglLayers( source: source.name, layerName: styleLayer.styleLayerName, zIndex: styleLayer.zIndex, - objectGroups: [imageGroupBuilder.build()], + objectGroups: [ + imageGroupBuilder.build(camera, `${tileId}_${styleLayer.styleLayerName}_images`, styleLayer.zIndex), + ], }; onLayerReady(layers); tileLayers.push(layers); diff --git a/src/map/renderer/webgl/tile/weblg_tile_processor_pbf.ts b/src/map/renderer/webgl/tile/weblg_tile_processor_pbf.ts index 7829168..3c72ec8 100644 --- a/src/map/renderer/webgl/tile/weblg_tile_processor_pbf.ts +++ b/src/map/renderer/webgl/tile/weblg_tile_processor_pbf.ts @@ -1,6 +1,6 @@ import Protobuf from 'pbf'; import { VectorTile } from '@mapbox/vector-tile'; -import { mat3, vec4 } from 'gl-matrix'; +import { vec4 } from 'gl-matrix'; import geometryCenter from '@turf/center'; import { Feature, LineString, MultiPolygon, Polygon, MultiLineString, Point, MultiPoint } from 'geojson'; // Common @@ -23,6 +23,7 @@ import { } from '../../../styles/styles'; import { compileStatement } from '../../../styles/style_statement_utils'; // WebGl objects +import { SceneCamera } from '../../renderer'; import { WebGlObjectBufferredGroup } from '../objects/object/object'; import { LineJoinStyle, LineCapStyle, LineFillStyle } from '../objects/line/line'; import { PointGroupBuilder } from '../objects/point/point_builder'; @@ -31,6 +32,7 @@ import { LineGroupBuilder } from '../objects/line/line_builder'; import { GlyphGroupBuilder } from '../objects/glyph/glyph_group_builder'; import { TextVectorBuilder } from '../objects/text_vector/text_vector_builder'; import { TextTextureGroupBuilder } from '../objects/text_texture/text_texture_builder'; +import { LineShaiderBuilder } from '../objects/line_shader/line_shader_builder'; export type SupportedGeometry = Polygon | MultiPolygon | LineString | MultiLineString | Point | MultiPoint; @@ -68,17 +70,20 @@ export async function PbfTile2WebglLayers( tileSize, atlasTextureMappingState, fontManagerState, - projectionViewMat: projectionViewMatSource, + projectionViewMat, featureFlags, }: FetchTileOptions, abortController: AbortController, onLayerReady: (tileLayer: WebGlMapLayer) => void ): Promise { - const minZoom = tileStyles.minzoom || 0; - const maxZoom = tileStyles.maxzoom || 0; const [x, y, z] = tileId.split('/').map(Number); const projection = new MercatorProjection(); - const projectionViewMat = mat3.fromValues(...projectionViewMatSource); + const camera: SceneCamera = { + width: canvasWidth, + height: canvasHeight, + distance: Math.pow(2, zoom) * tileSize, + viewMatrix: projectionViewMat, + }; const fontManager = new FontManager(featureFlags, {}, fontManagerState); const tileLayers: WebGlMapLayer[] = []; @@ -95,84 +100,18 @@ export async function PbfTile2WebglLayers( const numFeatures = vectorTile.layers[styleLayer.sourceLayer]?._features?.length || 0; const objectGroups: WebGlObjectBufferredGroup[] = []; - const pointsGroupBuilder = new PointGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); - const polygonGroupBuilder = new PolygonGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); - const lineGroupBuilder = new LineGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags - ); - const glyphGroupBuilder = new GlyphGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags, - atlasTextureMappingState - ); + const pointsGroupBuilder = new PointGroupBuilder(featureFlags, pixelRatio); + const polygonGroupBuilder = new PolygonGroupBuilder(featureFlags, pixelRatio); + + const lineGroupBuilder = featureFlags.webglRendererUseShaderLines + ? new LineShaiderBuilder(featureFlags, pixelRatio) + : new LineGroupBuilder(featureFlags, pixelRatio); + const glyphGroupBuilder = new GlyphGroupBuilder(featureFlags, pixelRatio, atlasTextureMappingState); const textTextureGroupBuilder = featureFlags.webglRendererFontFormatType === FontFormatType.vector - ? new TextVectorBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags, - fontManager - ) - : new TextTextureGroupBuilder( - projectionViewMat, - canvasWidth, - canvasHeight, - pixelRatio, - zoom, - minZoom, - maxZoom, - tileSize, - projection, - featureFlags, - fontManager - ); + ? new TextVectorBuilder(featureFlags, pixelRatio, fontManager) + : new TextTextureGroupBuilder(featureFlags, pixelRatio, fontManager); for (let i = 0; i < numFeatures; i++) { const geojson: Feature = vectorTile.layers[styleLayer.sourceLayer] @@ -205,7 +144,7 @@ export async function PbfTile2WebglLayers( id: pointFeature.id! as number, type: MapTileFeatureType.point, color: compileStatement(pointStyle.color, pointFeature), - center: pointFeature.geometry.coordinates as [number, number], + center: projection.fromLngLat(pointFeature.geometry.coordinates as [number, number]), radius: pointStyle.radius ? compileStatement(pointStyle.radius, pointFeature) : 1, components: 32, borderWidth: pointStyle.border?.width ? compileStatement(pointStyle.border.width, pointFeature) : 1, @@ -227,7 +166,7 @@ export async function PbfTile2WebglLayers( id: pointFeature.id! as number, type: MapTileFeatureType.point, color: compileStatement(pointStyle.color, pointFeature), - center: point as [number, number], + center: projection.fromLngLat(point as [number, number]), radius: pointStyle.radius ? compileStatement(pointStyle.radius, pointFeature) : 1, components: 32, borderWidth: pointStyle.border?.width ? compileStatement(pointStyle.border.width, pointFeature) : 1, @@ -255,7 +194,7 @@ export async function PbfTile2WebglLayers( color: compileStatement(textStyle.color, pointFeature), borderColor: compileStatement(textStyle.borderColor, pointFeature), text: compileStatement(textStyle.text, pointFeature), - center: pointFeature.geometry.coordinates as [number, number], + center: projection.fromLngLat(pointFeature.geometry.coordinates as [number, number]), font: textStyle.font ? compileStatement(textStyle.font, pointFeature) : 'opensans', fontSize: compileStatement(textStyle.fontSize, pointFeature), borderWidth: 1, @@ -278,7 +217,7 @@ export async function PbfTile2WebglLayers( color: compileStatement(textStyle.color, pointFeature), borderColor: compileStatement(textStyle.borderColor, pointFeature), text: compileStatement(textStyle.text, pointFeature), - center: point as [number, number], + center: projection.fromLngLat(point as [number, number]), font: textStyle.font ? compileStatement(textStyle.font, pointFeature) : 'opensans', fontSize: compileStatement(textStyle.fontSize, pointFeature), borderWidth: 1, @@ -310,7 +249,7 @@ export async function PbfTile2WebglLayers( type: MapTileFeatureType.glyph, atlas: compileStatement(glyphStyle.atlas, pointFeature), name: compileStatement(glyphStyle.name, pointFeature), - center, + center: projection.fromLngLat(center), width: glyphStyle.width ?? compileStatement(glyphStyle.width, pointFeature), height: glyphStyle.height ?? compileStatement(glyphStyle.height, pointFeature), margin: { @@ -336,7 +275,9 @@ export async function PbfTile2WebglLayers( id: polygonFeature.id! as number, type: MapTileFeatureType.polygon, color: compileStatement(polygonStyle.color, polygonFeature), - vertecies: geojson.geometry.coordinates as Array>, + vertecies: (geojson.geometry.coordinates as Array>).map(arr => + arr.map(p => projection.fromLngLat(p)) + ), borderWidth: 1, borderColor: vec4.fromValues(0, 0, 0, 1), borderJoin: LineJoinStyle.bevel, @@ -353,7 +294,9 @@ export async function PbfTile2WebglLayers( id: polygonFeature.id! as number, type: MapTileFeatureType.polygon, color: compileStatement(polygonStyle.color, polygonFeature), - vertecies: [polygons[0]] as Array>, + vertecies: ([polygons[0]] as Array>).map(arr => + arr.map(p => projection.fromLngLat(p)) + ), borderWidth: 1, borderColor: vec4.fromValues(0, 0, 0, 1), borderJoin: LineJoinStyle.bevel, @@ -374,10 +317,12 @@ export async function PbfTile2WebglLayers( id: lineFeature.id! as number, type: MapTileFeatureType.line, color: compileStatement(lineStyle.color, lineFeature), - vertecies: lineFeature.geometry.coordinates as Array<[number, number]>, + vertecies: (lineFeature.geometry.coordinates as Array<[number, number]>).map(p => projection.fromLngLat(p)), width: lineStyle.width ? compileStatement(lineStyle.width, lineFeature) : 1, - borderWidth: 0, - borderColor: vec4.fromValues(0, 0, 0, 1), + borderWidth: lineStyle.borderWidth ? compileStatement(lineStyle.borderWidth, lineFeature) : 0, + borderColor: lineStyle.borderColor + ? compileStatement(lineStyle.borderColor, lineFeature) + : vec4.fromValues(0, 0, 0, 0), fill: lineStyle.fillStyle ? compileStatement(lineStyle.fillStyle, lineFeature) : LineFillStyle.solid, join: lineStyle.joinStyle && compileStatement(lineStyle.joinStyle, lineFeature), cap: lineStyle.capStyle && compileStatement(lineStyle.capStyle, lineFeature), @@ -394,10 +339,12 @@ export async function PbfTile2WebglLayers( id: lineFeature.id! as number, type: MapTileFeatureType.line, color: compileStatement(lineStyle.color, lineFeature), - vertecies: lineGeometry as Array<[number, number]>, + vertecies: (lineGeometry as Array<[number, number]>).map(p => projection.fromLngLat(p)), width: lineStyle.width ? compileStatement(lineStyle.width, lineFeature) : 1, - borderWidth: 0, - borderColor: vec4.fromValues(0, 0, 0, 1), + borderWidth: lineStyle.borderWidth ? compileStatement(lineStyle.borderWidth, lineFeature) : 0, + borderColor: lineStyle.borderColor + ? compileStatement(lineStyle.borderColor, lineFeature) + : vec4.fromValues(0, 0, 0, 0), fill: lineStyle.fillStyle ? compileStatement(lineStyle.fillStyle, lineFeature) : LineFillStyle.solid, join: lineStyle.joinStyle && compileStatement(lineStyle.joinStyle, lineFeature), cap: lineStyle.capStyle && compileStatement(lineStyle.capStyle, lineFeature), @@ -409,24 +356,34 @@ export async function PbfTile2WebglLayers( } } - if (!polygonGroupBuilder.isEmpty()) { - objectGroups.push(polygonGroupBuilder.build()); + if (!pointsGroupBuilder.isEmpty()) { + objectGroups.push( + pointsGroupBuilder.build(camera, `${tileId}_${styleLayer.styleLayerName}_points`, styleLayer.zIndex) + ); } if (!lineGroupBuilder.isEmpty()) { - objectGroups.push(lineGroupBuilder.build()); + objectGroups.push( + lineGroupBuilder.build(camera, `${tileId}_${styleLayer.styleLayerName}_lines`, styleLayer.zIndex) + ); } - if (!pointsGroupBuilder.isEmpty()) { - objectGroups.push(pointsGroupBuilder.build()); + if (!polygonGroupBuilder.isEmpty()) { + objectGroups.push( + polygonGroupBuilder.build(camera, `${tileId}_${styleLayer.styleLayerName}_polygons`, styleLayer.zIndex) + ); } if (!textTextureGroupBuilder.isEmpty()) { - objectGroups.push(textTextureGroupBuilder.build()); + objectGroups.push( + textTextureGroupBuilder.build(camera, `${tileId}_${styleLayer.styleLayerName}_text`, styleLayer.zIndex) + ); } if (!glyphGroupBuilder.isEmpty()) { - objectGroups.push(glyphGroupBuilder.build()); + objectGroups.push( + glyphGroupBuilder.build(camera, `${tileId}_${styleLayer.styleLayerName}_glyphs`, styleLayer.zIndex) + ); } const layer: WebGlMapLayer = { diff --git a/src/map/renderer/webgl/utils/array_utils.ts b/src/map/renderer/webgl/utils/array_utils.ts new file mode 100644 index 0000000..8761add --- /dev/null +++ b/src/map/renderer/webgl/utils/array_utils.ts @@ -0,0 +1,9 @@ +export function addXTimes(arr: number[], value: number | number[], times: number) { + for (let i = 0; i < times; i++) { + if (Array.isArray(value)) { + arr.push(...value); + } else { + arr.push(value); + } + } +} diff --git a/src/map/renderer/webgl/utils/webgl_framebuffer.ts b/src/map/renderer/webgl/utils/webgl_framebuffer.ts index 14a6dfc..cf561a8 100644 --- a/src/map/renderer/webgl/utils/webgl_framebuffer.ts +++ b/src/map/renderer/webgl/utils/webgl_framebuffer.ts @@ -15,12 +15,11 @@ export interface WebGlFrameBuffer { export function createFrameBuffer(gl: ExtendedWebGLRenderingContext, options: CreateFrameBufferOptions) { const framebuffer = gl.createFramebuffer(); - const COLOR_ATTACHMENT0 = 0x8ce0; gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); gl.framebufferTexture2D( gl.FRAMEBUFFER, - COLOR_ATTACHMENT0, + gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, options.texture.texture, options.texture.level diff --git a/src/map/renderer/webgl/webgl_camera.ts b/src/map/renderer/webgl/webgl_camera.ts new file mode 100644 index 0000000..f40fb56 --- /dev/null +++ b/src/map/renderer/webgl/webgl_camera.ts @@ -0,0 +1,78 @@ +import { mat3 } from 'gl-matrix'; +import { SceneCamera } from '../renderer'; + +export class WebGlSceneCamera implements SceneCamera { + private _viewMatrix: mat3; + + constructor( + private sceneWidth: number, + private sceneHeight: number, + private eyeX: number, + private eyeY: number, + private _distance: number, + private rotationInDegree: number + ) { + this.recalculateViewMatrix(); + } + get width(): number { + return this.sceneWidth; + } + + get height(): number { + return this.sceneHeight; + } + + get distance(): number { + return this._distance; + } + + get viewMatrix(): [number, number, number, number, number, number, number, number, number] { + return [...this._viewMatrix] as [number, number, number, number, number, number, number, number, number]; + } + + setEye(eyeX: number, eyeY: number) { + this.eyeX = eyeX; + this.eyeY = eyeY; + + this.recalculateViewMatrix(); + } + + setRotation(rotationInDegree: number) { + this.rotationInDegree = rotationInDegree; + + this.recalculateViewMatrix(); + } + + private recalculateViewMatrix() { + this._viewMatrix = getProjectionMatrix( + this.sceneWidth, + this.sceneHeight, + this._distance, + this.eyeX, + this.eyeY, + this.rotationInDegree + ); + } +} + +function getProjectionMatrix( + sceneWidth: number, + sceneHeight: number, + distance: number, + eyeX: number, + eyeY: number, + rotationInDegree: number +): mat3 { + // update camera matrix + const cameraMat = mat3.create(); + mat3.translate(cameraMat, cameraMat, [eyeX, eyeY]); + mat3.scale(cameraMat, cameraMat, [sceneWidth / distance, sceneHeight / distance]); + mat3.rotate(cameraMat, cameraMat, (Math.PI / 180) * rotationInDegree); + + // update view projection matrix + const mat = mat3.create(); + const viewMat = mat3.invert(mat3.create(), cameraMat); + const viewProjectionMat = mat3.multiply(mat, mat, viewMat); + + return viewProjectionMat; +} diff --git a/src/map/renderer/webgl/webgl_map_tile_renderer.ts b/src/map/renderer/webgl/webgl_map_tile_renderer.ts new file mode 100644 index 0000000..34b8ba8 --- /dev/null +++ b/src/map/renderer/webgl/webgl_map_tile_renderer.ts @@ -0,0 +1,63 @@ +import { MapTileRenderer, MapTileRendererType } from '../renderer'; +import { MapFeatureFlags } from '../../flags'; +import { GlyphsManager } from '../../glyphs/glyphs_manager'; +import { FontManager } from '../../font/font_manager'; + +import { WebGlSceneCamera } from './webgl_camera'; +import { WebGlRenderer, WebGlRendererOptions } from './webgl_renderer'; +import { WebGlMapTile } from './tile/webgl_tile'; + +/** + * Wrapper for WebGlRenderer to fit the MapTileRenderer interface. + * Extracts object buffered groups from tiles and deligates render to WebGlRenderer. + */ +export class WebGlMapTileRenderer implements MapTileRenderer { + private readonly renderer: WebGlRenderer; + + constructor( + rootEl: HTMLElement, + featureFlags: MapFeatureFlags, + type: MapTileRendererType.webgl | MapTileRendererType.webgl2, + devicePixelRatio: number, + fontManager: FontManager, + textureManager: GlyphsManager + ) { + this.renderer = new WebGlRenderer(rootEl, featureFlags, type, devicePixelRatio, fontManager, textureManager); + } + + init(): Promise { + return this.renderer.init(); + } + + destroy(): void { + return this.renderer.destroy(); + } + + resize(width: number, height: number): void { + return this.renderer.resize(width, height); + } + + render(tiles: WebGlMapTile[], camera: WebGlSceneCamera, renderOptions?: WebGlRendererOptions): void { + const objectGroups = []; + + for (const tile of tiles) { + for (const layer of tile.layers) { + objectGroups.push(...layer.objectGroups); + } + } + + return this.renderer.render(objectGroups, camera, renderOptions); + } + + getObjectId(tiles: WebGlMapTile[], camera: WebGlSceneCamera, x: number, y: number): number { + const objectGroups = []; + + for (const tile of tiles) { + for (const layer of tile.layers) { + objectGroups.push(...layer.objectGroups); + } + } + + return this.renderer.getObjectId(objectGroups, camera, x, y); + } +} diff --git a/src/map/renderer/webgl/webgl_renderer.ts b/src/map/renderer/webgl/webgl_renderer.ts index c63839e..68364bc 100644 --- a/src/map/renderer/webgl/webgl_renderer.ts +++ b/src/map/renderer/webgl/webgl_renderer.ts @@ -1,13 +1,12 @@ -import { mat3 } from 'gl-matrix'; import { addExtensionsToContext } from 'twgl.js'; -import { Renderer, RenderOptions } from '../renderer'; +import { MapTileRendererType, RenderOptions, SceneCamera } from '../renderer'; import { MapTileFeatureType } from '../../tile/tile'; -import { WebGlMapTile, WebGlMapLayer } from './tile/webgl_tile'; import { ExtendedWebGLRenderingContext } from './webgl_context'; import { ObjectProgram } from './objects/object/object_program'; import { PointProgram } from './objects/point/point_program'; import { PolygonProgram } from './objects/polygon/polygon_program'; import { LineProgram } from './objects/line/line_program'; +import { LineShaderProgram } from './objects/line_shader/line_shader_program'; import { TextTextureProgram } from './objects/text_texture/text_texture_program'; import { TextVectorProgram } from './objects/text_vector/text_vector_program'; import { GlyphProgram } from './objects/glyph/glyph_program'; @@ -20,9 +19,18 @@ import { WebGlFrameBuffer, createFrameBuffer } from './utils/webgl_framebuffer'; import { vector4ToInteger } from './utils/number2vec'; import { FontFormatType } from '../../font/font_config'; import { FontManager } from '../../font/font_manager'; -import { MapTileRendererType } from '../renderer'; +import { WebGlObjectBufferredGroup } from './objects/object/object'; -export class WebGlRenderer implements Renderer { +export interface WebGlRendererOptions extends RenderOptions { + pruneCache?: boolean; + readPixelRenderMode?: boolean; +} + +/** + * Render object using WebGl API. + * Knows how to render objects, manage cache, animation and the order of object render. + */ +export class WebGlRenderer { private canvas: HTMLCanvasElement; private programs: Record; private gl?: ExtendedWebGLRenderingContext; @@ -78,7 +86,9 @@ export class WebGlRenderer implements Renderer { const pointProgram = new PointProgram(gl, this.featureFlags); const polygonProgram = new PolygonProgram(gl, this.featureFlags); - const lineProgram = new LineProgram(gl, this.featureFlags); + const lineProgram = this.featureFlags.webglRendererUseShaderLines + ? new LineShaderProgram(gl, this.featureFlags) + : new LineProgram(gl, this.featureFlags); const glyphProgram = new GlyphProgram(gl, this.featureFlags, this.textureManager); const textProgram = this.featureFlags.webglRendererFontFormatType === FontFormatType.vector @@ -139,20 +149,20 @@ export class WebGlRenderer implements Renderer { private currentStateId?: string; private alreadyRenderedTileLayer = new Set(); - private getCurrentStateId(viewMatrix: mat3, zoom: number, tileSize: number) { - return [...viewMatrix, zoom, tileSize, this.canvas.width, this.canvas.height].join('-'); + private getCurrentStateId(camera: SceneCamera) { + return [...camera.viewMatrix, camera.distance, this.canvas.width, this.canvas.height].join('-'); } - getObjectId(tiles: WebGlMapTile[], viewMatrix: mat3, zoom: number, tileSize: number, x: number, y: number): number { + getObjectId(objects: WebGlObjectBufferredGroup[], camera: SceneCamera, x: number, y: number): number { const gl = this.gl; const pixels = new Uint8Array(4); - this.render(tiles, viewMatrix, zoom, tileSize, { + this.render(objects, camera, { pruneCache: true, readPixelRenderMode: true, }); gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); - this.render(tiles, viewMatrix, zoom, tileSize, { + this.render(objects, camera, { pruneCache: true, readPixelRenderMode: false, }); @@ -160,12 +170,12 @@ export class WebGlRenderer implements Renderer { return vector4ToInteger([pixels[0], pixels[1], pixels[2], pixels[3]]); } - render(tiles: WebGlMapTile[], viewMatrix: mat3, zoom: number, tileSize: number, options: RenderOptions) { + render(objects: WebGlObjectBufferredGroup[], camera: SceneCamera, options: WebGlRendererOptions) { let program: ObjectProgram; let globalUniformsSet = false; let shouldRenderToCanvas = false; - const stateId = this.getCurrentStateId(viewMatrix, zoom, tileSize); + const stateId = this.getCurrentStateId(camera); if (options.pruneCache || this.currentStateId !== stateId) { this.currentStateId = stateId; this.alreadyRenderedTileLayer.clear(); @@ -173,42 +183,37 @@ export class WebGlRenderer implements Renderer { this.debugLog('clear'); } - const sortedLayers = this.getSortedLayers(tiles); - - for (const layer of sortedLayers) { - const { objectGroups, layerName, tileId } = layer as WebGlMapLayer; - const renderLayerId = `${tileId}-${layerName}`; + const sortedObjects = this.getSortedObjects(objects); - if (this.alreadyRenderedTileLayer.has(renderLayerId)) { - this.debugLog(`skip layer render "${renderLayerId}"`); + for (const objectGroup of sortedObjects) { + if (this.alreadyRenderedTileLayer.has(objectGroup.name)) { + this.debugLog(`skip layer render "${objectGroup.name}"`); continue; } else { - this.alreadyRenderedTileLayer.add(renderLayerId); - this.debugLog(`layer render "${renderLayerId}"`); + this.alreadyRenderedTileLayer.add(objectGroup.name); + this.debugLog(`layer render "${objectGroup.name}"`); } if (program && !globalUniformsSet) { - this.setProgramGlobalUniforms(program, viewMatrix, zoom, tileSize, options); + this.setProgramGlobalUniforms(program, camera, options); globalUniformsSet = true; } - for (const objectGroup of objectGroups) { - const prevProgram: ObjectProgram = program; - program = this.programs[objectGroup.type]; - - this.framebuffer.bind(); - prevProgram?.unlink(); - program.link(); - this.setProgramGlobalUniforms(program, viewMatrix, zoom, tileSize, options); - program.drawObjectGroup(objectGroup, { readPixelRenderMode: options.readPixelRenderMode }); - this.framebuffer.unbind(); - shouldRenderToCanvas = true; - } + const prevProgram: ObjectProgram = program; + program = this.programs[objectGroup.type]; + + this.framebuffer.bind(); + prevProgram?.unlink(); + program.link(); + this.setProgramGlobalUniforms(program, camera, options); + program.drawObjectGroup(objectGroup, { readPixelRenderMode: options.readPixelRenderMode }); + this.framebuffer.unbind(); + shouldRenderToCanvas = true; } if (shouldRenderToCanvas) { this.framebufferProgram.link(); - this.setProgramGlobalUniforms(this.framebufferProgram, viewMatrix, zoom, tileSize, options); + this.setProgramGlobalUniforms(this.framebufferProgram, camera, options); this.framebufferProgram.draw(this.frameBufferTexture); this.framebufferProgram.unlink(); this.debugLog(`canvas render`); @@ -224,26 +229,12 @@ export class WebGlRenderer implements Renderer { } } - private getSortedLayers(tiles: WebGlMapTile[]): WebGlMapLayer[] { - const layers: WebGlMapLayer[] = []; - - for (const tile of tiles) { - layers.push(...tile.layers); - } - - return layers.sort((l1, l2) => l1.zIndex - l2.zIndex); + private getSortedObjects(objects: WebGlObjectBufferredGroup[]): WebGlObjectBufferredGroup[] { + return [...objects].sort((g1, g2) => g1.zIndex - g2.zIndex); } - private setProgramGlobalUniforms( - program: ObjectProgram, - viewMatrix: mat3, - zoom: number, - tileSize: number, - options: RenderOptions - ) { - program.setMatrix(viewMatrix); - program.setZoom(zoom); - program.setTileSize(tileSize); + private setProgramGlobalUniforms(program: ObjectProgram, camera: SceneCamera, options: WebGlRendererOptions) { + program.setMatrix(camera.viewMatrix); program.setWidth(this.rootEl.offsetWidth); program.setHeight(this.rootEl.offsetHeight); program.setReadPixelRenderMode(options.readPixelRenderMode || false); diff --git a/src/map/styles/styles.ts b/src/map/styles/styles.ts index 7ca89dc..432215c 100644 --- a/src/map/styles/styles.ts +++ b/src/map/styles/styles.ts @@ -83,6 +83,8 @@ export interface LineStyle { joinStyle?: Statement; // default: none capStyle?: Statement; width?: Statement; // default 1 + borderWidth?: Statement; // default 1 + borderColor?: Statement; // default <0, 0, 0, 0> show?: Statement; minzoom?: number; maxzoom?: number; diff --git a/src/map/tile/tile_grid.ts b/src/map/tile/tile_grid.ts index da583fb..6824651 100644 --- a/src/map/tile/tile_grid.ts +++ b/src/map/tile/tile_grid.ts @@ -25,7 +25,7 @@ export enum TilesGridEvent { export class TilesGrid extends Evented { private tiles: LRUCache; - private tilesInView: TileRef[]; + private tilesInView: TileRef[] = []; private workerPool: WorkerPool; private bufferedTiles: TileRef[]; private currentLoadingTiles: Map = new Map(); @@ -49,7 +49,6 @@ export class TilesGrid extends Evented { } init() { - this.tilesInView = []; this.workerPool = new WorkerPool(this.maxWorkerPool); }