diff --git a/play-services-maps-core-mapbox/build.gradle b/play-services-maps-core-mapbox/build.gradle index 7c310449832ad38d8bc3816ad1a76bd836945c9e..7db8b0ee424076b74906cc88e12ea7606c022aa7 100644 --- a/play-services-maps-core-mapbox/build.gradle +++ b/play-services-maps-core-mapbox/build.gradle @@ -20,12 +20,12 @@ apply plugin: 'kotlin-android' dependencies { implementation project(':play-services-maps') implementation project(':play-services-base-core') - implementation("org.maplibre.gl:android-sdk:9.6.0") { - exclude group: 'com.google.android.gms' - } + implementation("org.maplibre.gl:android-sdk:10.0.0") implementation("org.maplibre.gl:android-plugin-annotation-v9:1.0.0") { exclude group: 'com.google.android.gms' } + implementation 'org.maplibre.gl:android-sdk-turf:5.9.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" } @@ -39,6 +39,9 @@ def execResult(...args) { } def mapboxKey() { + String environmentKey = System.getenv('MAPBOX_VECTOR_TILES_KEY') + if (environmentKey != null) return environmentKey + Properties properties = new Properties() try { properties.load(project.rootProject.file('local.properties').newDataInputStream()) diff --git a/play-services-maps-core-mapbox/src/main/assets/style-mapbox-outdoors-v12.json b/play-services-maps-core-mapbox/src/main/assets/style-mapbox-outdoors-v12.json new file mode 100644 index 0000000000000000000000000000000000000000..21c4d40f556edc72190f68dd5094879fc3974c1b --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/assets/style-mapbox-outdoors-v12.json @@ -0,0 +1,13845 @@ +{ + "name": "Mapbox Outdoors", + "sprite": "mapbox://sprites/mapbox/outdoors-v12", + "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", + "center": [ + 9.1, + 42.2 + ], + "zoom": 7.5, + "fog": { + "range": [ + 1, + 20 + ], + "color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 4, + "hsl(200, 100%, 100%)", + 6, + "hsl(200, 50%, 90%)" + ], + "high-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 4, + "hsl(200, 100%, 60%)", + 6, + "hsl(310, 60%, 80%)" + ], + "space-color": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 4, + "hsl(205, 10%, 10%)", + 6, + "hsl(205, 60%, 50%)" + ], + "horizon-blend": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 4, + 0.01, + 6, + 0.1 + ], + "star-intensity": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 4, + 0.1, + 6, + 0 + ] + }, + "projection": { + "name": "globe" + }, + "visibility": "public", + "version": 8, + "layers": [ + { + "id": "land", + "type": "background", + "layout": {}, + "minzoom": 0, + "paint": { + "background-color": "hsl(60, 20%, 85%)" + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, land", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "landcover", + "type": "fill", + "source": "composite", + "source-layer": "landcover", + "minzoom": 0, + "maxzoom": 12, + "layout": {}, + "paint": { + "fill-color": [ + "match", + [ + "get", + "class" + ], + "wood", + "hsla(103, 50%, 60%, 0.8)", + "scrub", + "hsla(98, 47%, 68%, 0.6)", + "crop", + "hsla(68, 55%, 70%, 0.6)", + "grass", + "hsla(98, 50%, 74%, 0.6)", + "snow", + "hsl(205, 45%, 95%)", + "hsl(98, 48%, 67%)" + ], + "fill-opacity": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 8, + 0.8, + 12, + 0 + ], + "fill-antialias": false + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, land", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "national-park", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "minzoom": 5, + "filter": [ + "==", + [ + "get", + "class" + ], + "national_park" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(98, 38%, 68%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 5, + 0, + 6, + 0.6, + 12, + 0.2 + ] + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, land", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "national-park_tint-band", + "type": "line", + "source": "composite", + "source-layer": "landuse_overlay", + "minzoom": 9, + "filter": [ + "==", + [ + "get", + "class" + ], + "national_park" + ], + "layout": {}, + "paint": { + "line-color": "hsl(98, 38%, 68%)", + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 9, + 1, + 14, + 8 + ], + "line-blur": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 9, + 1, + 14, + 8 + ] + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, land", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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 + ], + "rock", + [ + "step", + [ + "zoom" + ], + false, + 11, + 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(103, 50%, 60%, 0.8)", + "scrub", + "hsla(98, 47%, 68%, 0.6)", + "agriculture", + "hsla(98, 50%, 74%, 0.6)", + "park", + [ + "match", + [ + "get", + "type" + ], + [ + "garden", + "playground", + "zoo" + ], + "hsl(98, 38%, 68%)", + "hsl(98, 55%, 70%)" + ], + "grass", + "hsla(98, 50%, 74%, 0.6)", + "airport", + "hsl(230, 40%, 82%)", + "cemetery", + "hsl(98, 45%, 75%)", + "glacier", + "hsl(205, 45%, 95%)", + "hospital", + "hsl(20, 45%, 82%)", + "pitch", + "hsl(88, 65%, 75%)", + "sand", + "hsl(69, 60%, 72%)", + "rock", + "hsl(60, 0%, 85%)", + "school", + "hsl(40, 45%, 78%)", + "commercial_area", + "hsl(55, 45%, 85%)", + "residential", + "hsl(60, 7%, 87%)", + [ + "facility", + "industrial" + ], + "hsl(230, 20%, 85%)", + "hsl(60, 22%, 72%)" + ], + 16, + [ + "match", + [ + "get", + "class" + ], + "wood", + "hsla(103, 50%, 60%, 0.8)", + "scrub", + "hsla(98, 47%, 68%, 0.6)", + "agriculture", + "hsla(98, 50%, 74%, 0.6)", + "park", + [ + "match", + [ + "get", + "type" + ], + [ + "garden", + "playground", + "zoo" + ], + "hsl(98, 38%, 68%)", + "hsl(98, 55%, 70%)" + ], + "grass", + "hsla(98, 50%, 74%, 0.6)", + "airport", + "hsl(230, 40%, 82%)", + "cemetery", + "hsl(98, 45%, 75%)", + "glacier", + "hsl(205, 45%, 95%)", + "hospital", + "hsl(20, 45%, 82%)", + "pitch", + "hsl(88, 65%, 75%)", + "sand", + "hsl(69, 60%, 72%)", + "rock", + "hsla(60, 0%, 85%, 0.5)", + "school", + "hsl(40, 45%, 78%)", + "commercial_area", + "hsla(55, 45%, 85%, 0.5)", + [ + "facility", + "industrial" + ], + "hsl(230, 20%, 85%)", + "hsl(60, 22%, 72%)" + ] + ], + "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", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "pitch-outline", + "type": "line", + "source": "composite", + "source-layer": "landuse", + "minzoom": 15, + "filter": [ + "==", + [ + "get", + "class" + ], + "pitch" + ], + "layout": {}, + "paint": { + "line-color": "hsl(88, 60%, 65%)" + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, land", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(224, 79%, 69%)", + "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", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "water-shadow", + "type": "fill", + "source": "composite", + "source-layer": "water", + "minzoom": 10, + "layout": {}, + "paint": { + "fill-color": "hsl(224, 79%, 69%)", + "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", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(205, 75%, 70%)", + "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", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "water", + "type": "fill", + "source": "composite", + "source-layer": "water", + "minzoom": 0, + "layout": {}, + "paint": { + "fill-color": "hsl(205, 75%, 70%)" + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, water", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(205, 75%, 70%, 0.35)", + 200, + "hsla(205, 75%, 63%, 0.35)", + 7000, + "hsla(205, 75%, 56%, 0.35)" + ], + 8, + [ + "interpolate", + [ + "linear" + ], + [ + "get", + "min_depth" + ], + 0, + "hsla(205, 75%, 70%, 0)", + 200, + "hsla(205, 75%, 63%, 0)", + 7000, + "hsla(205, 75%, 53%, 0)" + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, water", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "wetland", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "minzoom": 5, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "wetland", + "wetland_noveg" + ], + true, + false + ], + "paint": { + "fill-color": "hsl(194, 38%, 74%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 0.25, + 10.5, + 0.15 + ] + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, water", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "wetland-pattern", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "minzoom": 5, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "wetland", + "wetland_noveg" + ], + true, + false + ], + "paint": { + "fill-color": "hsl(194, 38%, 74%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 0, + 10.5, + 1 + ], + "fill-pattern": "wetland", + "fill-translate-anchor": "viewport" + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, water", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(66, 38%, 17%, 0.08)", + "hsla(60, 20%, 95%, 0.14)" + ], + 16, + [ + "match", + [ + "get", + "class" + ], + "shadow", + "hsla(66, 38%, 17%, 0)", + "hsla(60, 20%, 95%, 0)" + ] + ], + "fill-antialias": false + }, + "metadata": { + "mapbox:featureComponent": "terrain", + "mapbox:group": "Terrain, land", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "contour-line", + "type": "line", + "source": "composite", + "source-layer": "contour", + "minzoom": 11, + "filter": [ + "!=", + [ + "get", + "index" + ], + -1 + ], + "layout": {}, + "paint": { + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 11, + [ + "match", + [ + "get", + "index" + ], + [ + 1, + 2 + ], + 0.15, + 0.3 + ], + 13, + [ + "match", + [ + "get", + "index" + ], + [ + 1, + 2 + ], + 0.3, + 0.5 + ] + ], + "line-color": "hsl(60, 10%, 35%)", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + [ + "match", + [ + "get", + "index" + ], + [ + 1, + 2 + ], + 0.5, + 0.6 + ], + 16, + [ + "match", + [ + "get", + "index" + ], + [ + 1, + 2 + ], + 0.8, + 1.2 + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "terrain", + "mapbox:group": "Terrain, land", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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": "hsl(60, 20%, 85%)" + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, built", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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": "hsl(60, 20%, 85%)" + }, + "metadata": { + "mapbox:featureComponent": "land-and-water", + "mapbox:group": "Land & water, built", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(230, 36%, 74%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 0, + 11, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, built", + "microg:gms-type-feature": "transit.station.airport", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "aeroway-line", + "type": "line", + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "==", + [ + "geometry-type" + ], + "LineString" + ], + "paint": { + "line-color": "hsl(230, 36%, 74%)", + "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", + "microg:gms-type-feature": "transit.station.airport", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(50, 15%, 75%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0, + 16, + 1 + ], + "fill-outline-color": "hsl(60, 10%, 65%)" + }, + "metadata": { + "mapbox:featureComponent": "buildings", + "mapbox:group": "Buildings, built", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(260, 60%, 85%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0, + 16, + 0.5 + ] + }, + "metadata": { + "mapbox:featureComponent": "buildings", + "mapbox:group": "Buildings, built", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 3%, 57%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 3%, 57%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 3%, 57%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 3%, 57%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "tunnel-path-trail", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + [ + "get", + "structure" + ], + "tunnel" + ], + [ + "==", + [ + "get", + "class" + ], + "path" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "hiking", + "mountain_bike", + "trail" + ], + true, + false + ], + [ + "==", + [ + "geometry-type" + ], + "LineString" + ] + ], + "layout": {}, + "paint": { + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 15, + 1, + 18, + 4 + ], + "line-color": "hsl(60, 32%, 90%)", + "line-dasharray": [ + "step", + [ + "zoom" + ], + [ + "literal", + [ + 5, + 0.5 + ] + ], + 15, + [ + "literal", + [ + 4, + 0.5 + ] + ], + 16, + [ + "literal", + [ + 4, + 0.45 + ] + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "tunnel-path-cycleway-piste", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + [ + "get", + "structure" + ], + "tunnel" + ], + [ + "==", + [ + "get", + "class" + ], + "path" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "cycleway", + "piste" + ], + true, + false + ], + [ + "==", + [ + "geometry-type" + ], + "LineString" + ] + ], + "layout": {}, + "paint": { + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 15, + 1, + 18, + 4 + ], + "line-color": "hsl(60, 32%, 90%)", + "line-dasharray": [ + 10, + 0 + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 32%, 90%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 32%, 90%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 22%, 80%)", + "hsl(0, 0%, 95%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 100%, 85%)", + "hsl(35, 78%, 85%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 22%, 80%)", + "hsl(0, 0%, 95%)" + ], + "line-opacity": [ + "step", + [ + "zoom" + ], + 0, + 14, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 100%, 85%)", + "hsl(35, 78%, 85%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, tunnels", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "labels.icon" + } + }, + { + "id": "cliff", + "type": "line", + "source": "composite", + "source-layer": "structure", + "minzoom": 15, + "filter": [ + "==", + [ + "get", + "class" + ], + "cliff" + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0, + 15.25, + 1 + ], + "line-width": 10, + "line-pattern": "cliff" + }, + "metadata": { + "mapbox:featureComponent": "terrain", + "mapbox:group": "Terrain, surface", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "ferry", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 8, + "filter": [ + "==", + [ + "get", + "type" + ], + "ferry" + ], + "paint": { + "line-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + "hsl(214, 68%, 63%)", + 17, + "hsl(239, 68%, 63%)" + ], + "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", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(214, 68%, 63%)", + 17, + "hsl(239, 68%, 63%)" + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 14, + 0.5, + 20, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, ferries", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 20%, 85%)" + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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": [ + "match", + [ + "get", + "type" + ], + "piste", + "hsl(215, 80%, 48%)", + [ + "mountain_bike", + "hiking", + "trail", + "cycleway", + "footway", + "path", + "bridleway" + ], + "hsl(35, 80%, 48%)", + "hsl(60, 1%, 64%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(35, 80%, 48%)", + "line-opacity": 0.75 + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)" + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "road-path-trail", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "path" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "hiking", + "mountain_bike", + "trail" + ], + true, + false + ], + [ + "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, + 1, + 18, + 4 + ], + "line-color": "hsl(0, 0%, 95%)", + "line-dasharray": [ + "step", + [ + "zoom" + ], + [ + "literal", + [ + 5, + 0.5 + ] + ], + 15, + [ + "literal", + [ + 4, + 0.5 + ] + ], + 16, + [ + "literal", + [ + 4, + 0.45 + ] + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "road-path-cycleway-piste", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "path" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "cycleway", + "piste" + ], + true, + false + ], + [ + "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, + 1, + 18, + 4 + ], + "line-color": "hsl(0, 0%, 95%)", + "line-dasharray": [ + 10, + 0 + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 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., surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "golf-hole-line", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "==", + [ + "get", + "class" + ], + "golf" + ], + "paint": { + "line-color": "hsl(98, 26%, 56%)" + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., surface", + "microg:gms-type-feature": "poi.attraction", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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%, 95%)", + "fill-outline-color": "hsl(60, 10%, 70%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "circle-stroke-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0.8, + 16, + 1.2, + 18, + 2 + ], + "circle-stroke-color": "hsl(60, 10%, 70%)", + "circle-pitch-alignment": "map" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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": [ + "match", + [ + "get", + "class" + ], + "track", + "hsl(35, 80%, 48%)", + "hsl(60, 10%, 70%)" + ], + "line-gap-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 14, + 1, + 18, + 10, + 22, + 100 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "line-gap-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 3, + 0, + 18, + 26, + 22, + 260 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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%, 95%)", + "circle-pitch-alignment": "map" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 100%, 75%)", + "hsl(35, 89%, 75%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 22%, 80%)", + "hsl(0, 0%, 95%)" + ], + "line-opacity": [ + "step", + [ + "zoom" + ], + 0, + 14, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 88%, 69%)", + "trunk", + "hsl(35, 81%, 59%)", + "hsl(60, 18%, 85%)" + ], + 9, + [ + "match", + [ + "get", + "class" + ], + "motorway", + "hsl(15, 100%, 75%)", + "hsl(35, 89%, 75%)" + ] + ], + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 3, + 0, + 3.5, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, surface", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(75, 25%, 68%)", + 16, + "hsl(60, 0%, 56%)" + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 14, + 0.5, + 20, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, surface", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(75, 25%, 68%)", + 16, + "hsl(60, 0%, 56%)" + ], + "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", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.icon" + } + }, + { + "id": "gate-fence-hedge", + "type": "line", + "source": "composite", + "source-layer": "structure", + "minzoom": 16, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "gate", + "fence", + "hedge" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": [ + "match", + [ + "get", + "class" + ], + "hedge", + "hsl(98, 32%, 56%)", + "hsl(60, 25%, 63%)" + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 16, + 1, + 20, + 3 + ], + "line-opacity": [ + "match", + [ + "get", + "class" + ], + "gate", + 0.5, + 1 + ], + "line-dasharray": [ + 1, + 2, + 5, + 2, + 1, + 2 + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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": [ + "match", + [ + "get", + "type" + ], + "piste", + "hsl(215, 80%, 48%)", + [ + "mountain_bike", + "hiking", + "trail", + "cycleway", + "footway", + "path", + "bridleway" + ], + "hsl(35, 80%, 48%)", + "hsl(60, 1%, 64%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(35, 80%, 48%)", + "line-opacity": 0.75 + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)" + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "bridge-path-trail", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + [ + "get", + "structure" + ], + "bridge" + ], + [ + "==", + [ + "get", + "class" + ], + "path" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "hiking", + "mountain_bike", + "trail" + ], + true, + false + ], + [ + "==", + [ + "geometry-type" + ], + "LineString" + ] + ], + "layout": {}, + "paint": { + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 15, + 1, + 18, + 4 + ], + "line-color": "hsl(0, 0%, 95%)", + "line-dasharray": [ + "step", + [ + "zoom" + ], + [ + "literal", + [ + 5, + 0.5 + ] + ], + 15, + [ + "literal", + [ + 4, + 0.5 + ] + ], + 16, + [ + "literal", + [ + 4, + 0.45 + ] + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "id": "bridge-path-cycleway-piste", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + [ + "get", + "structure" + ], + "bridge" + ], + [ + "==", + [ + "get", + "class" + ], + "path" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "cycleway", + "piste" + ], + true, + false + ], + [ + "==", + [ + "geometry-type" + ], + "LineString" + ] + ], + "layout": {}, + "paint": { + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 15, + 1, + 18, + 4 + ], + "line-color": "hsl(0, 0%, 95%)", + "line-dasharray": [ + 10, + 0 + ] + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 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., barriers-bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "gate-label", + "type": "symbol", + "source": "composite", + "source-layer": "structure", + "minzoom": 16, + "filter": [ + "==", + [ + "get", + "class" + ], + "gate" + ], + "layout": { + "icon-image": [ + "match", + [ + "get", + "type" + ], + "gate", + "gate", + "lift_gate", + "lift-gate", + "" + ] + }, + "paint": {}, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., barriers-bridges", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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": [ + "match", + [ + "get", + "class" + ], + "track", + "hsl(35, 80%, 48%)", + "hsl(60, 10%, 70%)" + ], + "line-gap-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 14, + 1, + 18, + 10, + 22, + 100 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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": [ + "match", + [ + "get", + "class" + ], + "track", + "hsl(35, 80%, 48%)", + "hsl(60, 10%, 70%)" + ], + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 70%)", + "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", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 100%, 75%)", + "hsl(35, 89%, 75%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 22%, 80%)", + "hsl(0, 0%, 95%)" + ], + "line-opacity": [ + "step", + [ + "zoom" + ], + 0, + 14, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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%, 95%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 100%, 75%)", + "hsl(35, 89%, 75%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(60, 10%, 82%)", + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(15, 100%, 75%)", + "hsl(35, 89%, 75%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(15, 100%, 75%)", + "hsl(35, 89%, 75%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, bridges", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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(75, 25%, 68%)", + 16, + "hsl(60, 0%, 56%)" + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 14, + 0.5, + 20, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, bridges", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(75, 25%, 68%)", + 16, + "hsl(60, 0%, 56%)" + ], + "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", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "aerialway", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "==", + [ + "get", + "class" + ], + "aerialway" + ], + "paint": { + "line-color": "hsl(230, 50%, 60%)", + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 14, + 1, + 20, + 2 + ], + "line-dasharray": [ + 4, + 1 + ] + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, elevated", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(350, 90%, 88%)", + "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", + "microg:gms-type-feature": "administrative.province", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(350, 90%, 88%)", + "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", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "geometry.stroke" + } + }, + { + "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(350, 30%, 55%)" + }, + "metadata": { + "mapbox:featureComponent": "admin-boundaries", + "mapbox:group": "Administrative boundaries, admin", + "microg:gms-type-feature": "administrative.province", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(350, 30%, 50%)", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 3, + 0.5, + 12, + 2 + ], + "line-dasharray": [ + "step", + [ + "zoom" + ], + [ + "literal", + [ + 2, + 0 + ] + ], + 7, + [ + "literal", + [ + 2, + 2, + 6, + 2 + ] + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "admin-boundaries", + "mapbox:group": "Administrative boundaries, admin", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "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(350, 30%, 50%)", + "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", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "contour-label", + "type": "symbol", + "source": "composite", + "source-layer": "contour", + "minzoom": 11, + "filter": [ + "any", + [ + "==", + [ + "get", + "index" + ], + 10 + ], + [ + "==", + [ + "get", + "index" + ], + 5 + ] + ], + "layout": { + "text-field": [ + "concat", + [ + "get", + "ele" + ], + " m" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-max-angle": 25, + "text-padding": 5, + "text-font": [ + "DIN Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 9.5, + 20, + 12 + ] + }, + "paint": { + "text-color": "hsl(60, 10%, 35%)", + "text-halo-width": 1, + "text-halo-color": "hsl(60, 10%, 85%)" + }, + "metadata": { + "mapbox:featureComponent": "terrain", + "mapbox:group": "Terrain, terrain-labels", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(60, 8%, 38%)", + "text-halo-color": "hsl(60, 13%, 77%)", + "text-halo-width": 1, + "icon-opacity": 0.4 + }, + "metadata": { + "mapbox:featureComponent": "buildings", + "mapbox:group": "Buildings, building-labels", + "microg:gms-type-feature": "poi", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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(60, 8%, 38%)", + "text-halo-color": "hsl(60, 13%, 77%)", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:featureComponent": "buildings", + "mapbox:group": "Buildings, building-labels", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(60, 18%, 44%)", + "text-halo-color": "hsl(60, 17%, 84%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "metadata": { + "mapbox:featureComponent": "buildings", + "mapbox:group": "Buildings, building-labels", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "labels.text" + } + }, + { + "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", + "track" + ], + 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", + "track" + ], + 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", + "track" + ], + 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(60, 25%, 100%, 0.75)", + "hsl(60, 25%, 100%)" + ], + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, road-labels", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.text" + } + }, + { + "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, 36%, 64%)" + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, road-labels", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.text" + } + }, + { + "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, 63%, 70%)", + "orange", + "hsl(25, 63%, 75%)", + "blue", + "hsl(230, 36%, 44%)", + "red", + "hsl(0, 54%, 59%)", + "green", + "hsl(140, 46%, 37%)", + "hsl(230, 11%, 13%)" + ], + [ + "match", + [ + "get", + "shield_text_color" + ], + "white", + "hsl(0, 0%, 100%)", + "yellow", + "hsl(50, 63%, 70%)", + "orange", + "hsl(25, 63%, 75%)", + "blue", + "hsl(230, 36%, 44%)", + "red", + "hsl(0, 54%, 59%)", + "green", + "hsl(140, 46%, 37%)", + "hsl(230, 11%, 13%)" + ] + ] + }, + "metadata": { + "mapbox:featureComponent": "road-network", + "mapbox:group": "Road network, road-labels", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + } + }, + { + "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(60, 25%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., walking-cycling-labels", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(98, 60%, 55%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5, + "text-color": "hsl(100, 80%, 18%)" + }, + "metadata": { + "mapbox:featureComponent": "walking-cycling", + "mapbox:group": "Walking, cycling, etc., walking-cycling-labels", + "microg:gms-type-feature": "poi.attraction", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(205, 43%, 100%)", + "hsl(230, 50%, 60%)" + ], + "text-halo-color": [ + "match", + [ + "get", + "class" + ], + "ferry", + "hsl(205, 75%, 70%)", + "hsl(60, 20%, 100%)" + ], + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, ferry-aerialway-labels", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(205, 43%, 90%)", + "text-halo-color": "hsla(60, 17%, 84%, 0.5)" + }, + "metadata": { + "mapbox:featureComponent": "natural-features", + "mapbox:group": "Natural features, natural-labels", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "labels.text" + } + }, + { + "id": "natural-line-label", + "type": "symbol", + "metadata": { + "mapbox:featureComponent": "natural-features", + "mapbox:group": "Natural features, natural-labels", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "labels.text" + }, + "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" + ], + 4 + ], + [ + "==", + [ + "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(60, 17%, 84%)", + "text-halo-blur": 0.5, + "text-color": "hsl(340, 10%, 38%)" + } + }, + { + "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" + ], + 4 + ], + [ + "==", + [ + "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.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(60, 20%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5, + "text-color": "hsl(340, 10%, 38%)" + }, + "metadata": { + "mapbox:featureComponent": "natural-features", + "mapbox:group": "Natural features, natural-labels", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "labels.text" + } + }, + { + "id": "water-line-label", + "type": "symbol", + "metadata": { + "mapbox:featureComponent": "natural-features", + "mapbox:group": "Natural features, natural-labels", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "labels.text" + }, + "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(205, 71%, 90%)", + "hsl(205, 43%, 90%)" + ], + "text-halo-color": "hsla(60, 17%, 84%, 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(205, 71%, 90%)", + "hsl(205, 43%, 90%)" + ], + "text-halo-color": "hsla(60, 17%, 84%, 0.5)" + }, + "metadata": { + "mapbox:featureComponent": "natural-features", + "mapbox:group": "Natural features, natural-labels", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "labels.text" + } + }, + { + "id": "poi-label", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "minzoom": 6, + "filter": [ + "<=", + [ + "get", + "filterrank" + ], + [ + "+", + [ + "step", + [ + "zoom" + ], + 0, + 16, + 1, + 17, + 2 + ], + [ + "match", + [ + "get", + "class" + ], + "food_and_drink_stores", + 3, + "historic", + 3, + "landmark", + 3, + "medical", + 3, + "motorist", + 3, + "park_like", + 4, + "sport_and_leisure", + 4, + "visitor_amenities", + 4, + 2 + ] + ] + ], + "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(60, 20%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5, + "text-color": [ + "match", + [ + "get", + "class" + ], + "food_and_drink", + "hsl(35, 80%, 38%)", + "park_like", + "hsl(100, 80%, 18%)", + "education", + "hsl(30, 60%, 28%)", + "medical", + "hsl(10, 60%, 43%)", + "sport_and_leisure", + "hsl(210, 60%, 38%)", + "hsl(340, 10%, 38%)" + ] + }, + "metadata": { + "mapbox:featureComponent": "point-of-interest-labels", + "mapbox:group": "Point of interest labels, poi-labels", + "microg:gms-type-feature": "poi", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(60, 20%, 100%)", + "text-color": [ + "match", + [ + "get", + "network" + ], + "tokyo-metro", + "hsl(180, 30%, 30%)", + "mexico-city-metro", + "hsl(25, 63%, 63%)", + [ + "barcelona-metro", + "delhi-metro", + "hong-kong-mtr", + "milan-metro", + "osaka-subway" + ], + "hsl(0, 57%, 47%)", + [ + "boston-t", + "washington-metro" + ], + "hsl(230, 11%, 20%)", + [ + "chongqing-rail-transit", + "kiev-metro", + "singapore-mrt", + "taipei-metro" + ], + "hsl(140, 56%, 25%)", + "hsl(230, 50%, 60%)" + ], + "text-halo-blur": 0.5, + "text-halo-width": 0.5 + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, transit-labels", + "microg:gms-type-feature": "transit.station.bus", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(230, 40%, 55%)", + "text-halo-color": "hsl(60, 20%, 100%)", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:featureComponent": "transit", + "mapbox:group": "Transit, transit-labels", + "microg:gms-type-feature": "transit.station.airport", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(60, 25%, 100%, 0.75)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 36%)", + "text-halo-blur": 0.5 + }, + "metadata": { + "mapbox:featureComponent": "place-labels", + "mapbox:group": "Place labels, place-labels", + "microg:gms-type-feature": "administrative.neighborhood", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(230, 29%, 0%)", + "text-halo-color": "hsl(60, 25%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:featureComponent": "place-labels", + "mapbox:group": "Place labels, place-labels", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(230, 29%, 0%)", + "text-halo-color": "hsl(60, 25%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:featureComponent": "place-labels", + "mapbox:group": "Place labels, place-labels", + "microg:gms-type-feature": "administrative.land_parcel", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(230, 29%, 0%)", + "text-halo-color": "hsl(60, 25%, 100%)", + "text-halo-width": 1, + "text-opacity": 0.5 + }, + "metadata": { + "mapbox:featureComponent": "place-labels", + "mapbox:group": "Place labels, place-labels", + "microg:gms-type-feature": "administrative.province", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(230, 29%, 0%)", + "text-halo-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 2, + "hsla(60, 25%, 100%, 0.75)", + 3, + "hsl(60, 25%, 100%)" + ], + "text-halo-width": 1.25 + }, + "metadata": { + "mapbox:featureComponent": "place-labels", + "mapbox:group": "Place labels, place-labels", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "labels.text" + } + }, + { + "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(230, 29%, 0%)", + "text-halo-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + "hsla(60, 25%, 100%, 0.75)", + 3, + "hsl(60, 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", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "labels.text" + } + } + ], + "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": "outdoors-v12", + "draft": false +} diff --git a/play-services-maps-core-mapbox/src/main/assets/style-microg-normal.json b/play-services-maps-core-mapbox/src/main/assets/style-microg-normal.json new file mode 100644 index 0000000000000000000000000000000000000000..295ffad4467a317460199e96904752c92bffd624 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/assets/style-microg-normal.json @@ -0,0 +1,4392 @@ +{ + "version": 8, + "name": "Mountain View Full", + "metadata": { + "mapbox:origin": "basic-template", + "mapbox:autocomposite": true, + "mapbox:type": "template", + "mapbox:sdk-support": { + "js": "0.50.0", + "android": "6.7.0", + "ios": "4.6.0" + }, + "mapbox:trackposition": false, + "mapbox:groups": { + "f51b507d2a17e572c70a5db74b0fec7e": { + "name": "Base", + "collapsed": false + }, + "3f48b8dc54ff2e6544b9ef9cedbf2990": { + "name": "Streets", + "collapsed": true + }, + "29bb589e8d1b9b402583363648b70302": { + "name": "Buildings", + "collapsed": true + }, + "3c26e9cbc75335c6f0ba8de5439cf1fa": { + "name": "Country borders", + "collapsed": true + }, + "7b44201d7f1682d99f7140188aff23ce": { + "name": "Labels", + "collapsed": true + }, + "24306bdccbff03e2ee08d5d1a4ca7312": { + "name": "Street name", + "collapsed": true + }, + "124a9d7a8e5226775d947c592110dfad": { + "name": "POI", + "collapsed": true + } + }, + "mapbox:uiParadigm": "layers" + }, + "center": [ + 12.819420849458652, + 50.03325860617235 + ], + "zoom": 3.315829104862067, + "bearing": 0, + "pitch": 1.5, + "light": { + "intensity": 0.5, + "color": "hsl(0, 0%, 100%)", + "anchor": "viewport" + }, + "sources": { + "composite": { + "url": "mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/microg/cjui4020201oo1fmca7yuwbor/8fkcj5fgn4mftlzuak3guz1f9", + "glyphs": "mapbox://fonts/microg/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "layout": {}, + "paint": { + "background-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 4, + "hsl(43, 30%, 91%)", + 5, + "hsl(0, 0%, 96%)", + 8, + "hsl(0, 0%, 96%)", + 9, + "#efeee8", + 16, + "hsl(0, 0%, 95%)", + 18, + "#f8f9fb" + ] + }, + "metadata": { + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "grass", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landcover", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "grass" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + "hsl(124, 30%, 90%)", + 11, + "hsl(107, 30%, 94%)", + 12.5, + "hsl(107, 30%, 94%)", + 13.5, + "hsl(45, 12%, 93%)" + ] + } + }, + { + "id": "forrest", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landcover", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "wood", + "scrub" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + "hsl(124, 42%, 86%)", + 11, + "hsl(107, 47%, 94%)", + 12.5, + "hsl(107, 47%, 94%)", + 13.5, + "hsl(45, 12%, 93%)" + ] + } + }, + { + "id": "national_park", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landuse_overlay", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "national_park" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": "hsl(106, 58%, 85%)" + } + }, + { + "id": "snow", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landcover", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "snow" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": "#f9fafc" + } + }, + { + "id": "hillshade", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "hillshade", + "layout": {}, + "paint": { + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 0.03, + 13, + 0 + ] + } + }, + { + "id": "park", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "poi.park", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landuse", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "park", + "scrub" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": "#c1ecaf" + } + }, + { + "id": "pitch", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.natural.terrain", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landuse", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "pitch" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": "#c8efbb" + } + }, + { + "id": "landuse", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "landuse", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "airport", + "school", + "hospital" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": "hsl(202, 26%, 94%)" + } + }, + { + "id": "river", + "type": "fill", + "metadata": { + "mapbox:group": "f51b507d2a17e572c70a5db74b0fec7e", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": { + "fill-color": "hsl(206, 100%, 83%)" + } + }, + { + "id": "path", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "path" + ], + true, + false + ], + [ + "match", + [ + "get", + "type" + ], + [ + "platform", + "steps" + ], + false, + true + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(118, 34%, 66%)", + "line-dasharray": [ + 4, + 2 + ] + } + }, + { + "id": "steps", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "path" + ], + true, + false + ], + [ + "match", + [ + "get", + "type" + ], + [ + "steps" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(118, 5%, 66%)", + "line-dasharray": [ + 1, + 1 + ], + "line-gap-width": 1 + } + }, + { + "id": "platform", + "type": "fill", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "transit.station.rail", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "type" + ], + [ + "platform" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + false, + true + ] + ], + "layout": {}, + "paint": { + "fill-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + "hsl(2, 20%, 92%)", + 16, + "hsl(2, 95%, 92%)" + ], + "fill-outline-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + "hsl(1, 10%, 76%)", + 16, + "hsl(1, 74%, 76%)" + ], + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0, + 16, + 1 + ] + } + }, + { + "id": "primary_tunnel_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 7, + 0, + 8, + 1, + 12, + 4, + 14, + 6, + 16, + 10, + 22, + 64 + ], + "line-color": "#cbcccd" + } + }, + { + "id": "primary_tunnel", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 12, + 4, + 14, + 6, + 16, + 10, + 22, + 64 + ], + "line-color": "hsl(0, 0%, 89%)" + } + }, + { + "id": "aeroway", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "transit.station.airport", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "aeroway", + "layout": {}, + "paint": { + "line-color": "hsla(0, 0%, 0%, 0.1)" + } + }, + { + "id": "service_road", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "service" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "hsla(0, 0%, 0%, 0.1)" + } + }, + { + "id": "pedestrian_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "pedestrian" + ], + true, + false + ], + [ + "has", + "name" + ] + ], + "layout": {}, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 1, + 16, + 4, + 22, + 32 + ], + "line-color": "#e3e3e3", + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12.5, + 0, + 13.5, + 1 + ] + } + }, + { + "id": "street_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "street" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12, + 1, + 16, + 6, + 22, + 40 + ], + "line-color": "#e3e3e3" + } + }, + { + "id": "secondary_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "secondary", + "secondary_link", + "tertiary_link", + "tertiary", + "trunk_link", + "trunk" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 1, + 17, + 10, + 22, + 48 + ], + "line-color": "#e3e3e3", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 16, + 1, + 20, + 2 + ] + } + }, + { + "id": "primary_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + false, + true + ] + ], + "layout": { + "line-cap": "round" + }, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 1, + 16, + 8, + 22, + 64 + ], + "line-color": "#ecd283" + } + }, + { + "id": "motorway_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "motorway" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 15.5, + 8, + 22, + 78 + ], + "line-color": "#ecd283", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 15, + 2 + ] + } + }, + { + "id": "railway", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "major_rail", + "minor_rail", + "service_rail" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + false, + true + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(220, 4%, 85%)" + } + }, + { + "id": "pedestrian", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "pedestrian" + ], + true, + false + ], + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "platform" + ], + false, + true + ] + ], + "layout": {}, + "paint": { + "line-color": "#ffffff", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 1, + 16, + 4, + 22, + 32 + ], + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12.5, + 0, + 13.5, + 1 + ] + } + }, + { + "id": "street", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "street" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "#ffffff", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12, + 1, + 16, + 6, + 22, + 40 + ] + } + }, + { + "id": "secondary", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "secondary", + "secondary_link", + "trunk_link", + "tertiary", + "tertiary_link", + "trunk" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "#ffffff", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 1, + 17, + 10, + 22, + 48 + ] + } + }, + { + "id": "primary", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + false, + true + ] + ], + "layout": { + "line-cap": "round" + }, + "paint": { + "line-color": [ + "step", + [ + "zoom" + ], + "hsl(50, 100%, 75%)", + 7, + "hsl(50, 100%, 85%)" + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 1, + 16, + 8, + 22, + 64 + ] + } + }, + { + "id": "motorway", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "motorway" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "#ffeba3", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 15.5, + 8, + 22, + 78 + ] + } + }, + { + "id": "primary_bridge_border", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "bridge" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-gap-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 1, + 16, + 8, + 22, + 64 + ], + "line-color": "hsl(45, 73%, 72%)" + } + }, + { + "id": "primary_bridge", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "bridge" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": [ + "step", + [ + "zoom" + ], + "hsl(50, 100%, 75%)", + 7, + "hsl(50, 100%, 85%)" + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 1, + 16, + 8, + 22, + 64 + ] + } + }, + { + "id": "building", + "type": "fill", + "metadata": { + "mapbox:group": "29bb589e8d1b9b402583363648b70302", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "building", + "filter": [ + "match", + [ + "get", + "type" + ], + [ + "roof" + ], + false, + true + ], + "layout": {}, + "paint": { + "fill-color": [ + "match", + [ + "get", + "type" + ], + [ + "store", + "retail", + "church", + "kiosk", + "civic", + "hotel", + "supermarket", + "pub", + "dormitory" + ], + "hsl(33, 100%, 96%)", + "#ededed" + ], + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0, + 17, + 1 + ] + } + }, + { + "id": "building_border", + "type": "line", + "metadata": { + "mapbox:group": "29bb589e8d1b9b402583363648b70302", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "building", + "filter": [ + "match", + [ + "get", + "type" + ], + [ + "roof" + ], + false, + true + ], + "layout": {}, + "paint": { + "line-color": [ + "match", + [ + "get", + "type" + ], + [ + "store", + "retail", + "church", + "kiosk", + "civic", + "commercial", + "hotel", + "supermarket", + "pub" + ], + "#f8e1c7", + "#dcdcdc" + ], + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0, + 17, + 1 + ] + } + }, + { + "id": "building_3d", + "type": "fill-extrusion", + "metadata": { + "mapbox:group": "29bb589e8d1b9b402583363648b70302", + "microg:gms-type-feature": "landscape.man_made", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "building", + "filter": [ + "match", + [ + "get", + "extrude" + ], + [ + "true" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-extrusion-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + 0, + 16, + [ + "get", + "height" + ] + ], + "fill-extrusion-opacity": 0.3, + "fill-extrusion-color": "hsl(0, 0%, 93%)" + } + }, + { + "id": "admin_0", + "type": "line", + "metadata": { + "mapbox:group": "3c26e9cbc75335c6f0ba8de5439cf1fa", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "match", + [ + "get", + "maritime" + ], + [ + "false" + ], + true, + false + ], + [ + "match", + [ + "get", + "admin_level" + ], + [ + 0 + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": [ + "case", + [ + "==", + [ + "get", + "disputed" + ], + true + ], + "hsl(0, 24%, 48%)", + "#787a7b" + ] + } + }, + { + "id": "admin_1", + "type": "line", + "metadata": { + "mapbox:group": "3c26e9cbc75335c6f0ba8de5439cf1fa", + "microg:gms-type-feature": "administrative.province", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "match", + [ + "get", + "maritime" + ], + [ + "false" + ], + true, + false + ], + [ + "match", + [ + "get", + "admin_level" + ], + [ + 1 + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": [ + "case", + [ + "==", + [ + "get", + "disputed" + ], + true + ], + "hsl(0, 24%, 48%)", + "#787a7b" + ], + "line-dasharray": [ + 1, + 1 + ] + } + }, + { + "id": "river_name", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "natural_label", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "river" + ], + true, + false + ], + "layout": { + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ], + "symbol-placement": "line", + "symbol-spacing": 500, + "text-font": [ + "Roboto Regular" + ] + }, + "paint": { + "text-color": "#5083c1", + "text-halo-color": "#5083c1", + "text-halo-blur": 1 + } + }, + { + "id": "city_label_right", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 8, + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-optional": true, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular" + ] + ] + ], + "text-justify": "left", + "text-offset": [ + 0.5, + 0.1 + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": "left", + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ], + 5 + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "get", + "symbolrank" + ], + 25 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "icon-opacity": 0.8 + } + }, + { + "id": "city_label_left", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 8, + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular" + ] + ] + ], + "text-justify": "right", + "text-offset": [ + -0.5, + 0.1 + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": "right", + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ], + 5 + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "get", + "symbolrank" + ], + 25 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "icon-opacity": 0.8 + } + }, + { + "id": "city_label_below", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 8, + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular" + ] + ] + ], + "text-offset": [ + 0, + 0.4 + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": "top", + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ], + 5 + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "get", + "symbolrank" + ], + 25 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "icon-opacity": 0.8 + } + }, + { + "id": "city_name", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "step", + [ + "zoom" + ], + [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + 8, + "" + ], + "text-transform": [ + "step", + [ + "get", + "symbolrank" + ], + "none", + 15, + "uppercase" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular" + ] + ] + ], + "text-offset": [ + "step", + [ + "zoom" + ], + [ + "literal", + [ + 0, + -0.2 + ] + ], + 8, + [ + "literal", + [ + 0, + 0 + ] + ] + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": [ + "step", + [ + "zoom" + ], + "bottom", + 8, + "center" + ], + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ], + "text-letter-spacing": [ + "interpolate", + [ + "linear" + ], + [ + "get", + "symbolrank" + ], + 0, + 0, + 8, + 0, + 12, + 0.1, + 16, + 0.2 + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ], + 5 + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "get", + "symbolrank" + ], + 25 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "icon-opacity": 0.8 + } + }, + { + "id": "park_name", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "poi.park", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ], + "layout": { + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ], + "text-font": [ + "Roboto Regular" + ], + "text-size": 14 + }, + "paint": { + "text-color": "#297925", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "road-number-shield", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road", + "microg:gms-type-element": "labels.icon" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "ref" + ], + [ + "<=", + [ + "get", + "reflen" + ], + 6 + ] + ], + "layout": { + "text-size": 9, + "icon-image": [ + "case", + [ + "match", + [ + "get", + "shield" + ], + [ + "de-motorway", + "rectangle-green", + "rectangle-yellow", + "rectangle-white", + "rectangle-blue", + "rectangle-red", + "us-interstate" + ], + true, + false + ], + [ + "concat", + "shield_", + [ + "get", + "shield" + ], + "_", + [ + "get", + "reflen" + ] + ], + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "white" + ], + true, + false + ], + [ + "concat", + "shield_rectangle-blue_", + [ + "get", + "reflen" + ] + ], + [ + "concat", + "shield_rectangle-white_", + [ + "get", + "reflen" + ] + ] + ], + "icon-rotation-alignment": "viewport", + "text-font": [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "white" + ], + [ + "literal", + [ + "Roboto Bold" + ] + ], + [ + "black" + ], + [ + "literal", + [ + "Roboto Medium" + ] + ], + [ + "literal", + [ + "Roboto Bold" + ] + ] + ], + "symbol-placement": [ + "step", + [ + "zoom" + ], + "point", + 11, + "line" + ], + "text-offset": [ + 0, + 0.1 + ], + "text-rotation-alignment": "viewport", + "icon-size": 0.75, + "text-field": [ + "get", + "ref" + ], + "text-letter-spacing": 0.05 + }, + "paint": { + "text-color": [ + "case", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "white" + ], + true, + false + ], + "#ffffff", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "black" + ], + true, + false + ], + "hsl(0, 0%, 7%)", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "yellow" + ], + true, + false + ], + "hsl(50, 100%, 70%)", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "orange" + ], + true, + false + ], + "hsl(25, 100%, 75%)", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "blue" + ], + true, + false + ], + "hsl(230, 48%, 34%)", + "#ffffff" + ] + } + }, + { + "id": "country_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "country" + ], + true, + false + ], + "layout": { + "text-letter-spacing": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 1, + 0, + 3, + 0.15 + ], + "text-font": [ + "Roboto Medium" + ], + "text-size": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 1, + 12, + 7, + [ + "/", + 100, + [ + "get", + "symbolrank" + ] + ] + ], + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": "hsl(0, 0%, 10%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 1, + "text-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 6, + 1, + 7, + 0 + ] + } + }, + { + "id": "pedestrian_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "pedestrian" + ], + true, + false + ], + [ + "match", + [ + "get", + "type" + ], + [ + "platform" + ], + false, + true + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 17, + 10, + 22, + 14 + ], + "text-padding": 5 + }, + "paint": { + "text-color": "#575757", + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "street_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "street" + ], + true, + false + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 6, + 16, + 10 + ], + "text-padding": 5 + }, + "paint": { + "text-color": "#575757", + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "secondary_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "secondary", + "secondary_link", + "tertiary_link", + "tertiary", + "trunk_link", + "trunk" + ], + true, + false + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 8, + 16, + 13 + ], + "symbol-spacing": 300, + "text-padding": 25 + }, + "paint": { + "text-color": "hsl(196, 0%, 34%)", + "text-halo-width": 1, + "text-halo-color": "#ffffff", + "text-halo-blur": 1 + } + }, + { + "id": "primary_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "primary", + "primary_link" + ], + true, + false + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 10, + 18, + 14 + ], + "symbol-spacing": 800, + "text-padding": 50 + }, + "paint": { + "text-color": "#6e481d", + "text-halo-width": 1, + "text-halo-color": "#ffffff", + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_below", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-element": "labels.text", + "microg:gms-type-feature": "poi" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3.5 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-optional": true, + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular" + ], + "text-offset": [ + 0, + 0.5 + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "top", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 44%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 31%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "#c77d57", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 48%)", + [ + "bank", + "parking", + "parking-garage" + ], + "#737b9b", + [ + "hospital", + "doctor" + ], + "#a47172", + "#67747b" + ], + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_above", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-element": "labels.text", + "microg:gms-type-feature": "poi" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3.5 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-optional": true, + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular" + ], + "text-offset": [ + 0, + -2 + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "bottom", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 44%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 31%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "#c77d57", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 48%)", + [ + "bank", + "parking", + "parking-garage" + ], + "#737b9b", + [ + "hospital", + "doctor" + ], + "#a47172", + "#67747b" + ], + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_left", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-element": "labels.text", + "microg:gms-type-feature": "poi" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3.5 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular" + ], + "text-justify": "right", + "text-offset": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + [ + "literal", + [ + -1.1, + -0.7 + ] + ], + 15, + [ + "literal", + [ + -1.1, + -0.9 + ] + ] + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "right", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 44%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 31%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "#c77d57", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 48%)", + [ + "bank", + "parking", + "parking-garage" + ], + "#737b9b", + [ + "hospital", + "doctor" + ], + "#a47172", + "#67747b" + ], + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_right", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-element": "labels.text", + "microg:gms-type-feature": "poi" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 3.5 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular" + ], + "text-justify": "left", + "text-offset": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + [ + "literal", + [ + 1.1, + -0.7 + ] + ], + 15, + [ + "literal", + [ + 1.1, + -0.9 + ] + ] + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "left", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 44%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 31%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "#c77d57", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 48%)", + [ + "bank", + "parking", + "parking-garage" + ], + "#737b9b", + [ + "hospital", + "doctor" + ], + "#a47172", + "#67747b" + ], + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + } + ], + "created": "2019-04-15T08:41:40.148Z", + "modified": "2020-09-05T19:42:03.856Z", + "id": "cjui4020201oo1fmca7yuwbor", + "owner": "microg", + "visibility": "public", + "protected": false, + "draft": false +} diff --git a/play-services-maps-core-mapbox/src/main/assets/style-microg-satellite.json b/play-services-maps-core-mapbox/src/main/assets/style-microg-satellite.json new file mode 100644 index 0000000000000000000000000000000000000000..accb62735bd840c4645086b366022f9d9fb11086 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/assets/style-microg-satellite.json @@ -0,0 +1,3489 @@ +{ + "version": 8, + "name": "Mountain View Satellite", + "metadata": { + "mapbox:origin": "basic-template", + "mapbox:autocomposite": true, + "mapbox:type": "template", + "mapbox:sdk-support": { + "js": "0.50.0", + "android": "6.7.0", + "ios": "4.6.0" + }, + "mapbox:trackposition": false, + "mapbox:groups": { + "f51b507d2a17e572c70a5db74b0fec7e": { + "name": "Base", + "collapsed": true + }, + "3f48b8dc54ff2e6544b9ef9cedbf2990": { + "name": "Streets", + "collapsed": false + }, + "29bb589e8d1b9b402583363648b70302": { + "name": "Buildings", + "collapsed": true + }, + "3c26e9cbc75335c6f0ba8de5439cf1fa": { + "name": "Country borders", + "collapsed": true + }, + "7b44201d7f1682d99f7140188aff23ce": { + "name": "Labels", + "collapsed": true + }, + "24306bdccbff03e2ee08d5d1a4ca7312": { + "name": "Street name", + "collapsed": false + }, + "124a9d7a8e5226775d947c592110dfad": { + "name": "POI", + "collapsed": true + } + }, + "mapbox:uiParadigm": "layers" + }, + "center": [ + 12.819420849458652, + 50.03325860617235 + ], + "zoom": 3.315829104862067, + "bearing": 0, + "pitch": 1.5, + "light": { + "intensity": 0.5, + "color": "hsl(0, 0%, 0%)" + }, + "sources": { + "mapbox://mapbox.satellite": { + "url": "mapbox://mapbox.satellite", + "type": "raster", + "tileSize": 256 + }, + "composite": { + "url": "mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/microg/cjxgloted25ap1ct4uex7m6hi/8fkcj5fgn4mftlzuak3guz1f9", + "glyphs": "mapbox://fonts/microg/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "raster", + "source": "mapbox://mapbox.satellite", + "layout": {}, + "paint": {}, + "metadata": { + "microg:gms-type-feature": "landscape.natural.landcover", + "microg:gms-type-element": "geometry.fill" + } + }, + { + "id": "path", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "path" + ], + true, + false + ], + [ + "match", + [ + "get", + "type" + ], + [ + "platform", + "steps" + ], + false, + true + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(118, 34%, 66%)", + "line-dasharray": [ + 4, + 2 + ], + "line-opacity": 0.3 + } + }, + { + "id": "steps", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "path" + ], + true, + false + ], + [ + "match", + [ + "get", + "type" + ], + [ + "steps" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(118, 5%, 66%)", + "line-dasharray": [ + 1, + 1 + ], + "line-gap-width": 1, + "line-opacity": 0.3 + } + }, + { + "id": "platform", + "type": "fill", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "transit.station.rail", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "type" + ], + [ + "platform" + ], + true, + false + ], + "layout": {}, + "paint": { + "fill-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + "hsl(2, 20%, 92%)", + 16, + "hsl(2, 95%, 92%)" + ], + "fill-outline-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 15, + "hsl(1, 10%, 76%)", + 16, + "hsl(1, 74%, 76%)" + ], + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0, + 16, + 0.3 + ] + } + }, + { + "id": "primary_tunnel", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 12, + 4, + 14, + 6, + 16, + 10, + 22, + 64 + ], + "line-color": "hsl(0, 0%, 89%)", + "line-opacity": 0.3 + } + }, + { + "id": "aeroway", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "transit.station.airport", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "aeroway", + "layout": {}, + "paint": { + "line-color": "hsla(0, 0%, 0%, 0.1)", + "line-opacity": 0.3 + } + }, + { + "id": "service_road", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "service" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "hsla(0, 0%, 0%, 0.1)", + "line-opacity": 0.3 + } + }, + { + "id": "railway", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "transit.line", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "major_rail", + "minor_rail", + "service_rail" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "hsl(220, 4%, 85%)", + "line-opacity": 0.3 + } + }, + { + "id": "pedestrian", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "pedestrian" + ], + true, + false + ], + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "type" + ], + [ + "platform" + ], + false, + true + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 1, + 16, + 4, + 22, + 32 + ], + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12.5, + 0, + 13.5, + 0.3 + ] + } + }, + { + "id": "street", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "street" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12, + 1, + 16, + 6, + 22, + 40 + ], + "line-opacity": 0.3 + } + }, + { + "id": "secondary", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "secondary", + "secondary_link", + "trunk_link", + "tertiary", + "tertiary_link", + "trunk" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 1, + 17, + 10, + 22, + 48 + ], + "line-opacity": 0.3 + } + }, + { + "id": "primary", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "primary_link", + "primary", + "motorway_link" + ], + true, + false + ], + [ + "match", + [ + "get", + "structure" + ], + [ + "tunnel" + ], + false, + true + ] + ], + "layout": { + "line-cap": "round" + }, + "paint": { + "line-color": [ + "step", + [ + "zoom" + ], + "hsl(50, 100%, 75%)", + 7, + "hsl(50, 100%, 85%)" + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 1, + 16, + 8, + 22, + 64 + ], + "line-opacity": 0.3 + } + }, + { + "id": "motorway", + "type": "line", + "metadata": { + "mapbox:group": "3f48b8dc54ff2e6544b9ef9cedbf2990", + "microg:gms-type-feature": "road.arterial", + "microg:gms-type-element": "geometry.fill" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "motorway" + ], + true, + false + ], + "layout": {}, + "paint": { + "line-color": "hsl(47, 100%, 82%)", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 15.5, + 8, + 22, + 78 + ], + "line-opacity": 0.3 + } + }, + { + "id": "admin_0", + "type": "line", + "metadata": { + "mapbox:group": "3c26e9cbc75335c6f0ba8de5439cf1fa", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "match", + [ + "get", + "maritime" + ], + [ + "false" + ], + true, + false + ], + [ + "match", + [ + "get", + "admin_level" + ], + [ + 0 + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": [ + "case", + [ + "==", + [ + "get", + "disputed" + ], + true + ], + "hsl(0, 24%, 85%)", + "hsl(200, 1%, 85%)" + ] + } + }, + { + "id": "admin_1", + "type": "line", + "metadata": { + "mapbox:group": "3c26e9cbc75335c6f0ba8de5439cf1fa", + "microg:gms-type-feature": "administrative.province", + "microg:gms-type-element": "geometry.stroke" + }, + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "match", + [ + "get", + "maritime" + ], + [ + "false" + ], + true, + false + ], + [ + "match", + [ + "get", + "admin_level" + ], + [ + 1 + ], + true, + false + ] + ], + "layout": {}, + "paint": { + "line-color": [ + "case", + [ + "==", + [ + "get", + "disputed" + ], + true + ], + "hsl(0, 24%, 85%)", + "hsl(200, 1%, 85%)" + ], + "line-dasharray": [ + 1, + 1 + ] + } + }, + { + "id": "river_name", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "water", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "natural_label", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "river" + ], + true, + false + ], + "layout": { + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ], + "symbol-placement": "line", + "symbol-spacing": 500, + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ] + }, + "paint": { + "text-color": "#5083c1", + "text-halo-color": "#5083c1", + "text-halo-blur": 1 + } + }, + { + "id": "city_label_right", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 8, + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-optional": true, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium", + "Arial Unicode MS Regular" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular", + "Arial Unicode MS Regular" + ] + ] + ], + "text-justify": "left", + "text-offset": [ + 0.5, + 0.1 + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": "left", + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "-", + 100, + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ] + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "-", + 100, + [ + "get", + "symbolrank" + ] + ], + 5 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "icon-opacity": 0.8, + "text-halo-color": "hsl(0, 1%, 0%)" + } + }, + { + "id": "city_label_left", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 8, + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium", + "Arial Unicode MS Regular" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular", + "Arial Unicode MS Regular" + ] + ] + ], + "text-justify": "right", + "text-offset": [ + -0.5, + 0.1 + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": "right", + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "-", + 100, + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ] + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "-", + 100, + [ + "get", + "symbolrank" + ] + ], + 5 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "icon-opacity": 0.8, + "text-halo-color": "hsl(0, 1%, 0%)" + } + }, + { + "id": "city_label_below", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 8, + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium", + "Arial Unicode MS Regular" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular", + "Arial Unicode MS Regular" + ] + ] + ], + "text-offset": [ + 0, + 0.4 + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": "top", + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "-", + 100, + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ] + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "-", + 100, + [ + "get", + "symbolrank" + ] + ], + 5 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "icon-opacity": 0.8, + "text-halo-color": "hsl(0, 1%, 0%)" + } + }, + { + "id": "city_name", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "administrative.locality", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "match", + [ + "get", + "class" + ], + [ + "settlement", + "settlement_subdivision" + ], + true, + false + ] + ], + "layout": { + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "-", + 14, + [ + "max", + 0, + [ + "-", + [ + "get", + "symbolrank" + ], + 8 + ] + ] + ], + 22, + [ + "-", + 20, + [ + "/", + [ + "get", + "symbolrank" + ], + 4 + ] + ] + ], + "icon-image": [ + "step", + [ + "zoom" + ], + [ + "match", + [ + "get", + "capital" + ], + [ + 0, + 2 + ], + "capital", + "city" + ], + 8, + "" + ], + "text-transform": [ + "step", + [ + "get", + "symbolrank" + ], + "none", + 15, + "uppercase" + ], + "text-font": [ + "step", + [ + "get", + "symbolrank" + ], + [ + "literal", + [ + "Roboto Medium", + "Arial Unicode MS Regular" + ] + ], + 10, + [ + "literal", + [ + "Roboto Regular", + "Arial Unicode MS Regular" + ] + ] + ], + "text-offset": [ + "step", + [ + "zoom" + ], + [ + "literal", + [ + 0, + -0.2 + ] + ], + 8, + [ + "literal", + [ + 0, + 0 + ] + ] + ], + "icon-size": [ + "/", + 5, + [ + "get", + "symbolrank" + ] + ], + "text-anchor": [ + "step", + [ + "zoom" + ], + "bottom", + 8, + "center" + ], + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ], + "text-letter-spacing": [ + "interpolate", + [ + "linear" + ], + [ + "get", + "symbolrank" + ], + 0, + 0, + 8, + 0, + 12, + 0.1, + 16, + 0.2 + ] + }, + "paint": { + "text-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + [ + "concat", + "hsl(213, 11%, ", + [ + "-", + 100, + [ + "*", + [ + "get", + "symbolrank" + ], + 2 + ] + ], + "%)" + ], + 22, + [ + "concat", + "hsl(213, 11%, ", + [ + "+", + [ + "-", + 100, + [ + "get", + "symbolrank" + ] + ], + 5 + ], + "%)" + ] + ], + "text-halo-width": 1, + "text-halo-blur": 1, + "icon-opacity": 0.8, + "text-halo-color": "hsl(0, 1%, 0%)" + } + }, + { + "id": "park_name", + "type": "symbol", + "metadata": { + "mapbox:group": "7b44201d7f1682d99f7140188aff23ce", + "microg:gms-type-feature": "poi.park", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ], + "layout": { + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ], + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-size": 14 + }, + "paint": { + "text-color": "#297925", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "road-number-shield", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "labels.icon" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "ref" + ], + [ + "<=", + [ + "get", + "reflen" + ], + 6 + ] + ], + "layout": { + "text-size": 9, + "icon-image": [ + "case", + [ + "match", + [ + "get", + "shield" + ], + [ + "de-motorway", + "rectangle-green", + "rectangle-yellow", + "rectangle-white", + "rectangle-blue", + "rectangle-red", + "us-interstate" + ], + true, + false + ], + [ + "concat", + "shield_", + [ + "get", + "shield" + ], + "_", + [ + "get", + "reflen" + ] + ], + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "white" + ], + true, + false + ], + [ + "concat", + "shield_rectangle-blue_", + [ + "get", + "reflen" + ] + ], + [ + "concat", + "shield_rectangle-white_", + [ + "get", + "reflen" + ] + ] + ], + "icon-rotation-alignment": "viewport", + "text-font": [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "white" + ], + [ + "literal", + [ + "DIN Offc Pro Bold", + "Arial Unicode MS Regular" + ] + ], + [ + "black" + ], + [ + "literal", + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ], + [ + "literal", + [ + "DIN Offc Pro Bold", + "Arial Unicode MS Regular" + ] + ] + ], + "symbol-placement": [ + "step", + [ + "zoom" + ], + "point", + 11, + "line" + ], + "text-rotation-alignment": "viewport", + "icon-size": 0.75, + "text-field": [ + "get", + "ref" + ], + "text-letter-spacing": 0.05 + }, + "paint": { + "text-color": [ + "case", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "white" + ], + true, + false + ], + "#ffffff", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "black" + ], + true, + false + ], + "hsl(0, 0%, 7%)", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "yellow" + ], + true, + false + ], + "hsl(50, 100%, 70%)", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "orange" + ], + true, + false + ], + "hsl(25, 100%, 75%)", + [ + "match", + [ + "get", + "shield_text_color" + ], + [ + "blue" + ], + true, + false + ], + "hsl(230, 48%, 34%)", + "#ffffff" + ] + } + }, + { + "id": "country_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "administrative.country", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "place_label", + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "country" + ], + true, + false + ], + "layout": { + "text-letter-spacing": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 1, + 0, + 3, + 0.15 + ], + "text-font": [ + "Roboto Medium", + "Arial Unicode MS Regular" + ], + "text-size": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 1, + 12, + 7, + [ + "/", + 100, + [ + "get", + "symbolrank" + ] + ] + ], + "text-field": [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 6, + 1, + 7, + 0 + ], + "text-color": "hsl(0, 0%, 90%)", + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "hsl(0, 1%, 0%)" + } + }, + { + "id": "pedestrian_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "pedestrian" + ], + true, + false + ], + [ + "match", + [ + "get", + "type" + ], + [ + "platform" + ], + false, + true + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 17, + 10, + 22, + 14 + ], + "text-padding": 5 + }, + "paint": { + "text-color": "hsl(0, 0%, 86%)", + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "street_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "street" + ], + true, + false + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 6, + 16, + 10 + ], + "text-padding": 5 + }, + "paint": { + "text-color": "hsl(0, 0%, 86%)", + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "secondary_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.local", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "secondary", + "secondary_link", + "tertiary_link", + "tertiary", + "trunk_link", + "trunk" + ], + true, + false + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 8, + 16, + 13 + ], + "symbol-spacing": 300, + "text-padding": 25 + }, + "paint": { + "text-color": "hsl(196, 0%, 86%)", + "text-halo-width": 1, + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-blur": 1 + } + }, + { + "id": "primary_name", + "type": "symbol", + "metadata": { + "mapbox:group": "24306bdccbff03e2ee08d5d1a4ca7312", + "microg:gms-type-feature": "road.highway", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "match", + [ + "get", + "class" + ], + [ + "primary", + "primary_link" + ], + true, + false + ] + ], + "layout": { + "text-field": [ + "get", + "name" + ], + "symbol-placement": "line", + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 10, + 18, + 14 + ], + "symbol-spacing": 800, + "text-padding": 50 + }, + "paint": { + "text-color": "hsl(32, 58%, 93%)", + "text-halo-width": 1, + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_below", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-feature": "poi", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-optional": true, + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-offset": [ + 0, + 0.5 + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "top", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 65%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 65%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "hsl(20, 50%, 65%)", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 65%)", + [ + "bank", + "parking", + "parking-garage" + ], + "hsl(228, 17%, 65%)", + [ + "hospital", + "doctor" + ], + "hsl(359, 22%, 65%)", + "hsl(201, 9%, 80%)" + ], + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_above", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-feature": "poi", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-optional": true, + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-offset": [ + 0, + -2 + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "bottom", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 65%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 65%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "hsl(20, 50%, 65%)", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 65%)", + [ + "bank", + "parking", + "parking-garage" + ], + "hsl(228, 17%, 65%)", + [ + "hospital", + "doctor" + ], + "hsl(359, 22%, 65%)", + "hsl(201, 9%, 80%)" + ], + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_left", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-feature": "poi", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-justify": "right", + "text-offset": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + [ + "literal", + [ + -1.1, + -0.7 + ] + ], + 15, + [ + "literal", + [ + -1.1, + -0.9 + ] + ] + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "right", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 65%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 65%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "hsl(20, 50%, 65%)", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 65%)", + [ + "bank", + "parking", + "parking-garage" + ], + "hsl(228, 17%, 65%)", + [ + "hospital", + "doctor" + ], + "hsl(359, 22%, 65%)", + "hsl(201, 9%, 80%)" + ], + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + }, + { + "id": "poi_label_right", + "type": "symbol", + "metadata": { + "mapbox:group": "124a9d7a8e5226775d947c592110dfad", + "microg:gms-type-feature": "poi", + "microg:gms-type-element": "labels.text" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "<=", + [ + "get", + "filterrank" + ], + [ + "/", + [ + "zoom" + ], + 4 + ] + ], + [ + "!", + [ + "all", + [ + "match", + [ + "get", + "maki" + ], + [ + "park", + "cemetery" + ], + true, + false + ], + [ + "<=", + [ + "get", + "sizerank" + ], + 10 + ] + ] + ] + ], + "layout": { + "text-line-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 15, + 1.2 + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 13, + 15, + 14 + ], + "icon-offset": [ + 0, + -36 + ], + "icon-image": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "lodging", + "theatre", + "grocery", + "restaurant" + ], + [ + "concat", + "poi_", + [ + "get", + "maki" + ] + ], + [ + "fitness-centre", + "golf", + "campsite", + "bowling-alley", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "stadium", + "dog-park", + "pitch", + "cemetery" + ], + "poi_generic_green", + [ + "bank", + "parking", + "parking-garage" + ], + "poi_generic_purple", + [ + "bar", + "cafe", + "bakery" + ], + "poi_generic_orange", + [ + "alcohol-shop", + "shop", + "shoe", + "convenience", + "clothing-store", + "jewelry-store" + ], + "poi_generic_blue", + [ + "casino", + "castle", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "poi_generic_teal", + [ + "hospital", + "doctor" + ], + "poi_generic_red", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant-noodle", + "fast-food", + "ice-cream" + ], + "poi_restaurant", + "poi_generic" + ], + "text-font": [ + "Roboto Regular", + "Arial Unicode MS Regular" + ], + "text-justify": "left", + "text-offset": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + [ + "literal", + [ + 1.1, + -0.7 + ] + ], + 15, + [ + "literal", + [ + 1.1, + -0.9 + ] + ] + ], + "icon-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.25, + 15, + 0.32 + ], + "text-anchor": "left", + "text-field": [ + "to-string", + [ + "get", + "name" + ] + ] + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "maki" + ], + [ + "museum", + "casino", + "castle", + "theatre", + "art-gallery", + "attraction", + "cinema", + "music", + "monument" + ], + "hsl(186, 78%, 65%)", + [ + "lodging" + ], + "#df7db1", + [ + "fitness-centre", + "golf", + "campsite", + "park", + "garden", + "farm", + "picnic-site", + "zoo", + "dog-park", + "stadium", + "bowling-alley", + "pitch", + "cemetery" + ], + "hsl(117, 53%, 65%)", + [ + "restaurant-pizza", + "restaurant-seafood", + "restaurant", + "restaurant-noodle", + "bar", + "cafe", + "fast-food", + "bakery", + "ice-cream" + ], + "hsl(20, 50%, 65%)", + [ + "shop", + "shoe", + "alcohol-shop", + "convenience", + "grocery", + "clothing-store", + "jewelry-store" + ], + "hsl(213, 40%, 65%)", + [ + "bank", + "parking", + "parking-garage" + ], + "hsl(228, 17%, 65%)", + [ + "hospital", + "doctor" + ], + "hsl(359, 22%, 65%)", + "hsl(201, 9%, 80%)" + ], + "text-halo-color": "hsl(0, 1%, 0%)", + "text-halo-width": 1, + "icon-translate": [ + 0, + 0 + ], + "text-translate": [ + 0, + 0 + ], + "text-halo-blur": 1 + } + } + ], + "created": "2019-06-28T21:20:23.628Z", + "modified": "2020-09-05T20:08:11.990Z", + "id": "cjxgloted25ap1ct4uex7m6hi", + "owner": "microg", + "visibility": "public", + "protected": false, + "draft": false +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/AbstractGoogleMap.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/AbstractGoogleMap.kt new file mode 100644 index 0000000000000000000000000000000000000000..12ae2a0c0dc916dba0ab26c873b383d9c2d78d77 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/AbstractGoogleMap.kt @@ -0,0 +1,136 @@ +package org.microg.gms.maps.mapbox + +import android.content.Context +import android.location.Location +import android.os.Bundle +import android.util.DisplayMetrics +import android.util.Log +import com.google.android.gms.dynamic.IObjectWrapper +import com.google.android.gms.dynamic.ObjectWrapper +import com.google.android.gms.maps.internal.* +import org.microg.gms.maps.MapsConstants +import org.microg.gms.maps.mapbox.model.AbstractMarker +import org.microg.gms.maps.mapbox.model.DefaultInfoWindowAdapter +import org.microg.gms.maps.mapbox.model.InfoWindow +import org.microg.gms.maps.mapbox.utils.MapContext + +abstract class AbstractGoogleMap(context: Context) : IGoogleMapDelegate.Stub() { + + internal val mapContext = MapContext(context) + + val dpiFactor: Float + get() = mapContext.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT + + internal var currentInfoWindow: InfoWindow? = null + internal var infoWindowAdapter: IInfoWindowAdapter = DefaultInfoWindowAdapter(mapContext) + internal var onInfoWindowClickListener: IOnInfoWindowClickListener? = null + internal var onInfoWindowLongClickListener: IOnInfoWindowLongClickListener? = null + internal var onInfoWindowCloseListener: IOnInfoWindowCloseListener? = null + + internal var mapClickListener: IOnMapClickListener? = null + internal var mapLongClickListener: IOnMapLongClickListener? = null + internal var markerClickListener: IOnMarkerClickListener? = null + internal var circleClickListener: IOnCircleClickListener? = null + + + internal abstract fun showInfoWindow(marker: AbstractMarker): Boolean + + override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) { + onInfoWindowClickListener = listener + } + + override fun setInfoWindowLongClickListener(listener: IOnInfoWindowLongClickListener) { + onInfoWindowLongClickListener = listener + } + + override fun setInfoWindowCloseListener(listener: IOnInfoWindowCloseListener) { + onInfoWindowCloseListener = listener + } + + override fun setInfoWindowAdapter(adapter: IInfoWindowAdapter?) { + infoWindowAdapter = adapter ?: DefaultInfoWindowAdapter(mapContext) + } + + override fun setOnMapClickListener(listener: IOnMapClickListener?) { + mapClickListener = listener + } + + override fun setOnMapLongClickListener(listener: IOnMapLongClickListener?) { + mapLongClickListener = listener + } + + override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) { + markerClickListener = listener + } + + override fun setCircleClickListener(listener: IOnCircleClickListener?) { + circleClickListener = listener + } + + override fun getMyLocation(): Location? { + Log.d(TAG, "unimplemented Method: getMyLocation") + return null + } + + override fun setLocationSource(locationSource: ILocationSourceDelegate?) { + Log.d(TAG, "unimplemented Method: setLocationSource") + } + + override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) { + Log.d(TAG, "unimplemented Method: setOnMyLocationChangeListener") + } + + override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) { + Log.d(TAG, "unimplemented Method: setOnMyLocationButtonClickListener") + } + + override fun getTestingHelper(): IObjectWrapper { + Log.d(TAG, "unimplemented Method: getTestingHelper") + return ObjectWrapper.wrap(null) + } + + override fun isBuildingsEnabled(): Boolean { + Log.d(TAG, "unimplemented Method: isBuildingsEnabled") + return false + } + + override fun setBuildingsEnabled(buildings: Boolean) { + Log.d(TAG, "unimplemented Method: setBuildingsEnabled") + } + + override fun useViewLifecycleWhenInFragment(): Boolean { + Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment") + return false + } + + override fun onEnterAmbient(bundle: Bundle?) { + Log.d(TAG, "unimplemented Method: onEnterAmbient") + } + + override fun onExitAmbient() { + Log.d(TAG, "unimplemented Method: onExitAmbient") + } + + override fun isTrafficEnabled(): Boolean { + Log.d(TAG, "unimplemented Method: isTrafficEnabled") + return false + } + + override fun setTrafficEnabled(traffic: Boolean) { + Log.d(TAG, "unimplemented Method: setTrafficEnabled") + + } + + override fun isIndoorEnabled(): Boolean { + Log.d(TAG, "unimplemented Method: isIndoorEnabled") + return false + } + + override fun setIndoorEnabled(indoor: Boolean) { + Log.d(TAG, "unimplemented Method: setIndoorEnabled") + } + + companion object { + val TAG = "GmsMapAbstract" + } +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt index eea4304f56161ce47b83bff5400d2bea29595ab7..6d97b262f9b12f6ac84937e4ce437c7c66a34a52 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt @@ -17,26 +17,48 @@ package org.microg.gms.maps.mapbox import android.util.Log +import com.google.android.gms.maps.internal.IGoogleMapDelegate import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.camera.CameraUpdate import com.mapbox.mapboxsdk.geometry.LatLngBounds import com.mapbox.mapboxsdk.maps.MapboxMap import java.util.* -internal class CameraBoundsWithSizeUpdate(val bounds: LatLngBounds, val width: Int, val height: Int, val padding: IntArray) : CameraUpdate { +internal class CameraBoundsWithSizeUpdate(val bounds: LatLngBounds, val width: Int, val height: Int, val padding: IntArray) : LiteModeCameraUpdate, CameraUpdate { constructor(bounds: LatLngBounds, width: Int, height: Int, paddingLeft: Int, paddingTop: Int = paddingLeft, paddingRight: Int = paddingLeft, paddingBottom: Int = paddingTop) : this(bounds, width, height, intArrayOf(paddingLeft, paddingTop, paddingRight, paddingBottom)) {} + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate) = null + + override fun getLiteModeCameraBounds() = bounds + override fun getCameraPosition(map: MapboxMap): CameraPosition? { val padding = this.padding.clone() - val widthPad = ((map.width + map.padding[0] + map.padding[2] - width) / 2).toInt() - val heightPad = ((map.height + map.padding[1] + map.padding[3] - height) / 2).toInt() - padding[0] += widthPad - padding[1] += heightPad - padding[2] += widthPad - padding[3] += heightPad - Log.d(TAG, "map ${map.width} ${map.height}, set $width $height -> ${padding.map { it.toString() }.reduce { a, b -> "$a,$b"}}") - return map.getCameraForLatLngBounds(bounds, padding) + + val mapPadding = map.cameraPosition.padding + mapPadding?.let { + for (i in 0..3) { + padding[i] += it[i].toInt() + } + } + + val widthPadding = ((map.width - width) / 2).toInt() + val heightPadding = ((map.height - height) / 2).toInt() + padding[0] += widthPadding + padding[1] += heightPadding + padding[2] += widthPadding + padding[3] += heightPadding + + Log.d(TAG, "map ${map.width} ${map.height}, set $width $height -> ${Arrays.toString(padding)}") + return map.getCameraForLatLngBounds(bounds, padding)?.let { + CameraPosition.Builder(it) + .apply { + mapPadding?.let { + padding(it) + } + }.build() + } + } override fun equals(other: Any?): Boolean { diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt index 675429b90e72f0be427d5915e5b207f6936d5ec0..d5cd86d49b3653ef229e38375f3a7f0ec5f13b07 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt @@ -17,11 +17,13 @@ package org.microg.gms.maps.mapbox import android.graphics.Point +import android.graphics.PointF import android.os.Parcel import android.util.Log import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.ObjectWrapper import com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate +import com.google.android.gms.maps.internal.IGoogleMapDelegate import com.google.android.gms.maps.model.CameraPosition import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLngBounds @@ -32,29 +34,40 @@ import org.microg.gms.maps.mapbox.utils.toMapbox class CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() { - override fun zoomIn(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomIn()) - override fun zoomOut(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomOut()) + override fun zoomIn(): IObjectWrapper = ObjectWrapper.wrap(ZoomByCameraUpdate(1f)) + override fun zoomOut(): IObjectWrapper = ObjectWrapper.wrap(ZoomByCameraUpdate(-1f)) - override fun zoomTo(zoom: Float): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.zoomTo(zoom.toDouble() - 1.0)) + override fun zoomTo(zoom: Float): IObjectWrapper = ObjectWrapper.wrap(ZoomToCameraUpdate(zoom)) override fun zoomBy(zoomDelta: Float): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta.toDouble())) + ObjectWrapper.wrap(ZoomByCameraUpdate(zoomDelta)).also { + Log.d(TAG, "zoomBy") + } override fun zoomByWithFocus(zoomDelta: Float, x: Int, y: Int): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta.toDouble(), Point(x, y))) + ObjectWrapper.wrap(ZoomByWithFocusCameraUpdate(zoomDelta, x, y)).also { + Log.d(TAG, "zoomByWithFocus") + } override fun newCameraPosition(cameraPosition: CameraPosition): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.newCameraPosition(cameraPosition.toMapbox())) + ObjectWrapper.wrap(NewCameraPositionCameraUpdate(cameraPosition)).also { + Log.d(TAG, "newCameraPosition") + } override fun newLatLng(latLng: LatLng): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.newLatLng(latLng.toMapbox())) + ObjectWrapper.wrap(NewLatLngCameraUpdate(latLng)).also { + Log.d(TAG, "newLatLng") + } override fun newLatLngZoom(latLng: LatLng, zoom: Float): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.newLatLngZoom(latLng.toMapbox(), zoom.toDouble() - 1.0)) + ObjectWrapper.wrap(NewLatLngZoomCameraUpdate(latLng, zoom)).also { + Log.d(TAG, "newLatLngZoom") + } override fun newLatLngBounds(bounds: LatLngBounds, padding: Int): IObjectWrapper = - ObjectWrapper.wrap(CameraUpdateFactory.newLatLngBounds(bounds.toMapbox(), padding)) + ObjectWrapper.wrap(NewLatLngBoundsCameraUpdate(bounds, padding)).also { + Log.d(TAG, "newLatLngBounds") + } override fun scrollBy(x: Float, y: Float): IObjectWrapper { Log.d(TAG, "unimplemented Method: scrollBy") @@ -62,7 +75,9 @@ class CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() { } override fun newLatLngBoundsWithSize(bounds: LatLngBounds, width: Int, height: Int, padding: Int): IObjectWrapper = - ObjectWrapper.wrap(CameraBoundsWithSizeUpdate(bounds.toMapbox(), width, height, padding)) + ObjectWrapper.wrap(CameraBoundsWithSizeUpdate(bounds.toMapbox(), width, height, padding)).also { + Log.d(TAG, "newLatLngBoundsWithSize") + } override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = if (super.onTransact(code, data, reply, flags)) { @@ -71,9 +86,11 @@ class CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() { Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false } - private inner class NoCameraUpdate : CameraUpdate { + private inner class NoCameraUpdate : CameraUpdate, LiteModeCameraUpdate { override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = mapboxMap.cameraPosition + + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = map.cameraPosition } companion object { @@ -81,4 +98,70 @@ class CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() { } } +interface LiteModeCameraUpdate { + fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition? + + fun getLiteModeCameraBounds(): com.mapbox.mapboxsdk.geometry.LatLngBounds? = null +} + +class ZoomToCameraUpdate(private val zoom: Float) : LiteModeCameraUpdate, CameraUpdate { + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = + CameraPosition.Builder(map.cameraPosition).zoom(zoom).build() + + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = + CameraUpdateFactory.zoomTo(zoom.toDouble() - 1.0).getCameraPosition(mapboxMap) + +} + +class ZoomByCameraUpdate(private val delta: Float) : LiteModeCameraUpdate, CameraUpdate { + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = + CameraPosition.Builder(map.cameraPosition).zoom(map.cameraPosition.zoom + delta).build() + + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = + CameraUpdateFactory.zoomBy(delta.toDouble()).getCameraPosition(mapboxMap) + +} + +class ZoomByWithFocusCameraUpdate(private val delta: Float, private val x: Int, private val y: Int) : LiteModeCameraUpdate, + CameraUpdate { + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = + CameraPosition.Builder(map.cameraPosition).zoom(map.cameraPosition.zoom + delta) + .target(map.projection.fromScreenLocation(ObjectWrapper.wrap(PointF(x.toFloat(), y.toFloat())))).build() + + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = + CameraUpdateFactory.zoomBy(delta.toDouble(), Point(x, y)).getCameraPosition(mapboxMap) +} + +class NewCameraPositionCameraUpdate(private val cameraPosition: CameraPosition) : LiteModeCameraUpdate, CameraUpdate { + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = this.cameraPosition + + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition = + this.cameraPosition.toMapbox() +} + +class NewLatLngCameraUpdate(private val latLng: LatLng) : LiteModeCameraUpdate, CameraUpdate { + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = + CameraPosition.Builder(map.cameraPosition).target(latLng).build() + + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = + CameraUpdateFactory.newLatLng(latLng.toMapbox()).getCameraPosition(mapboxMap) +} + +class NewLatLngZoomCameraUpdate(private val latLng: LatLng, private val zoom: Float) : LiteModeCameraUpdate, CameraUpdate { + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = + CameraPosition.Builder(map.cameraPosition).target(latLng).zoom(zoom).build() + + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = + CameraUpdateFactory.newLatLngZoom(latLng.toMapbox(), zoom - 1.0).getCameraPosition(mapboxMap) +} + +class NewLatLngBoundsCameraUpdate(private val bounds: LatLngBounds, internal val padding: Int) : LiteModeCameraUpdate, + CameraUpdate { + + override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition? = null + + override fun getLiteModeCameraBounds() = bounds.toMapbox() + override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? = + CameraUpdateFactory.newLatLngBounds(bounds.toMapbox(), padding).getCameraPosition(mapboxMap) +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt index 360d1539ffde3d4c02d23389ec9da3ab253d311a..bcb0b4ceb49346409397c48bcd1302a1dd3785c1 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt @@ -18,11 +18,11 @@ package org.microg.gms.maps.mapbox import android.annotation.SuppressLint import android.content.Context +import android.graphics.Bitmap import android.location.Location import android.os.* import androidx.annotation.IdRes import androidx.annotation.Keep -import android.util.DisplayMetrics import android.util.Log import android.view.Gravity import android.view.View @@ -53,11 +53,14 @@ import com.mapbox.mapboxsdk.plugins.annotation.Annotation import com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_ROUND import com.google.android.gms.dynamic.unwrap import com.mapbox.mapboxsdk.WellKnownTileServer +import org.microg.gms.maps.mapbox.model.InfoWindow +import org.microg.gms.maps.mapbox.model.getInfoWindowViewFor +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback import com.mapbox.mapboxsdk.location.engine.LocationEngineResult import org.microg.gms.maps.MapsConstants.* import org.microg.gms.maps.mapbox.model.* -import org.microg.gms.maps.mapbox.utils.MapContext import org.microg.gms.maps.mapbox.utils.MultiArchLoader import org.microg.gms.maps.mapbox.utils.toGms import org.microg.gms.maps.mapbox.utils.toMapbox @@ -74,13 +77,11 @@ fun runOnMainLooper(method: () -> Unit) { } } -class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) : IGoogleMapDelegate.Stub() { +class GoogleMapImpl(context: Context, var options: GoogleMapOptions) : AbstractGoogleMap(context) { val view: FrameLayout var map: MapboxMap? = null private set - val dpiFactor: Float - get() = context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT private var mapView: MapView? = null private var created = false @@ -88,16 +89,13 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) private var loaded = false private val mapLock = Object() - private val initializedCallbackList = mutableListOf() + private val initializedCallbackList = mutableListOf() private var loadedCallback: IOnMapLoadedCallback? = null private var cameraChangeListener: IOnCameraChangeListener? = null private var cameraMoveListener: IOnCameraMoveListener? = null private var cameraMoveCanceledListener: IOnCameraMoveCanceledListener? = null private var cameraMoveStartedListener: IOnCameraMoveStartedListener? = null private var cameraIdleListener: IOnCameraIdleListener? = null - private var mapClickListener: IOnMapClickListener? = null - private var mapLongClickListener: IOnMapLongClickListener? = null - private var markerClickListener: IOnMarkerClickListener? = null private var markerDragListener: IOnMarkerDragListener? = null private var myLocationChangeListener: IOnMyLocationChangeListener? = null @@ -114,31 +112,30 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } var lineManager: LineManager? = null - val pendingLines = mutableSetOf() + val pendingLines = mutableSetOf>() var lineId = 0L var fillManager: FillManager? = null - val pendingFills = mutableSetOf() + val pendingFills = mutableSetOf>() + val circles = mutableMapOf() var fillId = 0L - var circleManager: CircleManager? = null - val pendingCircles = mutableSetOf() - var circleId = 0L - var symbolManager: SymbolManager? = null val pendingMarkers = mutableSetOf() val markers = mutableMapOf() var markerId = 0L + val pendingBitmaps = mutableMapOf() + var groundId = 0L var tileId = 0L var storedMapType: Int = options.mapType + var mapStyle: MapStyleOptions? = null val waitingCameraUpdates = mutableListOf() var locationEnabled: Boolean = false init { - val mapContext = MapContext(context) BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources) LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context)) runOnMainLooper { @@ -184,7 +181,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } } - override fun getCameraPosition(): CameraPosition? = map?.cameraPosition?.toGms() + override fun getCameraPosition(): CameraPosition = + map?.cameraPosition?.toGms() ?: CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f) + override fun getMaxZoomLevel(): Float = (map?.maxZoomLevel?.toFloat() ?: 20f) + 1f override fun getMinZoomLevel(): Float = (map?.minZoomLevel?.toFloat() ?: 0f) + 1f @@ -210,14 +209,16 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } } - fun afterInitialized(runnable: () -> Unit) { - initializedCallbackList.add(object : IOnMapReadyCallback { - override fun onMapReady(map: IGoogleMapDelegate?) { - runnable() + fun afterInitialize(runnable: (MapboxMap) -> Unit) { + synchronized(mapLock) { + if (initialized) { + runnable(map!!) + } else { + initializedCallbackList.add(OnMapReadyCallback { + runnable(it) + }) } - - override fun asBinder(): IBinder? = null - }) + } } override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) { @@ -227,7 +228,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) this.map?.animateCamera(update, callback?.toMapbox()) } else { waitingCameraUpdates.add(update) - afterInitialized { callback?.onFinish() } + afterInitialize { callback?.onFinish() } } } } @@ -239,7 +240,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) this.map?.animateCamera(update, duration, callback?.toMapbox()) } else { waitingCameraUpdates.add(update) - afterInitialized { callback?.onFinish() } + afterInitialize { callback?.onFinish() } } } } @@ -248,24 +249,25 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) override fun setMapStyle(options: MapStyleOptions?): Boolean { Log.d(TAG, "setMapStyle options: " + options?.getJson()) + mapStyle = options return true } - override fun setMinZoomPreference(minZoom: Float) { - map?.setMinZoomPreference(minZoom.toDouble() - 1) + override fun setMinZoomPreference(minZoom: Float) = afterInitialize { + it.setMinZoomPreference(minZoom.toDouble() - 1) } - override fun setMaxZoomPreference(maxZoom: Float) { - map?.setMaxZoomPreference(maxZoom.toDouble() - 1) + override fun setMaxZoomPreference(maxZoom: Float) = afterInitialize { + it.setMaxZoomPreference(maxZoom.toDouble() - 1) } - override fun resetMinMaxZoomPreference() { - map?.setMinZoomPreference(MapboxConstants.MINIMUM_ZOOM.toDouble()) - map?.setMaxZoomPreference(MapboxConstants.MAXIMUM_ZOOM.toDouble()) + override fun resetMinMaxZoomPreference() = afterInitialize { + it.setMinZoomPreference(MapboxConstants.MINIMUM_ZOOM.toDouble()) + it.setMaxZoomPreference(MapboxConstants.MAXIMUM_ZOOM.toDouble()) } - override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) { - map?.setLatLngBoundsForCameraTarget(bounds?.toMapbox()) + override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) = afterInitialize { + it.setLatLngBoundsForCameraTarget(bounds?.toMapbox()) } override fun addPolyline(options: PolylineOptions): IPolylineDelegate? { @@ -291,6 +293,13 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } else { fill.update(fillManager) } + + val lineManager = lineManager + if (lineManager == null) { + pendingLines.addAll(fill.strokes) + } else { + for (stroke in fill.strokes) stroke.update(lineManager) + } } return fill } @@ -318,21 +327,32 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) return TileOverlayImpl(this, "t${tileId++}", options) } - override fun addCircle(options: CircleOptions): ICircleDelegate? { - val circle = CircleImpl(this, "c${circleId++}", options) + override fun addCircle(options: CircleOptions): ICircleDelegate { + val circle = CircleImpl(this, "c${fillId++}", options) synchronized(this) { - val circleManager = circleManager - if (circleManager == null) { - pendingCircles.add(circle) + val fillManager = fillManager + if (fillManager == null) { + pendingFills.add(circle) + } else { + circle.update(fillManager) + } + val lineManager = lineManager + if (lineManager == null) { + pendingLines.add(circle.line) } else { - circle.update(circleManager) + circle.line.update(lineManager) + } + circle.strokePattern?.let { + addBitmap( + it.getName(circle.strokeColor, circle.strokeWidth), + it.makeBitmap(circle.strokeColor, circle.strokeWidth) + ) } } return circle } override fun clear() { - circleManager?.let { clear(it) } lineManager?.let { clear(it) } fillManager?.let { clear(it) } symbolManager?.let { clear(it) } @@ -355,56 +375,30 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) override fun setMapType(type: Int) { storedMapType = type - applyMapType() + applyMapStyle() } - fun applyMapType() { - val circles = circleManager?.annotations?.values() + fun applyMapStyle() { val lines = lineManager?.annotations?.values() val fills = fillManager?.annotations?.values() val symbols = symbolManager?.annotations?.values() val update: (Style) -> Unit = { - circles?.let { runCatching { circleManager?.update(it) } } lines?.let { runCatching { lineManager?.update(it) } } fills?.let { runCatching { fillManager?.update(it) } } symbols?.let { runCatching { symbolManager?.update(it) } } } - // TODO: Serve map styles locally - when (storedMapType) { - MAP_TYPE_SATELLITE -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update) - MAP_TYPE_TERRAIN -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/mapbox/outdoors-v12"), update) - MAP_TYPE_HYBRID -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update) - //MAP_TYPE_NONE, MAP_TYPE_NORMAL, - else -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/microg/cjui4020201oo1fmca7yuwbor"), update) - } + map?.setStyle( + getStyle(mapContext, storedMapType, mapStyle), + update + ) map?.let { BitmapDescriptorFactoryImpl.registerMap(it) } } - override fun setWatermarkEnabled(watermark: Boolean) { - map?.uiSettings?.isLogoEnabled = watermark - } - - override fun isTrafficEnabled(): Boolean { - Log.d(TAG, "unimplemented Method: isTrafficEnabled") - return false - } - - override fun setTrafficEnabled(traffic: Boolean) { - Log.d(TAG, "unimplemented Method: setTrafficEnabled") - - } - - override fun isIndoorEnabled(): Boolean { - Log.d(TAG, "unimplemented Method: isIndoorEnabled") - return false - } - - override fun setIndoorEnabled(indoor: Boolean) { - Log.d(TAG, "unimplemented Method: setIndoorEnabled") - + override fun setWatermarkEnabled(watermark: Boolean) = afterInitialize { + it.uiSettings.isLogoEnabled = watermark } override fun isMyLocationEnabled(): Boolean { @@ -433,7 +427,6 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) Log.w(TAG, e) locationEnabled = false } - Unit } } @@ -443,96 +436,59 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } } - override fun setLocationSource(locationSource: ILocationSourceDelegate?) { - Log.d(TAG, "unimplemented Method: setLocationSource") - } - override fun setContentDescription(desc: String?) { mapView?.contentDescription = desc } - override fun getUiSettings(): IUiSettingsDelegate? = map?.uiSettings?.let { UiSettingsImpl(it) } + override fun getUiSettings(): IUiSettingsDelegate = + map?.uiSettings?.let { UiSettingsImpl(it) } ?: UiSettingsCache().also { + // Apply cached UI settings after map is initialized + initializedCallbackList.add(it.getMapReadyCallback()) + } - override fun getProjection(): IProjectionDelegate? = map?.projection?.let { + override fun getProjection(): IProjectionDelegate = map?.projection?.let { val experiment = try { map?.cameraPosition?.tilt == 0.0 && map?.cameraPosition?.bearing == 0.0 } catch (e: Exception) { Log.w(TAG, e); false } ProjectionImpl(it, experiment) - } + } ?: DummyProjection() override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) { cameraChangeListener = listener } - override fun setOnMapClickListener(listener: IOnMapClickListener?) { - mapClickListener = listener - } - - override fun setOnMapLongClickListener(listener: IOnMapLongClickListener?) { - mapLongClickListener = listener - } - - override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) { - markerClickListener = listener - } - override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) { markerDragListener = listener } - override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) { - Log.d(TAG, "unimplemented Method: setOnInfoWindowClickListener") - - } - - override fun setInfoWindowAdapter(adapter: IInfoWindowAdapter?) { - Log.d(TAG, "unimplemented Method: setInfoWindowAdapter") - - } - - override fun getTestingHelper(): IObjectWrapper? { - Log.d(TAG, "unimplemented Method: getTestingHelper") - return null - } - - override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) { - myLocationChangeListener = listener - } - - override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) { - Log.d(TAG, "unimplemented Method: setOnMyLocationButtonClickListener") - - } - override fun snapshot(callback: ISnapshotReadyCallback, bitmap: IObjectWrapper?) { - Log.d(TAG, "unimplemented Method: snapshot") - - } - - override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) { - Log.d(TAG, "setPadding: $left $top $right $bottom") - map?.let { map -> - map.setPadding(left, top, right, bottom) - val fourDp = mapView?.context?.resources?.getDimension(R.dimen.mapbox_four_dp)?.toInt() - ?: 0 - val ninetyTwoDp = mapView?.context?.resources?.getDimension(R.dimen.mapbox_ninety_two_dp)?.toInt() - ?: 0 - map.uiSettings.setLogoMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp) - map.uiSettings.setCompassMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp) - map.uiSettings.setAttributionMargins(left + ninetyTwoDp, top + fourDp, right + fourDp, bottom + fourDp) + val map = map + if (map == null) { + // Snapshot cannot be taken + runOnMainLooper { callback.onBitmapWrappedReady(ObjectWrapper.wrap(null)) } + } else { + map.snapshot { + runOnMainLooper { + callback.onBitmapWrappedReady(ObjectWrapper.wrap(it)) + } + } } } - override fun isBuildingsEnabled(): Boolean { - Log.d(TAG, "unimplemented Method: isBuildingsEnabled") - return false - } - - override fun setBuildingsEnabled(buildings: Boolean) { - Log.d(TAG, "unimplemented Method: setBuildingsEnabled") + override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) = afterInitialize { map -> + Log.d(TAG, "setPadding: $left $top $right $bottom") + CameraUpdateFactory.paddingTo(left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) + .let { map.moveCamera(it) } + val fourDp = mapView?.context?.resources?.getDimension(R.dimen.maplibre_four_dp)?.toInt() + ?: 0 + val ninetyTwoDp = mapView?.context?.resources?.getDimension(R.dimen.maplibre_ninety_two_dp)?.toInt() + ?: 0 + map.uiSettings.setLogoMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp) + map.uiSettings.setCompassMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp) + map.uiSettings.setAttributionMargins(left + ninetyTwoDp, top + fourDp, right + fourDp, bottom + fourDp) } override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) { @@ -574,7 +530,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) override fun onCreate(savedInstanceState: Bundle?) { if (!created) { Log.d(TAG, "create"); - val mapView = MapView(MapContext(context)) + val mapView = MapView(mapContext) this.mapView = mapView view.addView(mapView) mapView.onCreate(savedInstanceState?.toMapbox()) @@ -611,6 +567,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) map.addOnCameraMoveListener { try { cameraMoveListener?.onCameraMove() + currentInfoWindow?.update() } catch (e: Exception) { Log.w(TAG, e) } @@ -631,7 +588,11 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } map.addOnMapClickListener { latlng -> try { - mapClickListener?.let { if (!hasSymbolAt(latlng)) it.onMapClick(latlng.toGms()); } + if (!hasSymbolAt(latlng)) { + mapClickListener?.onMapClick(latlng.toGms()) + currentInfoWindow?.close() + currentInfoWindow = null + } } catch (e: Exception) { Log.w(TAG, e) } @@ -646,7 +607,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) false } - applyMapType() + applyMapStyle() options.minZoomPreference?.let { if (it != 0f) map.setMinZoomPreference(it.toDouble()) } options.maxZoomPreference?.let { if (it != 0f) map.setMaxZoomPreference(it.toDouble()) } options.latLngBoundsForCameraTarget?.let { map.setLatLngBoundsForCameraTarget(it.toMapbox()) } @@ -662,11 +623,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) val initializedCallbackList = ArrayList(initializedCallbackList) Log.d(TAG, "Invoking ${initializedCallbackList.size} callbacks delayed, as map is initialized") for (callback in initializedCallbackList) { - try { - callback.onMapReady(this) - } catch (e: Exception) { - Log.w(TAG, e) - } + callback.onMapReady(map) } } @@ -675,11 +632,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) if (loaded) return@let val symbolManager: SymbolManager val lineManager: LineManager - val circleManager: CircleManager val fillManager: FillManager synchronized(mapLock) { - circleManager = CircleManager(view, map, it) fillManager = FillManager(view, map, it) symbolManager = SymbolManager(view, map, it) lineManager = LineManager(view, map, it) @@ -687,17 +642,21 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) this.symbolManager = symbolManager this.lineManager = lineManager - this.circleManager = circleManager this.fillManager = fillManager } symbolManager.iconAllowOverlap = true symbolManager.addClickListener { + val marker = markers[it.id] try { - markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } == true + if (markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } == true) { + return@addClickListener true + } } catch (e: Exception) { Log.w(TAG, e) - false + return@addClickListener false } + + marker?.let { showInfoWindow(it) } == true } symbolManager.addDragListener(object : OnSymbolDragListener { override fun onAnnotationDragStarted(annotation: Symbol?) { @@ -710,22 +669,42 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) override fun onAnnotationDrag(annotation: Symbol?) { try { - markers[annotation?.id]?.let { markerDragListener?.onMarkerDrag(it) } + annotation?.let { symbol -> + markers[symbol.id]?.let { marker -> + marker.setPositionWhileDragging(symbol.latLng.toGms()) + markerDragListener?.onMarkerDrag(marker) + } + } } catch (e: Exception) { Log.w(TAG, e) } } override fun onAnnotationDragFinished(annotation: Symbol?) { + mapView?.post { try { markers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) } } catch (e: Exception) { Log.w(TAG, e) } + } } }) - pendingCircles.forEach { it.update(circleManager) } - pendingCircles.clear() + fillManager.addClickListener { fill -> + try { + circles[fill.id]?.let { circle -> + if (circle.isClickable) { + circleClickListener?.let { + it.onCircleClick(circle) + return@addClickListener true + } + } + } + } catch (e: Exception) { + Log.w(TAG, e) + } + false + } pendingFills.forEach { it.update(fillManager) } pendingFills.clear() pendingLines.forEach { it.update(lineManager) } @@ -733,7 +712,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) pendingMarkers.forEach { it.update(symbolManager) } pendingMarkers.clear() - val mapContext = MapContext(context) + pendingBitmaps.forEach { map -> it.addImage(map.key, map.value) } + pendingBitmaps.clear() + map.locationComponent.apply { activateLocationComponent(LocationComponentActivationOptions.builder(mapContext, it) .useSpecializedLocationLayer(true) @@ -756,27 +737,45 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } } - override fun useViewLifecycleWhenInFragment(): Boolean { - Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment") + override fun showInfoWindow(marker: AbstractMarker): Boolean { + infoWindowAdapter.getInfoWindowViewFor(marker, mapContext)?.let { infoView -> + currentInfoWindow?.close() + currentInfoWindow = InfoWindow(infoView, this, marker).also { infoWindow -> + mapView?.let { infoWindow.open(it) } + } + return true + } return false } + internal fun addBitmap(name: String, bitmap: Bitmap) { + val map = map + if (map != null) { + map.getStyle { + it.addImage(name, bitmap) + } + } else { + pendingBitmaps[name] = bitmap + } + } + override fun onResume() = mapView?.onResume() ?: Unit override fun onPause() = mapView?.onPause() ?: Unit override fun onDestroy() { Log.d(TAG, "destroy") - circleManager?.onDestroy() - circleManager = null lineManager?.onDestroy() lineManager = null fillManager?.onDestroy() fillManager = null + circles.clear() symbolManager?.onDestroy() symbolManager = null + currentInfoWindow?.close() + pendingMarkers.clear() markers.clear() @@ -788,8 +787,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) mapView?.onDestroy() mapView = null - // Don't make it null; this object is not deleted immediately, and it may want to access map.* stuff - //map = null + map = null created = false initialized = false @@ -804,15 +802,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) mapView?.onStop() } - override fun onEnterAmbient(bundle: Bundle?) { - Log.d(TAG, "unimplemented Method: onEnterAmbient") - } - - override fun onExitAmbient() { - Log.d(TAG, "unimplemented Method: onExitAmbient") - } - override fun onLowMemory() = mapView?.onLowMemory() ?: Unit + override fun onSaveInstanceState(outState: Bundle) { val newBundle = Bundle() mapView?.onSaveInstanceState(newBundle) @@ -821,16 +812,25 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) fun getMapAsync(callback: IOnMapReadyCallback) { synchronized(mapLock) { - if (initialized) { - Log.d(TAG, "Invoking callback instantly, as map is initialized") + + val runCallback = { try { callback.onMapReady(this) } catch (e: Exception) { Log.w(TAG, e) } + } + + if (initialized) { + Log.d(TAG, "Invoking callback instantly, as map is initialized") + runCallback() + } else if (mapView?.isShown != true) { + // If map is not shown, an app (e.g. Dott) may expect it to initialize anyway – before showing it + Log.d(TAG, "Invoking callback instantly: map cannot be initialized because it is not shown (yet)") + runCallback() } else { Log.d(TAG, "Delay callback invocation, as map is not yet initialized") - initializedCallbackList.add(callback) + initializedCallbackList.add { runCallback() } } } } diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt new file mode 100644 index 0000000000000000000000000000000000000000..c5ad88440ada803377083dcea581ef9c05082192 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt @@ -0,0 +1,682 @@ +package org.microg.gms.maps.mapbox + +import android.Manifest +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.content.Intent.ACTION_VIEW +import android.content.pm.PackageManager +import android.graphics.PointF +import android.location.Location +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.util.Log +import android.view.View +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.widget.FrameLayout +import android.widget.ImageView +import androidx.annotation.UiThread +import androidx.core.app.ActivityCompat +import com.google.android.gms.dynamic.IObjectWrapper +import com.google.android.gms.dynamic.ObjectWrapper +import com.google.android.gms.dynamic.unwrap +import com.google.android.gms.maps.GoogleMapOptions +import com.google.android.gms.maps.internal.* +import com.google.android.gms.maps.model.* +import com.google.android.gms.maps.model.internal.* +import com.mapbox.mapboxsdk.Mapbox +import com.mapbox.mapboxsdk.WellKnownTileServer +import com.mapbox.mapboxsdk.location.engine.* +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions +import com.mapbox.mapboxsdk.snapshotter.MapSnapshot +import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter +import com.mapbox.mapboxsdk.style.layers.* +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource +import com.mapbox.turf.TurfConstants.UNIT_METERS +import com.mapbox.turf.TurfMeasurement +import org.microg.gms.maps.MapsConstants +import org.microg.gms.maps.mapbox.model.* +import org.microg.gms.maps.mapbox.utils.toGms +import org.microg.gms.maps.mapbox.utils.toMapbox +import org.microg.gms.maps.mapbox.utils.toPoint +import java.util.concurrent.atomic.AtomicBoolean +import kotlin.math.max +import kotlin.math.roundToInt + +// From com.mapbox.mapboxsdk.location.LocationComponent +const val DEFAULT_INTERVAL_MILLIS = 1000L +const val DEFAULT_FASTEST_INTERVAL_MILLIS = 1000L + +class MetaSnapshot( + val snapshot: MapSnapshot, + val cameraPosition: CameraPosition, + val cameraBounds: com.mapbox.mapboxsdk.geometry.LatLngBounds?, + val width: Int, + val height: Int, + val paddingRight: Int, + val paddingTop: Int, + val dpi: Float +) { + fun latLngForPixelFixed(point: PointF) = snapshot.latLngForPixel( + PointF( + point.x / dpi, point.y / dpi + ) + ) +} + +class LiteGoogleMapImpl(context: Context, var options: GoogleMapOptions) : AbstractGoogleMap(context) { + + internal val view: FrameLayout = FrameLayout(mapContext) + val map: ImageView + + private var created = false + + private var cameraPosition: CameraPosition = options.camera + private var cameraBounds: com.mapbox.mapboxsdk.geometry.LatLngBounds? = null + + private var mapType: Int = options.mapType + private var mapStyle: MapStyleOptions? = null + + private var currentSnapshotter: MapSnapshotter? = null + + private var lastSnapshot: MetaSnapshot? = null + + private var lastTouchPosition = PointF(0f, 0f) + + private val afterNextDrawCallback = mutableListOf<() -> Unit>() + private var cameraChangeListener: IOnCameraChangeListener? = null + + private var myLocationEnabled = false + private var myLocation: Location? = null + private var locationEngineProvider: LocationEngine = LocationEngineDefault.getDefaultLocationEngine(mapContext) + private val locationListener = object : LocationEngineCallback { + override fun onSuccess(result: LocationEngineResult?) { + this@LiteGoogleMapImpl.myLocation = result?.lastLocation + postUpdateSnapshot() + } + + override fun onFailure(exception: Exception) { + // same behavior as MapLibre's LocationComponent + Log.e(TAG, "Failed to obtain location update", exception) + } + } + + internal val markers: MutableList = mutableListOf() + internal val polygons: MutableList = mutableListOf() + internal val polylines: MutableList = mutableListOf() + internal val circles: MutableList = mutableListOf() + + private var nextObjectId = 0 + + private var showWatermark = true + + private val updatePosted = AtomicBoolean(false) + + init { + map = ImageView(mapContext).apply { + layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + } + + view.addView(map) + + view.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + postUpdateSnapshot() + currentInfoWindow?.update() + } + + BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources) + + // noinspection ClickableViewAccessibility; touch listener only has side effects + map.setOnTouchListener { _, event -> + lastTouchPosition = PointF(event.x + map.paddingLeft, event.y + map.paddingTop) + false + } + + map.setOnClickListener { + + // Test if clickable + if ((view.parent as View?)?.isClickable == false) return@setOnClickListener + + lastSnapshot?.let { meta -> + // Calculate marker hitboxes + for (marker in markers.filter { it.isVisible }) { + + marker.getIconDimensions()?.let { iconDimensions -> // consider only markers with icon + val anchorPoint = meta.snapshot.pixelForLatLng(marker.position.toMapbox()) + + val leftX = anchorPoint.x - marker.anchor[0] * iconDimensions[0] + val topY = anchorPoint.y - marker.anchor[1] * iconDimensions[1] + + if (lastTouchPosition.x >= leftX && lastTouchPosition.x <= leftX + iconDimensions[0] + && lastTouchPosition.y >= topY && lastTouchPosition.y <= topY + iconDimensions[1]) { + // Marker was clicked + if (markerClickListener?.onMarkerClick(marker) == true) { + currentInfoWindow?.close() + currentInfoWindow = null + return@setOnClickListener + } else if (showInfoWindow(marker)) { + return@setOnClickListener + } + } + } + } + + currentInfoWindow?.close() + currentInfoWindow = null + + // Test if circle was clicked + for (circle in circles.filter { it.isVisible && it.isClickable }) { + Log.d(TAG, "last touch ${lastTouchPosition.x}, ${lastTouchPosition.y}, turf ${TurfMeasurement.distance( + circle.center.toPoint(), + meta.latLngForPixelFixed(lastTouchPosition).toPoint(), + UNIT_METERS + )}, radius ${circle.radiusInMeters}") + if (TurfMeasurement.distance( + circle.center.toPoint(), + meta.latLngForPixelFixed(lastTouchPosition).toPoint(), + UNIT_METERS + ) <= circle.radiusInMeters) { + // Circle was clicked + circleClickListener?.onCircleClick(circle) + return@setOnClickListener + } + } + + val clickedPosition = meta.latLngForPixelFixed(lastTouchPosition) + val clickListenerConsumedClick = mapClickListener?.let { + it.onMapClick(clickedPosition.toGms()) + true + } ?: false + + if (clickListenerConsumedClick) return@setOnClickListener + + // else open external map at clicked location + val intent = + Intent(ACTION_VIEW, Uri.parse("geo:${clickedPosition.latitude},${clickedPosition.longitude}")) + + try { + context.startActivity(intent) + } catch (e: ActivityNotFoundException) { + Log.e(TAG, "No compatible mapping application installed. Not handling click.") + } + } + + + } + map.setOnLongClickListener { + mapLongClickListener?.onMapLongClick( + lastSnapshot?.latLngForPixelFixed(lastTouchPosition)?.toGms() ?: LatLng(0.0, 0.0) + ) + mapLongClickListener != null + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + if (!created) { + + Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox) + + if (savedInstanceState?.containsKey(BUNDLE_CAMERA_POSITION) == true) { + cameraPosition = savedInstanceState.getParcelable(BUNDLE_CAMERA_POSITION)!! + cameraBounds = savedInstanceState.getParcelable(BUNDLE_CAMERA_BOUNDS) + } + + postUpdateSnapshot() + + created = true + } + } + + internal fun postUpdateSnapshot() { + if (updatePosted.compareAndSet(false, true)) { + Handler(Looper.getMainLooper()).post { + updatePosted.set(false) + updateSnapshot() + } + } + } + + @UiThread + private fun updateSnapshot() { + + val cameraPosition = cameraPosition + val dpi = dpiFactor + + val cameraBounds = cameraBounds + + val pixelWidth = map.width + val pixelHeight = map.height + + val styleBuilder = Style.Builder().fromUri(getStyleUriByMapType(mapType)) + // TODO should be getStyle(mapContext, mapType, mapStyle) + + // Add visible polygons (before polylines, so that they are drawn below their strokes) + for (polygon in polygons.filter { it.isVisible }) { + styleBuilder.withLayer( + FillLayer("l${polygon.id}", polygon.id).withProperties( + PropertyFactory.fillColor(polygon.fillColor) + ) + ).withSource( + GeoJsonSource(polygon.id, polygon.annotationOptions.geometry) + ) + } + + // Add visible polylines + for (polyline in polylines.filter { it.isVisible }) { + styleBuilder.withLayer( + LineLayer("l${polyline.id}", polyline.id).withProperties( + PropertyFactory.lineWidth(polyline.width), + PropertyFactory.lineColor(polyline.color), + PropertyFactory.lineCap(Property.LINE_CAP_ROUND) + ) + ).withSource( + GeoJsonSource(polyline.id, polyline.annotationOptions.geometry) + ) + } + + // Add circles + for (circle in circles.filter { it.isVisible }) { + styleBuilder.withLayer(FillLayer("l${circle.id}c", circle.id).withProperties( + PropertyFactory.fillColor(circle.fillColor) + )).withSource(GeoJsonSource(circle.id, circle.annotationOptions.geometry)) + + styleBuilder.withLayer(LineLayer("l${circle.id}s", "${circle.id}s").withProperties( + PropertyFactory.lineWidth(circle.strokeWidth), + PropertyFactory.lineColor(circle.strokeColor), + PropertyFactory.lineCap(Property.LINE_CAP_ROUND), + ).apply { + circle.strokePattern?.let { + val name = it.getName(circle.strokeColor, circle.strokeWidth, dpi) + withProperties(PropertyFactory.linePattern(name)) + styleBuilder.withImage(name, it.makeBitmap(circle.strokeColor, circle.strokeWidth, dpi)) + } + }).withSource(GeoJsonSource("${circle.id}s", circle.line.annotationOptions.geometry)) + } + + // Add markers + BitmapDescriptorFactoryImpl.put(styleBuilder) + for (marker in markers.filter { it.isVisible }) { + val layer = SymbolLayer("l${marker.id}", marker.id).withProperties( + PropertyFactory.symbolSortKey(marker.zIndex), + PropertyFactory.iconAllowOverlap(true) + ) + marker.icon?.applyTo(layer, marker.anchor, dpi) + styleBuilder.withLayer(layer).withSource( + GeoJsonSource(marker.id, marker.annotationOptions.geometry) + ) + } + + // Add location overlay + if (myLocationEnabled) myLocation?.let { + val indicator = mapContext.getDrawable(R.drawable.location_dot)!! + styleBuilder.withImage("locationIndicator", indicator) + val layer = SymbolLayer("location", "locationSource").withProperties( + PropertyFactory.iconAllowOverlap(true), + PropertyFactory.iconImage("locationIndicator"), + PropertyFactory.iconAnchor(Property.ICON_ANCHOR_TOP_LEFT), + PropertyFactory.iconOffset(arrayOf( + 0.5f * indicator.minimumWidth / dpi, 0.5f * indicator.minimumHeight / dpi + )) + ) + styleBuilder.withLayer(layer).withSource( + GeoJsonSource( + "locationSource", + SymbolOptions().withLatLng(com.mapbox.mapboxsdk.geometry.LatLng(it.latitude, it.longitude)).geometry + ) + ) + } + + val dpiWidth = max(pixelWidth / dpi, 1f).roundToInt() + val dpiHeight = max(pixelHeight / dpi, 1f).roundToInt() + + val snapshotter = MapSnapshotter( + mapContext, MapSnapshotter.Options(dpiWidth, dpiHeight) + .withCameraPosition(this@LiteGoogleMapImpl.cameraPosition.toMapbox()) + .apply { + // if camera bounds are set, overwrite camera position + cameraBounds?.let { withRegion(it) } + } + .withStyleBuilder(styleBuilder) + .withLogo(showWatermark) + .withPixelRatio(dpi) + ) + + synchronized(this) { + this.currentSnapshotter?.cancel() + this.currentSnapshotter = snapshotter + } + + snapshotter.start({ + + val cameraPositionChanged = cameraPosition != lastSnapshot?.cameraPosition || (cameraBounds != lastSnapshot?.cameraBounds) + + lastSnapshot = MetaSnapshot( + it, cameraPosition, cameraBounds, pixelWidth, pixelHeight, view.paddingRight, view.paddingTop, dpi + ) + map.setImageBitmap(it.bitmap) + + for (callback in afterNextDrawCallback) callback() + afterNextDrawCallback.clear() + + if (cameraPositionChanged) { + // Notify apps that new projection is now available + cameraChangeListener?.onCameraChange(cameraPosition) + } + + currentInfoWindow?.update() + + synchronized(this) { + this.currentSnapshotter = null + } + + }, null) + } + + fun getMapAsync(callback: IOnMapReadyCallback) { + if (lastSnapshot == null) { + Log.d(TAG, "Invoking callback instantly, as a snapshot is ready") + callback.onMapReady(this) + } else { + Log.d(TAG, "Delay callback invocation, as snapshot has not been rendered yet") + afterNextDrawCallback.add { callback.onMapReady(this) } + } + } + + override fun getCameraPosition(): CameraPosition = cameraPosition + + override fun getMaxZoomLevel() = 21f + + override fun getMinZoomLevel() = 1f + + override fun moveCamera(cameraUpdate: IObjectWrapper?): Unit = cameraUpdate.unwrap()?.let { + cameraPosition = it.getLiteModeCameraPosition(this) ?: cameraPosition + cameraBounds = it.getLiteModeCameraBounds() + + postUpdateSnapshot() + } ?: Unit + + override fun animateCamera(cameraUpdate: IObjectWrapper?) = moveCamera(cameraUpdate) + + override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) { + moveCamera(cameraUpdate) + Log.d(TAG, "animateCameraWithCallback: animation not possible in lite mode, invoking callback instantly") + callback?.onFinish() + } + + override fun animateCameraWithDurationAndCallback( + cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback? + ) = animateCameraWithCallback(cameraUpdate, callback) + + override fun stopAnimation() { + Log.d(TAG, "stopAnimation: animation not possible in lite mode") + } + + override fun addPolyline(options: PolylineOptions): IPolylineDelegate { + return LitePolylineImpl(this, "polyline${nextObjectId++}", options).also { polylines.add(it) } + } + + override fun addPolygon(options: PolygonOptions): IPolygonDelegate { + return LitePolygonImpl( + "polygon${nextObjectId++}", options, this + ).also { + polygons.add(it) + polylines.addAll(it.strokes) + postUpdateSnapshot() + } + } + + override fun addMarker(options: MarkerOptions): IMarkerDelegate { + return LiteMarkerImpl("marker${nextObjectId++}", options, this).also { + markers.add(it) + postUpdateSnapshot() + } + } + + override fun addGroundOverlay(options: GroundOverlayOptions?): IGroundOverlayDelegate? { + Log.d(TAG, "addGroundOverlay: not supported in lite mode") + return null + } + + override fun addTileOverlay(options: TileOverlayOptions?): ITileOverlayDelegate? { + Log.d(TAG, "addTileOverlay: not supported in lite mode") + return null + } + + override fun clear() { + polylines.clear() + polygons.clear() + markers.clear() + circles.clear() + postUpdateSnapshot() + } + + override fun getMapType(): Int { + return mapType + } + + override fun setMapType(type: Int) { + mapType = type + postUpdateSnapshot() + } + + override fun isTrafficEnabled(): Boolean { + Log.d(TAG, "isTrafficEnabled: traffic not supported in lite mode") + return false + } + + override fun setTrafficEnabled(traffic: Boolean) { + Log.d(TAG, "setTrafficEnabled: traffic not supported in lite mode") + } + + override fun isIndoorEnabled(): Boolean { + Log.d(TAG, "isIndoorEnabled: indoor not supported in lite mode") + return false + } + + override fun setIndoorEnabled(indoor: Boolean) { + Log.d(TAG, "setIndoorEnabled: indoor not supported in lite mode") + } + + override fun isMyLocationEnabled(): Boolean = myLocationEnabled + + override fun setMyLocationEnabled(myLocation: Boolean) { + if (!myLocationEnabled && myLocation) { + activateLocationProvider() + } else if (myLocationEnabled && !myLocation) { + deactivateLocationProvider() + } // else situation is unchanged + myLocationEnabled = myLocation + } + + private fun activateLocationProvider() { + // Activate only if sufficient permissions + if (ActivityCompat.checkSelfPermission( + mapContext, Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission( + mapContext, Manifest.permission.ACCESS_COARSE_LOCATION + ) == PackageManager.PERMISSION_GRANTED + ) { + locationEngineProvider.requestLocationUpdates( + LocationEngineRequest.Builder(DEFAULT_INTERVAL_MILLIS) + .setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .build(), locationListener, Looper.getMainLooper() + ) + + } else { + Log.w(TAG, "Called setMyLocationEnabled(true) without sufficient permissions. Not showing location.") + } + } + + private fun deactivateLocationProvider() { + locationEngineProvider.removeLocationUpdates(locationListener) + } + + override fun getUiSettings(): IUiSettingsDelegate { + Log.d(TAG, "UI settings have no effect") + return UiSettingsCache() + } + + /** + * Gets a projection snapshot. This means that, in accordance to the docs, the projection object + * will represent the map as it is seen at the point in time that the projection is queried, and + * not updated later on. + */ + override fun getProjection(): IProjectionDelegate = lastSnapshot?.let { LiteProjection(it) } ?: DummyProjection() + + override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) { + cameraChangeListener = listener + } + + override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) { + Log.d(TAG, "setOnMarkerDragListener: marker drag is not supported in lite mode") + } + + override fun addCircle(options: CircleOptions): ICircleDelegate { + return LiteCircleImpl(this, "circle${nextObjectId++}", options).also { circles.add(it) } + } + + override fun snapshot(callback: ISnapshotReadyCallback?, bitmap: IObjectWrapper?) { + val lastSnapshot = lastSnapshot + if (lastSnapshot == null) { + afterNextDrawCallback.add { + callback?.onBitmapWrappedReady(ObjectWrapper.wrap(this@LiteGoogleMapImpl.lastSnapshot!!.snapshot.bitmap)) + } + } else { + callback?.onBitmapWrappedReady(ObjectWrapper.wrap(lastSnapshot.snapshot.bitmap)) + } + } + + override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) { + view.setPadding(left, top, right, bottom) + postUpdateSnapshot() + } + + override fun isBuildingsEnabled(): Boolean { + Log.d(TAG, "isBuildingsEnabled: never enabled in light mode") + return false + } + + override fun setBuildingsEnabled(buildings: Boolean) { + Log.d(TAG, "setBuildingsEnabled: cannot be enabled in light mode") + } + + override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) = callback?.let { onMapLoadedCallback -> + if (lastSnapshot != null) { + Log.d(TAG, "Invoking map loaded callback instantly, as a snapshot is ready") + onMapLoadedCallback.onMapLoaded() + } + else { + Log.d(TAG, "Delaying map loaded callback, as snapshot has not been taken yet") + afterNextDrawCallback.add { onMapLoadedCallback.onMapLoaded() } + } + Unit + } ?: Unit + + override fun setWatermarkEnabled(watermark: Boolean) { + showWatermark = watermark + } + + override fun showInfoWindow(marker: AbstractMarker): Boolean { + infoWindowAdapter.getInfoWindowViewFor(marker, mapContext)?.let { infoView -> + currentInfoWindow?.close() + currentInfoWindow = InfoWindow(infoView, this, marker).also { infoWindow -> + infoWindow.open(view) + } + return true + } + return false + } + + override fun onResume() { + if (myLocationEnabled) activateLocationProvider() + } + + override fun onPause() { + synchronized(this) { + currentSnapshotter?.cancel() + currentSnapshotter = null + } + deactivateLocationProvider() + } + + override fun onDestroy() { + view.removeView(map) + } + + override fun onLowMemory() { + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putParcelable(BUNDLE_CAMERA_POSITION, cameraPosition) + outState.putParcelable(BUNDLE_CAMERA_BOUNDS, cameraBounds) + } + + override fun setContentDescription(desc: String?) { + view.contentDescription = desc + } + + override fun setMapStyle(options: MapStyleOptions?): Boolean { + Log.d(TAG, "setMapStyle options: " + options?.getJson()) + mapStyle = options + + return true + } + + override fun setMinZoomPreference(minZoom: Float) { + Log.d(TAG, "setMinZoomPreference: no interactivity in lite mode") + } + + override fun setMaxZoomPreference(maxZoom: Float) { + Log.d(TAG, "setMaxZoomPreference: no interactivity in lite mode") + } + + override fun resetMinMaxZoomPreference() { + Log.d(TAG, "resetMinMaxZoomPreference: no interactivity in lite mode") + } + + override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) { + Log.d(TAG, "setLatLngBoundsForCameraTarget: no interactivity in lite mode") + } + + override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) { + Log.d(TAG, "setCameraMoveStartedListener: event not supported in lite mode") + } + + override fun setCameraMoveListener(listener: IOnCameraMoveListener?) { + Log.d(TAG, "setCameraMoveListener: event not supported in lite mode") + + } + + override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) { + Log.d(TAG, "setCameraMoveCanceledListener: event not supported in lite mode") + } + + override fun setCameraIdleListener(listener: IOnCameraIdleListener?) { + Log.d(TAG, "setCameraIdleListener: event not supported in lite mode") + } + + override fun onStart() { + } + + override fun onStop() { + } + + companion object { + private val TAG = "GmsMapLite" + private val BUNDLE_CAMERA_POSITION = "camera" + private val BUNDLE_CAMERA_BOUNDS = "cameraBounds" + } +} + +// TODO custom colors +fun getStyleUriByMapType(mapType: Int) = when (mapType) { + MapsConstants.MAP_TYPE_SATELLITE -> "mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi" + MapsConstants.MAP_TYPE_TERRAIN -> "mapbox://styles/mapbox/outdoors-v12" + MapsConstants.MAP_TYPE_HYBRID -> "mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi" + //MAP_TYPE_NONE, MAP_TYPE_NORMAL, + else -> "mapbox://styles/microg/cjui4020201oo1fmca7yuwbor" +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt index daf4bfb92e5987a087bafcb020536d9af31aeefb..69135ab29904e67093951dfd4b33b4065456712b 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt @@ -32,12 +32,18 @@ import com.google.android.gms.maps.internal.IOnMapReadyCallback class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stub() { - private var map: GoogleMapImpl? = null + private var map: IGoogleMapDelegate? = null private var options: GoogleMapOptions? = null override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle?) { this.options = options - map?.options = options + map?.apply { + if (this is GoogleMapImpl) { + this.options = options + } else if (this is LiteGoogleMapImpl) { + this.options = options + } + } } override fun onCreate(savedInstanceState: Bundle?) { @@ -47,7 +53,11 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu if (options == null) { options = GoogleMapOptions() } - map = GoogleMapImpl(activity, options ?: GoogleMapOptions()) + if (options?.liteMode == true) { + map = LiteGoogleMapImpl(activity, options ?: GoogleMapOptions()) + } else { + map = GoogleMapImpl(activity, options ?: GoogleMapOptions()) + } } override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle?): IObjectWrapper { @@ -56,13 +66,25 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu } Log.d(TAG, "onCreateView: ${options?.camera?.target}") if (map == null) { - map = GoogleMapImpl(activity, options ?: GoogleMapOptions()) + map = if (options?.liteMode == true) { + LiteGoogleMapImpl(activity, options ?: GoogleMapOptions()) + } else { + GoogleMapImpl(activity, options ?: GoogleMapOptions()) + } + } + map!!.apply { + onCreate(savedInstanceState) + + val view = when (this) { + is GoogleMapImpl -> this.view + is LiteGoogleMapImpl -> this.view + else -> null + } + + val parent = view?.parent as ViewGroup? + parent?.removeView(view) + return ObjectWrapper.wrap(view) } - map!!.onCreate(savedInstanceState) - val view = map!!.view - val parent = view.parent as ViewGroup? - parent?.removeView(view) - return ObjectWrapper.wrap(view) } override fun getMap(): IGoogleMapDelegate? = map @@ -74,7 +96,10 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu override fun onPause() = map?.onPause() ?: Unit override fun onLowMemory() = map?.onLowMemory() ?: Unit override fun isReady(): Boolean = this.map != null - override fun getMapAsync(callback: IOnMapReadyCallback) = map?.getMapAsync(callback) ?: Unit + override fun getMapAsync(callback: IOnMapReadyCallback) = map?.let { + if (it is GoogleMapImpl) it.getMapAsync(callback) + else if (it is LiteGoogleMapImpl) it.getMapAsync(callback) + } ?: Unit override fun onDestroyView() { map?.onDestroy() diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt index bef3cd83c36914d5fbc245d6036e6fcf43b45015..4ce82b13e40ec82445210b3f084ee0ebf2eef6ca 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt @@ -30,12 +30,17 @@ import com.google.android.gms.maps.internal.IOnMapReadyCallback class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IMapViewDelegate.Stub() { private val options: GoogleMapOptions = options ?: GoogleMapOptions() - private var map: GoogleMapImpl? = null + private var map: IGoogleMapDelegate? = null override fun onCreate(savedInstanceState: Bundle?) { Log.d(TAG, "onCreate: ${options?.camera?.target}") - map = GoogleMapImpl(context, options) - map!!.onCreate(savedInstanceState) + map = if (options.liteMode) { + LiteGoogleMapImpl(context, options) + } else { + GoogleMapImpl(context, options) + }.apply { + this.onCreate(savedInstanceState) + } } override fun getMap(): IGoogleMapDelegate? = map @@ -53,8 +58,23 @@ class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IM override fun onLowMemory() = map?.onLowMemory() ?: Unit override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit - override fun getView(): IObjectWrapper = ObjectWrapper.wrap(map?.view) - override fun getMapAsync(callback: IOnMapReadyCallback) = map?.getMapAsync(callback) ?: Unit + override fun getView(): IObjectWrapper = ObjectWrapper.wrap( + map?.let { + when (it) { + is GoogleMapImpl -> it.view + is LiteGoogleMapImpl -> it.view + else -> null + } + } + ) + + override fun getMapAsync(callback: IOnMapReadyCallback) = map?.let { + when (it) { + is GoogleMapImpl -> it.getMapAsync(callback) + is LiteGoogleMapImpl -> it.getMapAsync(callback) + else -> null + } + } ?: Unit override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = if (super.onTransact(code, data, reply, flags)) { diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt new file mode 100644 index 0000000000000000000000000000000000000000..0214f9ca5d935f1b84a78e0e63e817bf0244ac07 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt @@ -0,0 +1,83 @@ +package org.microg.gms.maps.mapbox + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Paint +import com.google.android.gms.maps.model.Dash +import com.google.android.gms.maps.model.Dot +import com.google.android.gms.maps.model.Gap +import com.google.android.gms.maps.model.PatternItem + +fun PatternItem.getName(): String = when (this) { + is Dash -> "dash${this.length}" + is Gap -> "gap${this.length}" + is Dot -> "dot" + else -> this.javaClass.name +} + +/** + * Name of pattern, to identify it after it is added to map + */ +fun List.getName(color: Int, strokeWidth: Float, skew: Float = 1f) = joinToString("-") { + it.getName() +} + "-${color}-width${strokeWidth}-skew${skew}" + +/** + * Gets width that a bitmap for this pattern item would have if the pattern's bitmap + * were to be drawn with respect to aspect ratio onto a canvas with height 1. + */ +fun PatternItem.getWidth(strokeWidth: Float, skew: Float): Float = when (this) { + is Dash -> this.length + is Gap -> this.length + is Dot -> strokeWidth * skew + else -> 1f +} + +/** + * Gets width that a bitmap for this pattern would have if it were to be drawn + * with respect to aspect ratio onto a canvas with height 1. + */ +fun List.getWidth(strokeWidth: Float, skew: Float) = map { it.getWidth(strokeWidth, skew) }.sum() + +fun List.makeBitmap(color: Int, strokeWidth: Float, skew: Float = 1f): Bitmap = makeBitmap(Paint().apply { + setColor(color) + style = Paint.Style.FILL +}, strokeWidth, skew) + + +fun List.makeBitmap(paint: Paint, strokeWidth: Float, skew: Float): Bitmap { + + // Pattern aspect ratio is not respected by renderer + val width = getWidth(strokeWidth, skew).toInt() + val height = (strokeWidth * skew).toInt() // avoids squished image bugs + + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + + var drawCursor = 0f + for (item in this) { + when (item) { + is Dash -> canvas.drawRect( + drawCursor, + 0f, + drawCursor + item.getWidth(strokeWidth, skew), + strokeWidth * skew, + paint + ) + + // is Gap -> do nothing, only move cursor + + is Dot -> canvas.drawOval( + drawCursor, + 0f, + drawCursor + item.getWidth(strokeWidth, skew), + strokeWidth * skew, + paint + ) + } + + drawCursor += item.getWidth(strokeWidth, skew) + } + + return bitmap +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt index ab22186dc585533da0111700eeb466abe4168094..df743f27c3cedac0c8417792681d94f9b293f368 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt @@ -26,25 +26,30 @@ import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.VisibleRegion import com.mapbox.mapboxsdk.maps.Projection import com.google.android.gms.dynamic.unwrap +import com.google.android.gms.maps.model.LatLngBounds import org.microg.gms.maps.mapbox.utils.toGms import org.microg.gms.maps.mapbox.utils.toMapbox import kotlin.math.roundToInt +val ZERO_LAT_LNG = com.mapbox.mapboxsdk.geometry.LatLng(0.0, 0.0) + // TODO: Do calculations using backed up locations instead of live (which requires UI thread) class ProjectionImpl(private val projection: Projection, private val withoutTiltOrBearing: Boolean) : IProjectionDelegate.Stub() { - private val visibleRegion = projection.visibleRegion - private val farLeft = projection.toScreenLocation(visibleRegion.farLeft) - private val farRight = projection.toScreenLocation(visibleRegion.farRight) - private val nearLeft = projection.toScreenLocation(visibleRegion.nearLeft) - private val nearRight = projection.toScreenLocation(visibleRegion.nearRight) + private val visibleRegion = projection.getVisibleRegion(false) + private val farLeft = projection.toScreenLocation(visibleRegion.farLeft?: ZERO_LAT_LNG) + private val farRight = projection.toScreenLocation(visibleRegion.farRight?: ZERO_LAT_LNG) + private val nearLeft = projection.toScreenLocation(visibleRegion.nearLeft?: ZERO_LAT_LNG) + private val nearRight = projection.toScreenLocation(visibleRegion.nearRight?: ZERO_LAT_LNG) override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? = try { obj.unwrap()?.let { if (withoutTiltOrBearing) { val xPercent = (it.x.toFloat() - farLeft.x) / (farRight.x - farLeft.x) val yPercent = (it.y.toFloat() - farLeft.y) / (nearLeft.y - farLeft.y) - val lon = visibleRegion.farLeft.longitude + xPercent * (visibleRegion.farRight.longitude - visibleRegion.farLeft.longitude) - val lat = visibleRegion.farLeft.latitude + yPercent * (visibleRegion.nearLeft.latitude - visibleRegion.farLeft.latitude) + val lon = (visibleRegion.farLeft?.longitude ?: 0.0) + xPercent * + ((visibleRegion.farRight?.longitude ?: 0.0) - (visibleRegion.farLeft?.longitude ?: 0.0)) + val lat = (visibleRegion.farLeft?.latitude?: 0.0) + yPercent * + ((visibleRegion.nearLeft?.latitude?: 0.0) - (visibleRegion.farLeft?.latitude?: 0.0)) LatLng(lat, lon) } else { projection.fromScreenLocation(PointF(it)).toGms() @@ -58,8 +63,10 @@ class ProjectionImpl(private val projection: Projection, private val withoutTilt override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try { ObjectWrapper.wrap(latLng?.toMapbox()?.let { if (withoutTiltOrBearing) { - val xPercent = (it.longitude - visibleRegion.farLeft.longitude) / (visibleRegion.farRight.longitude - visibleRegion.farLeft.longitude) - val yPercent = (it.latitude - visibleRegion.farLeft.latitude) / (visibleRegion.nearLeft.latitude - visibleRegion.farLeft.latitude) + val xPercent = (it.longitude - (visibleRegion.farLeft?.longitude ?: 0.0)) / + ((visibleRegion.farRight?.longitude ?: 0.0) - (visibleRegion.farLeft?.longitude ?: 0.0)) + val yPercent = (it.latitude - (visibleRegion.farLeft?.longitude ?: 0.0)) / + ((visibleRegion.nearLeft?.longitude ?: 0.0) - (visibleRegion.farLeft?.longitude ?: 0.0)) val x = farLeft.x + xPercent * (farRight.x - farLeft.x) val y = farLeft.y + yPercent * (nearLeft.y - farLeft.y) Point(x.roundToInt(), y.roundToInt()) @@ -78,3 +85,48 @@ class ProjectionImpl(private val projection: Projection, private val withoutTilt private val TAG = "GmsMapProjection" } } + +class LiteProjection(private val snapshot: MetaSnapshot) : IProjectionDelegate.Stub() { + + private fun fromScreenLocationAfterPadding(point: Point?): LatLng = + point?.let { snapshot.latLngForPixelFixed(PointF(point)).toGms() } ?: LatLng(0.0, 0.0) + + override fun fromScreenLocation(obj: IObjectWrapper?): LatLng = fromScreenLocationAfterPadding(obj.unwrap()?.let { + Point((it.x - snapshot.paddingRight), (it.y - snapshot.paddingRight)) + }) + + override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = + ObjectWrapper.wrap(snapshot.snapshot.pixelForLatLng(latLng?.toMapbox()).let { + Point(it.x.roundToInt() + snapshot.paddingRight, it.y.roundToInt() + snapshot.paddingTop) + }) + + override fun getVisibleRegion(): VisibleRegion { + val nearLeft = fromScreenLocationAfterPadding(Point(0, snapshot.height)) + val nearRight = fromScreenLocationAfterPadding(Point(snapshot.width, snapshot.height)) + val farLeft = fromScreenLocationAfterPadding(Point(0, 0)) + val farRight = fromScreenLocationAfterPadding(Point(snapshot.width, 0)) + + return VisibleRegion(nearLeft, nearRight, farLeft, farRight, LatLngBounds(nearLeft, farRight)) + } +} + +class DummyProjection : IProjectionDelegate.Stub() { + override fun fromScreenLocation(obj: IObjectWrapper?): LatLng { + Log.d(TAG, "Map not initialized when calling getProjection(). Cannot calculate fromScreenLocation") + return LatLng(0.0, 0.0) + } + + override fun toScreenLocation(latLng: LatLng?): IObjectWrapper { + Log.d(TAG, "Map not initialized when calling getProjection(). Cannot calculate toScreenLocation") + return ObjectWrapper.wrap(Point(0, 0)) + } + + override fun getVisibleRegion(): VisibleRegion { + Log.d(TAG, "Map not initialized when calling getProjection(). Cannot calculate getVisibleRegion") + return VisibleRegion(LatLngBounds(LatLng(0.0, 0.0), LatLng(0.0, 0.0))) + } + + companion object { + private val TAG = "GmsMapDummyProjection" + } +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt new file mode 100644 index 0000000000000000000000000000000000000000..5cd4f8d47655cd84ba717700474a0ed9fa920e83 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt @@ -0,0 +1,364 @@ +package org.microg.gms.maps.mapbox + +import android.graphics.Color +import android.util.Log +import androidx.annotation.ColorInt +import androidx.annotation.FloatRange +import androidx.core.graphics.ColorUtils +import com.google.android.gms.maps.model.MapStyleOptions +import com.google.gson.Gson +import com.google.gson.JsonSyntaxException +import com.google.gson.annotations.SerializedName +import com.mapbox.mapboxsdk.maps.Style +import org.json.JSONArray +import org.json.JSONObject +import org.microg.gms.maps.MapsConstants +import org.microg.gms.maps.mapbox.utils.MapContext +import java.lang.NumberFormatException +import kotlin.math.pow +import kotlin.math.roundToInt + +const val TAG = "GmsMapStyles" +const val KEY_METADATA_FEATURE_TYPE = "microg:gms-type-feature" +const val KEY_METADATA_ELEMENT_TYPE = "microg:gms-type-element" + +const val SELECTOR_ALL = "all" +const val SELECTOR_ELEMENT_LABEL_TEXT_FILL = "labels.text.fill" +const val SELECTOR_ELEMENT_LABEL_TEXT_OUTLINE = "labels.text.outline" +const val KEY_LAYER_METADATA = "metadata" +const val KEY_LAYER_PAINT = "paint" + + + +fun getStyle(context: MapContext, storedMapType: Int, styleOptions: MapStyleOptions?): Style.Builder { + + // TODO: Serve map style resources locally + val styleJson = JSONObject( + context.assets.open( + when (storedMapType) { + MapsConstants.MAP_TYPE_SATELLITE, MapsConstants.MAP_TYPE_HYBRID -> "style-microg-satellite.json" + MapsConstants.MAP_TYPE_TERRAIN -> "style-mapbox-outdoors-v12.json" + //MAP_TYPE_NONE, MAP_TYPE_NORMAL, + else -> "style-microg-normal.json" + } + ).bufferedReader().readText() + ) + + styleOptions?.apply(styleJson) + + return Style.Builder().fromJson(styleJson.toString()) +} + +fun MapStyleOptions.apply(style: JSONObject) { + try { + Gson().fromJson(json, Array::class.java).let { styleOperations -> + + val layerArray = style.getJSONArray("layers") + + // Apply operations in order + operations@ for (operation in styleOperations.map { it.toNonNull() }) { + + // Reverse direction allows removing hidden layers + layers@ for (i in layerArray.length() - 1 downTo 0) { + + val layer = layerArray.getJSONObject(i) + if (layer.layerHasRequiredFields()) { + + if (operation.isValid() && layer.matchesOperation(operation)) { + Log.v(TAG, "applying ${Gson().toJson(operation)} to $layer") + + if (layer.layerShouldBeRemoved(operation)) { + Log.v(TAG, "removing $layer") + layerArray.remove(i) + } else { + layer.applyOperation(operation) + } + } + } + } + } + } + + + } catch (e: JsonSyntaxException) { + e.printStackTrace() + } +} + +data class StyleOperation(val featureType: String?, val elementType: String?, val stylers: Array?) + +data class NonNullStyleOperation(val featureType: String, val elementType: String, val stylers: Array) + +class Styler( + val hue: String?, + @FloatRange(from = -100.0, to = 100.0) val saturation: Float?, + @FloatRange(from = -100.0, to = 100.0) val lightness: Float?, + @FloatRange(from = 0.01, to = 10.0) val gamma: Float?, + @SerializedName("invert_lightness") val invertLightness: Boolean?, + val visibility: String?, + val color: String?, + val weight: Int? +) + +/** + * Constructs a `NonNullStyleOperation` out of the `StyleOperation` while filling null fields with + * default values. + */ +fun StyleOperation.toNonNull() = + NonNullStyleOperation(featureType ?: SELECTOR_ALL, elementType ?: SELECTOR_ALL, stylers ?: emptyArray()) + +/** + * Returns false iff the operation is invalid. + * + * There is one invalid selector that is tested for – per docs: + * "`administrative` selects all administrative areas. Styling affects only + * the labels of administrative areas, not the geographical borders or fill." + */ +fun NonNullStyleOperation.isValid() = !(featureType.startsWith("administrative") && + elementType.startsWith("geometry")) + +/** + * True iff the layer represented by the JSON object should be modified according to the stylers in the operation. + * + * Layer metadata always has the most concrete category, while operation applies to all subcategories as well. + * Therefore, we test if the operation is a substring of the layer's metadata – i.e. the layer's metadata contains + * (more concretely: starts with) the operation's selector. + */ +fun JSONObject.matchesOperation(operation: NonNullStyleOperation) = + (getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_FEATURE_TYPE).startsWith(operation.featureType) + || operation.featureType == "all") + && (getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_ELEMENT_TYPE).startsWith(operation.elementType) + || operation.elementType == "all") + + +/** + * Layer has fields that allow applying style operations. + */ +fun JSONObject.layerHasRequiredFields() = has(KEY_LAYER_PAINT) && has(KEY_LAYER_METADATA) && + getJSONObject(KEY_LAYER_METADATA).let { it.has(KEY_METADATA_FEATURE_TYPE) && it.has(KEY_METADATA_ELEMENT_TYPE) } + +/** + * True iff the layer represented by the JSON object should be removed according to the provided style operation. + * + * Interpretation of visibility "simplified": hide labels, display geometry. + */ +fun JSONObject.layerShouldBeRemoved(operation: NonNullStyleOperation) = + // A styler sets the layer to be invisible + operation.stylers.any { it.visibility == "off" } || + // A styler sets the layer to simplified and we are working with a label + (getJSONObject("metadata").getString(KEY_METADATA_ELEMENT_TYPE) + .startsWith("labels") && operation.stylers.any { it.visibility == "simplified" }) + +/** + * Applies the provided style operation to the layer represented by the JSON object. + */ +fun JSONObject.applyOperation(operation: NonNullStyleOperation) = operation.stylers.forEach { styler -> + when (operation.elementType) { + SELECTOR_ELEMENT_LABEL_TEXT_FILL -> styler.applyTextFill(getJSONObject(KEY_LAYER_PAINT)) + SELECTOR_ELEMENT_LABEL_TEXT_OUTLINE -> styler.applyTextOutline(getJSONObject(KEY_LAYER_PAINT)) + else -> styler.traverse(getJSONObject(KEY_LAYER_PAINT)) + } +} + +/** + * Returns true if string is likely to contain a color. + */ +fun String.isColor() = startsWith("hsl(") || startsWith("hsla(") || startsWith("#") || startsWith("rgba(") + +/** + * Can parse colors in the format '#rrggbb', '#aarrggbb', 'hsl(h, s, l)', and 'rgba(r, g, b, a)' + * Returns 0 and prints to log if an invalid color is provided. + */ +@ColorInt +fun String.parseColor(): Int { + if (startsWith("#") && length in listOf(7, 9)) { + return Color.parseColor(this) + } else if (startsWith("hsl(")) { + val hslArray = replace("hsl(", "").replace(")", "").split(", ") + if (hslArray.size != 3) { + Log.w(TAG, "Invalid color `$this`") + return 0 + } + + return try { + ColorUtils.HSLToColor( + floatArrayOf( + hslArray[0].toFloat(), + hslArray[1].parseFloat(), + hslArray[2].parseFloat() + ) + ) + } catch (e: NumberFormatException) { + Log.w(TAG, "Invalid color `$this`") + 0 + } + } else if (startsWith("hsla(")) { + val hslArray = replace("hsla(", "").replace(")", "").split(", ") + if (hslArray.size != 4) { + Log.w(TAG, "Invalid color `$this`") + return 0 + } + + return try { + ColorUtils.setAlphaComponent( + ColorUtils.HSLToColor( + floatArrayOf( + hslArray[0].toFloat(), hslArray[1].parseFloat(), hslArray[2].parseFloat() + ) + ), (hslArray[3].parseFloat() * 255).roundToInt() + ) + } catch (e: NumberFormatException) { + Log.w(TAG, "Invalid color `$this`") + 0 + } + + } else if (startsWith("rgba(")) { + return com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor(this) + } + + Log.w(TAG, "Invalid color `$this`") + return 0 +} + +/** + * Formats color int in such a format that it MapLibre's rendering engine understands it. + */ +fun Int.colorToString() = com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString(this) + +/** + * Can parse string values that contain '%'. + */ +fun String.parseFloat(): Float { + return if (contains("%")) { + replace("%", "").toFloat() / 100f + } else { + toFloat() + } +} + +/** + * Applies operation specified by styler to the provided color int, and returns + * a new, corresponding color int. + */ +@ColorInt +fun Styler.applyColorChanges(color: Int): Int { + // There may only be one operation per styler per docs. + + hue?.let { hue -> + // Extract hue from input color + val hslResult = FloatArray(3) + ColorUtils.colorToHSL(hue.parseColor(), hslResult) + + val hueDegree = hslResult[0] + + // Apply hue to layer color + ColorUtils.colorToHSL(color, hslResult) + hslResult[0] = hueDegree + return ColorUtils.HSLToColor(hslResult) + } + + lightness?.let { lightness -> + // Apply lightness to layer color + val hsl = FloatArray(3) + ColorUtils.colorToHSL(color, hsl) + hsl[2] = if (lightness < 0) { + // Increase darkness. Percentage amount = relative reduction of is-lightness. + (lightness / 100 + 1) * hsl[2] + } else { + // Increase brightness. Percentage amount = relative reduction of difference between is-lightness and 1.0. + hsl[2] + (lightness / 100) * (1 - hsl[2]) + } + return ColorUtils.HSLToColor(hsl) + } + + saturation?.let { saturation -> + // Apply saturation to layer color + val hsl = FloatArray(3) + ColorUtils.colorToHSL(color, hsl) + hsl[1] = if (saturation < 0) { + // Reduce intensity. Percentage amount = relative reduction of is-saturation. + (saturation / 100 + 1) * hsl[1] + } else { + // Increase intensity. Percentage amount = relative reduction of difference between is-saturation and 1.0. + hsl[1] + (saturation / 100) * (1 - hsl[1]) + } + + return ColorUtils.HSLToColor(hsl) + } + + gamma?.let { gamma -> + // Apply gamma to layer color + val hsl = FloatArray(3) + ColorUtils.colorToHSL(color, hsl) + hsl[2] = hsl[2].toDouble().pow(gamma.toDouble()).toFloat() + + return ColorUtils.HSLToColor(hsl) + } + + if (invertLightness == true) { + // Invert layer color's lightness + val hsl = FloatArray(3) + ColorUtils.colorToHSL(color, hsl) + hsl[2] = 1 - hsl[2] + + return ColorUtils.HSLToColor(hsl) + } + + this.color?.let { + return it.parseColor() + } + + Log.w(TAG, "No applicable operation") + return color +} + +/** + * Traverse JSON object and replace any color strings according to styler + */ +fun Styler.traverse(json: JSONObject) { + // Traverse layer and replace any color strings + json.keys().forEach { key -> + json.get(key).let { + when (it) { + is JSONObject -> traverse(it) + is JSONArray -> traverse(it) + is String -> if (it.isColor()) { + json.put(key, applyColorChanges(it.parseColor()).colorToString()) + } + } + } + } +} + +/** + * Traverse array and replace any color strings according to styler + */ +fun Styler.traverse(array: JSONArray) { + for (i in 0 until array.length()) { + array.get(i).let { + when (it) { + is JSONObject -> traverse(it) + is JSONArray -> traverse(it) + is String -> if (it.isColor()) { + array.put(i, applyColorChanges(it.parseColor()).colorToString()) + } + } + } + } +} + +fun Styler.applyTextFill(paint: JSONObject) { + if (paint.has("text-color")) when (val textColor = paint.get("text-color")) { + is JSONObject -> traverse(textColor) + is JSONArray -> traverse(textColor) + is String -> paint.put("text-color", applyColorChanges(textColor.parseColor()).colorToString()) + } +} + +fun Styler.applyTextOutline(paint: JSONObject) { + if (paint.has("text-halo-color")) when (val textOutline = paint.get("text-halo-color")) { + is JSONObject -> traverse(textOutline) + is JSONArray -> traverse(textOutline) + is String -> paint.put("text-halo-color", applyColorChanges(textOutline.parseColor()).colorToString()) + } +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt index 32320eb448c8bbf74631aa1da7b711794d96e72e..e6ab10cf5f847fc8529259e19da6cffa78391fe6 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt @@ -17,45 +17,22 @@ package org.microg.gms.maps.mapbox import android.os.Parcel -import android.os.RemoteException import android.util.Log import com.google.android.gms.maps.internal.IUiSettingsDelegate +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback import com.mapbox.mapboxsdk.maps.UiSettings -class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.Stub() { - +/** + * This class "implements" unimplemented methods to avoid duplication in subclasses + */ +abstract class AbstractUiSettings : IUiSettingsDelegate.Stub() { override fun setZoomControlsEnabled(zoom: Boolean) { Log.d(TAG, "unimplemented Method: setZoomControlsEnabled") } - override fun setCompassEnabled(compass: Boolean) { - uiSettings.isCompassEnabled = compass - } - override fun setMyLocationButtonEnabled(locationButton: Boolean) { Log.d(TAG, "unimplemented Method: setMyLocationButtonEnabled") - - } - - override fun setScrollGesturesEnabled(scrollGestures: Boolean) { - uiSettings.isScrollGesturesEnabled = scrollGestures - } - - override fun setZoomGesturesEnabled(zoomGestures: Boolean) { - uiSettings.isZoomGesturesEnabled = zoomGestures - } - - override fun setTiltGesturesEnabled(tiltGestures: Boolean) { - uiSettings.isTiltGesturesEnabled = tiltGestures - } - - override fun setRotateGesturesEnabled(rotateGestures: Boolean) { - uiSettings.isRotateGesturesEnabled = rotateGestures - } - - override fun setAllGesturesEnabled(gestures: Boolean) { - uiSettings.setAllGesturesEnabled(gestures) } override fun isZoomControlsEnabled(): Boolean { @@ -63,21 +40,11 @@ class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.S return false } - override fun isCompassEnabled(): Boolean = uiSettings.isCompassEnabled - override fun isMyLocationButtonEnabled(): Boolean { Log.d(TAG, "unimplemented Method: isMyLocationButtonEnabled") return false } - override fun isScrollGesturesEnabled(): Boolean = uiSettings.isScrollGesturesEnabled - - override fun isZoomGesturesEnabled(): Boolean = uiSettings.isZoomGesturesEnabled - - override fun isTiltGesturesEnabled(): Boolean = uiSettings.isTiltGesturesEnabled - - override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled - override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) { Log.d(TAG, "unimplemented Method: setIndoorLevelPickerEnabled") } @@ -105,6 +72,48 @@ class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.S return true } + companion object { + private val TAG = "GmsMapsUi" + } +} + +class UiSettingsImpl(private val uiSettings: UiSettings) : AbstractUiSettings() { + + + override fun setCompassEnabled(compass: Boolean) { + uiSettings.isCompassEnabled = compass + } + + override fun setScrollGesturesEnabled(scrollGestures: Boolean) { + uiSettings.isScrollGesturesEnabled = scrollGestures + } + + override fun setZoomGesturesEnabled(zoomGestures: Boolean) { + uiSettings.isZoomGesturesEnabled = zoomGestures + } + + override fun setTiltGesturesEnabled(tiltGestures: Boolean) { + uiSettings.isTiltGesturesEnabled = tiltGestures + } + + override fun setRotateGesturesEnabled(rotateGestures: Boolean) { + uiSettings.isRotateGesturesEnabled = rotateGestures + } + + override fun setAllGesturesEnabled(gestures: Boolean) { + uiSettings.setAllGesturesEnabled(gestures) + } + + override fun isCompassEnabled(): Boolean = uiSettings.isCompassEnabled + + override fun isScrollGesturesEnabled(): Boolean = uiSettings.isScrollGesturesEnabled + + override fun isZoomGesturesEnabled(): Boolean = uiSettings.isZoomGesturesEnabled + + override fun isTiltGesturesEnabled(): Boolean = uiSettings.isTiltGesturesEnabled + + override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = if (super.onTransact(code, data, reply, flags)) { true @@ -113,6 +122,80 @@ class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.S } companion object { - private val TAG = "GmsMapsUi" + private val TAG = "GmsMapsUiImpl" } } + +class UiSettingsCache : AbstractUiSettings() { + + private var compass: Boolean? = null + private var scrollGestures: Boolean? = null + private var zoomGestures: Boolean? = null + private var tiltGestures: Boolean? = null + private var rotateGestures: Boolean? = null + private var otherGestures: Boolean? = null + + override fun setCompassEnabled(compass: Boolean) { + this.compass = compass + } + + override fun setScrollGesturesEnabled(scrollGestures: Boolean) { + this.scrollGestures = scrollGestures + } + + override fun setZoomGesturesEnabled(zoomGestures: Boolean) { + this.zoomGestures = zoomGestures + } + + override fun setTiltGesturesEnabled(tiltGestures: Boolean) { + this.tiltGestures = tiltGestures + } + + override fun setRotateGesturesEnabled(rotateGestures: Boolean) { + this.rotateGestures = rotateGestures + } + + override fun setAllGesturesEnabled(gestures: Boolean) { + // Simulate MapLibre's UiSettings behavior + isScrollGesturesEnabled = gestures + isRotateGesturesEnabled = gestures + isTiltGesturesEnabled = gestures + isZoomGesturesEnabled = gestures + + // Other gestures toggles double tap and quick zoom gestures + otherGestures = gestures + } + + override fun isCompassEnabled(): Boolean { + return compass ?: true + } + + override fun isScrollGesturesEnabled(): Boolean { + return scrollGestures ?: true + } + + override fun isZoomGesturesEnabled(): Boolean { + return zoomGestures ?: true + } + + override fun isTiltGesturesEnabled(): Boolean { + return tiltGestures ?: true + } + + override fun isRotateGesturesEnabled(): Boolean { + return rotateGestures ?: true + } + + fun getMapReadyCallback(): OnMapReadyCallback = OnMapReadyCallback { map -> + val uiSettings = map.uiSettings + compass?.let { uiSettings.isCompassEnabled = it } + scrollGestures?.let { uiSettings.isScrollGesturesEnabled = it } + zoomGestures?.let { uiSettings.isZoomGesturesEnabled = it } + tiltGestures?.let { uiSettings.isTiltGesturesEnabled = it } + rotateGestures?.let { uiSettings.isRotateGesturesEnabled = it } + otherGestures?.let { + uiSettings.isDoubleTapGesturesEnabled = it + uiSettings.isQuickZoomGesturesEnabled = it + } + } +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt index e228387da70a2e38d2086471ddb710af52c20cad..48b16f7544eaf96a9f0e6a37cd2985256adc93d7 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt @@ -22,9 +22,11 @@ import android.util.Log import com.mapbox.mapboxsdk.plugins.annotation.Symbol import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions import com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_TOP_LEFT +import com.mapbox.mapboxsdk.style.layers.PropertyFactory +import com.mapbox.mapboxsdk.style.layers.SymbolLayer import com.mapbox.mapboxsdk.utils.ColorUtils -open class BitmapDescriptorImpl(private val id: String, private val size: FloatArray) { +open class BitmapDescriptorImpl(private val id: String, internal val size: FloatArray) { open fun applyTo(options: SymbolOptions, anchor: FloatArray, dpiFactor: Float): SymbolOptions { return options.withIconImage(id).withIconAnchor(ICON_ANCHOR_TOP_LEFT).withIconOffset(arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor)) } @@ -34,6 +36,14 @@ open class BitmapDescriptorImpl(private val id: String, private val size: FloatA symbol.iconOffset = PointF(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor) symbol.iconImage = id } + + open fun applyTo(symbolLayer: SymbolLayer, anchor: FloatArray, dpiFactor: Float) { + symbolLayer.withProperties( + PropertyFactory.iconAnchor(ICON_ANCHOR_TOP_LEFT), + PropertyFactory.iconOffset(arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor)), + PropertyFactory.iconImage(id) + ) + } } class ColorBitmapDescriptorImpl(id: String, size: FloatArray, val hue: Float) : BitmapDescriptorImpl(id, size) { diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt index f4f517481463caad7390d7fc44c394f7d9cdb6c1..465230041d49d713532d22b49db1546108d5e94a 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt @@ -18,14 +18,13 @@ package org.microg.gms.maps.mapbox.model import android.content.res.Resources import android.graphics.* -import android.os.Handler -import android.os.Looper import android.os.Parcel import android.util.Log import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.ObjectWrapper import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Style import org.microg.gms.maps.mapbox.R import org.microg.gms.maps.mapbox.runOnMainLooper @@ -57,6 +56,14 @@ object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() { // TODO: cleanup bitmaps? } + fun put(style: Style.Builder) { + synchronized(bitmaps) { + for (bitmap in bitmaps) { + style.withImage(bitmap.key, bitmap.value) + } + } + } + fun bitmapSize(id: String): FloatArray = bitmaps[id]?.let { floatArrayOf(it.width.toFloat(), it.height.toFloat()) } ?: floatArrayOf(0f, 0f) diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt index aa016ea8005c4b92a936a52836c67f60d7352c1f..93f3c1d32a8d62e257de8be1794066dc57a15e78 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt @@ -18,78 +18,172 @@ package org.microg.gms.maps.mapbox.model import android.os.Parcel import android.util.Log +import com.google.android.gms.dynamic.IObjectWrapper +import com.google.android.gms.dynamic.ObjectWrapper +import com.google.android.gms.dynamic.unwrap +import com.google.android.gms.maps.model.Dash import com.google.android.gms.maps.model.LatLng +import com.google.android.gms.maps.model.PatternItem import com.google.android.gms.maps.model.internal.ICircleDelegate -import com.mapbox.mapboxsdk.plugins.annotation.Circle -import com.mapbox.mapboxsdk.plugins.annotation.CircleOptions +import com.mapbox.geojson.LineString +import com.mapbox.geojson.Point +import com.mapbox.mapboxsdk.plugins.annotation.* import com.mapbox.mapboxsdk.utils.ColorUtils +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfConstants.UNIT_METERS +import com.mapbox.turf.TurfMeasurement +import com.mapbox.turf.TurfMeta +import com.mapbox.turf.TurfTransformation import org.microg.gms.maps.mapbox.GoogleMapImpl -import org.microg.gms.maps.mapbox.utils.toMapbox +import org.microg.gms.maps.mapbox.LiteGoogleMapImpl +import org.microg.gms.maps.mapbox.utils.toPoint +import org.microg.gms.maps.mapbox.getName +import org.microg.gms.maps.mapbox.makeBitmap import com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions -class CircleImpl(private val map: GoogleMapImpl, private val id: String, options: GmsCircleOptions) : ICircleDelegate.Stub(), Markup { - private var center: LatLng = options.center - private var radius: Double = options.radius - private var strokeWidth: Float = options.strokeWidth - private var strokeColor: Int = options.strokeColor - private var fillColor: Int = options.fillColor - private var visible: Boolean = options.isVisible +val NORTH_POLE: Point = Point.fromLngLat(0.0, 90.0) +val SOUTH_POLE: Point = Point.fromLngLat(0.0, -90.0) - override var annotation: Circle? = null - override var removed: Boolean = false - override val annotationOptions: CircleOptions - get() = CircleOptions() - .withLatLng(center.toMapbox()) - .withCircleColor(ColorUtils.colorToRgbaString(fillColor)) - .withCircleRadius(radius.toFloat()) - .withCircleStrokeColor(ColorUtils.colorToRgbaString(strokeColor)) - .withCircleStrokeWidth(strokeWidth / map.dpiFactor) - .withCircleOpacity(if (visible) 1f else 0f) - .withCircleStrokeOpacity(if (visible) 1f else 0f) +/** + * Amount of points to be used in the polygon that approximates the circle. + */ +const val CIRCLE_POLYGON_STEPS = 256 - override fun remove() { - removed = true - map.circleManager?.let { update(it) } +abstract class AbstractCircle( + private val id: String, options: GmsCircleOptions, private val dpiFactor: Function0 +) : ICircleDelegate.Stub() { + + internal var center: LatLng = options.center + internal var radiusInMeters: Double = options.radius // unlike MapLibre's circles, which only work with pixel radii + internal var strokeWidth: Float = options.strokeWidth + internal var strokeColor: Int = options.strokeColor + internal var fillColor: Int = options.fillColor + internal var visible: Boolean = options.isVisible + internal var clickable: Boolean = options.isClickable + internal var strokePattern: MutableList? = options.strokePattern + internal var tag: Any? = null + + internal val line: Markup = object : Markup { + override var annotation: Line? = null + override val annotationOptions: LineOptions + get() = LineOptions() + .withGeometry( + LineString.fromLngLats( + makeOutlineLatLngs() + ) + ).withLineWidth(strokeWidth / dpiFactor()) + .withLineColor(ColorUtils.colorToRgbaString(strokeColor)) + .withLineOpacity(if (visible) 1f else 0f) + .apply { + strokePattern?.let { + withLinePattern(it.getName(strokeColor, strokeWidth)) + } + } + + override var removed: Boolean = false + } + + val annotationOptions: FillOptions + get() = + FillOptions() + .withGeometry(makePolygon()) + .withFillColor(ColorUtils.colorToRgbaString(fillColor)) + .withFillOpacity(if (visible && !wrapsAroundPoles()) 1f else 0f) + + internal abstract fun update() + + internal fun makePolygon() = TurfTransformation.circle( + Point.fromLngLat(center.longitude, center.latitude), radiusInMeters, CIRCLE_POLYGON_STEPS, TurfConstants.UNIT_METERS + ) + + /** + * Google's "map renderer is unable to draw the circle fill if the circle encompasses + * either the North or South pole" (though it does so incorrectly anyway) + */ + internal fun wrapsAroundPoles() = center.toPoint().let { + TurfMeasurement.distance( + it, NORTH_POLE, UNIT_METERS + ) < radiusInMeters || TurfMeasurement.distance( + it, SOUTH_POLE, UNIT_METERS + ) < radiusInMeters + } + + internal fun makeOutlineLatLngs(): MutableList { + val pointList = TurfMeta.coordAll( + makePolygon(), wrapsAroundPoles() + ) + // Circles around the poles are tricky to draw (https://github.com/mapbox/mapbox-gl-js/issues/11235). + // We modify our lines such to match the way Mapbox / MapLibre draws them. + // This results in a small gap somewhere in the line, but avoids an incorrect horizontal line. + + val centerPoint = center.toPoint() + + if (!centerPoint.equals(NORTH_POLE) && TurfMeasurement.distance(centerPoint, NORTH_POLE, UNIT_METERS) < radiusInMeters) { + // Wraps around North Pole + for (i in 0 until pointList.size) { + // We want to have the north-most points at the start and end + if (pointList[0].latitude() > pointList[1].latitude() && pointList[pointList.size - 1].latitude() > pointList[pointList.size - 2].latitude()) { + return pointList + } else { + // Cycle point list + val zero = pointList.removeFirst() + pointList.add(zero) + } + } + } + + if (!centerPoint.equals(SOUTH_POLE) && TurfMeasurement.distance(centerPoint, SOUTH_POLE, UNIT_METERS) < radiusInMeters) { + // Wraps around South Pole + for (i in 0 until pointList.size) { + // We want to have the south-most points at the start and end + if (pointList[0].latitude() < pointList[1].latitude() && pointList[pointList.size - 1].latitude() < pointList[pointList.size - 2].latitude()) { + return pointList + } else { + // Cycle point list + val last = pointList.removeAt(pointList.size - 1) + pointList.add(0, last) + } + } + } + + // In this case no changes were made + return pointList } override fun getId(): String = id override fun setCenter(center: LatLng) { this.center = center - annotation?.latLng = center.toMapbox() - map.circleManager?.let { update(it) } + update() + } override fun getCenter(): LatLng = center override fun setRadius(radius: Double) { - this.radius = radius - annotation?.circleRadius = radius.toFloat() - map.circleManager?.let { update(it) } + this.radiusInMeters = radius + update() } - override fun getRadius(): Double = radius + override fun getRadius(): Double = radiusInMeters override fun setStrokeWidth(width: Float) { this.strokeWidth = width - annotation?.circleStrokeWidth = width / map.dpiFactor - map.circleManager?.let { update(it) } + update() } override fun getStrokeWidth(): Float = strokeWidth override fun setStrokeColor(color: Int) { this.strokeColor = color - annotation?.setCircleStrokeColor(color) - map.circleManager?.let { update(it) } + update() } override fun getStrokeColor(): Int = strokeColor override fun setFillColor(color: Int) { this.fillColor = color - annotation?.setCircleColor(color) - map.circleManager?.let { update(it) } + update() } override fun getFillColor(): Int = fillColor @@ -105,9 +199,7 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun setVisible(visible: Boolean) { this.visible = visible - annotation?.circleOpacity = if (visible) 1f else 0f - annotation?.circleStrokeOpacity = if (visible) 1f else 0f - map.circleManager?.let { update(it) } + update() } override fun isVisible(): Boolean = visible @@ -116,6 +208,30 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun hashCodeRemote(): Int = hashCode() + override fun setClickable(clickable: Boolean) { + this.clickable = clickable + } + + override fun isClickable(): Boolean { + return clickable + } + + override fun setStrokePattern(pattern: MutableList?) { + this.strokePattern = pattern + update() + } + + + override fun getStrokePattern(): MutableList? { + return strokePattern + } + + override fun setTag(o: IObjectWrapper) { + this.tag = o.unwrap() + } + + override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(tag) + override fun hashCode(): Int { return id.hashCode() } @@ -132,13 +248,92 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options } override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = - if (super.onTransact(code, data, reply, flags)) { - true - } else { - Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false + if (super.onTransact(code, data, reply, flags)) { + true + } else { + Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false + } + + companion object { + val TAG = "GmsMapAbstractCircle" + } +} + +class CircleImpl(private val map: GoogleMapImpl, private val id: String, options: GmsCircleOptions) : + AbstractCircle(id, options, { map.dpiFactor }), Markup { + + override var annotation: Fill? = null + override var removed: Boolean = false + + override fun update() { + val polygon = makePolygon() + + // Extracts points from generated polygon in expected format + annotation?.let { + it.latLngs = FillOptions().withGeometry(polygon).latLngs + it.setFillColor(fillColor) + it.fillOpacity = if (visible && !wrapsAroundPoles()) 1f else 0f + } + + line.annotation?.let { + it.latLngs = makeOutlineLatLngs().map { point -> + com.mapbox.mapboxsdk.geometry.LatLng( + point.latitude(), + point.longitude() + ) + } + + it.lineWidth = strokeWidth / map.dpiFactor + + (strokePattern ?: listOf(Dash(1f))).let { pattern -> + val bitmapName = pattern.getName(strokeColor, strokeWidth) + map.addBitmap(bitmapName, pattern.makeBitmap(strokeColor, strokeWidth)) + line.annotation?.linePattern = bitmapName + } + map.lineManager?.let { line.update(it) } + + it.setLineColor(strokeColor) + } + + map.fillManager?.let { update(it) } + map.lineManager?.let { line.update(it) } + } + + override fun remove() { + removed = true + line.removed = true + map.fillManager?.let { update(it) } + map.lineManager?.let { line.update(it) } + } + + + override fun update(manager: AnnotationManager<*, Fill, FillOptions, *, *, *>) { + synchronized(this) { + val id = annotation?.id + if (removed && id != null) { + map.circles.remove(id) + } + super.update(manager) + val annotation = annotation + if (annotation != null && id == null) { + map.circles[annotation.id] = this } + } + } companion object { val TAG = "GmsMapCircle" } +} + +class LiteCircleImpl(private val map: LiteGoogleMapImpl, id: String, options: GmsCircleOptions) : + AbstractCircle(id, options, { map.dpiFactor }) { + override fun update() { + map.postUpdateSnapshot() + } + + override fun remove() { + map.circles.remove(this) + } + } \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/InfoWindow.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/InfoWindow.kt new file mode 100644 index 0000000000000000000000000000000000000000..91b41f117a1b334692820949cf1da72275fcb07f --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/InfoWindow.kt @@ -0,0 +1,164 @@ +package org.microg.gms.maps.mapbox.model + +import android.graphics.Point +import android.graphics.PointF +import android.view.LayoutInflater +import android.view.View +import android.view.View.VISIBLE +import android.view.ViewGroup +import android.view.ViewManager +import android.widget.FrameLayout +import android.widget.TextView +import com.google.android.gms.dynamic.ObjectWrapper +import com.google.android.gms.dynamic.unwrap +import com.google.android.gms.maps.internal.IInfoWindowAdapter +import com.google.android.gms.maps.model.internal.IMarkerDelegate +import com.mapbox.android.gestures.Utils +import org.microg.gms.maps.mapbox.AbstractGoogleMap +import org.microg.gms.maps.mapbox.GoogleMapImpl +import org.microg.gms.maps.mapbox.R +import org.microg.gms.maps.mapbox.utils.MapContext +import org.microg.gms.maps.mapbox.utils.toMapbox +import kotlin.math.* + +/** + * `InfoWindow` is a tooltip shown when a [MarkerImpl] is tapped. Only + * one info window is displayed at a time. When the user clicks on a marker, the currently open info + * window will be closed and the new info window will be displayed. If the user clicks the same + * marker while its info window is currently open, the info window will be reopened. + * + * The info window is drawn oriented against the device's screen, centered above its associated + * marker, unless a different info window anchor is set. The default info window contains the title + * in bold and snippet text below the title. + * If neither is set, no default info window is shown. + * + * Based on Mapbox's / MapLibre's [com.mapbox.mapboxsdk.annotations.InfoWindow]. + * + */ + +fun IInfoWindowAdapter.getInfoWindowViewFor(marker: IMarkerDelegate, mapContext: MapContext): View? { + getInfoWindow(marker).unwrap()?.let { return it } + + getInfoContents(marker).unwrap()?.let { view -> + // Detach from previous BubbleLayout parent, if exists + view.parent?.let { (it as ViewManager).removeView(view) } + + return FrameLayout(view.context).apply { + background = mapContext.getDrawable(R.drawable.maps_default_bubble) + val fourDp = Utils.dpToPx(4f) + elevation = fourDp + setPadding(fourDp.toInt(), fourDp.toInt(), fourDp.toInt(), fourDp.toInt() * 3) + addView(view) + } + } + + // When a custom adapter is used, but both methods return null, the default adapter must be used + if (this !is DefaultInfoWindowAdapter) { + return DefaultInfoWindowAdapter(mapContext).getInfoWindowViewFor(marker, mapContext) + } + + return null +} + +class InfoWindow internal constructor( + private val view: View, private val map: AbstractGoogleMap, internal val marker: AbstractMarker +) { + private var coordinates: PointF = PointF(0f, 0f) + var isVisible = false + + init { + view.setOnClickListener { + map.onInfoWindowClickListener?.onInfoWindowClick(marker) + } + view.setOnLongClickListener { + map.onInfoWindowLongClickListener?.onInfoWindowLongClick(marker) + true + } + } + + fun open(mapView: FrameLayout) { + val layoutParams: FrameLayout.LayoutParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT + ) + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) + + close(true) // if it was already opened + mapView.addView(view, layoutParams) + isVisible = true + + // Set correct position + update() + } + + /** + * Close this [InfoWindow] if it is visible, otherwise calling this will do nothing. + * + * @param silent `OnInfoWindowCloseListener` is only called if `silent` is not `false` + */ + fun close(silent: Boolean = false) { + if (isVisible) { + isVisible = false + (view.parent as ViewGroup?)?.removeView(view) + if (!silent) { + map.onInfoWindowCloseListener?.onInfoWindowClose(marker) + } + } + } + + /** + * Updates the position of the displayed view. + */ + fun update() { + + if (map is GoogleMapImpl) { + map.map?.projection?.toScreenLocation(marker.position.toMapbox())?.let { + coordinates = it + } + } else { + map.projection.toScreenLocation(marker.position)?.let { + coordinates = PointF(it.unwrap()!!) + } + } + + val iconDimensions = marker.getIconDimensions() + val width = iconDimensions?.get(0) ?: 0f + val height = iconDimensions?.get(1) ?: 0f + + view.x = + coordinates.x - view.measuredWidth / 2f + sin(Math.toRadians(marker.rotation.toDouble())).toFloat() * width * marker.infoWindowAnchor[0] + view.y = coordinates.y - view.measuredHeight - max( + height * cos(Math.toRadians(marker.rotation.toDouble())).toFloat() * marker.infoWindowAnchor[1], 0f + ) + } +} + +class DefaultInfoWindowAdapter(val context: MapContext) : IInfoWindowAdapter { + override fun asBinder() = null + + override fun getInfoWindow(marker: IMarkerDelegate?): ObjectWrapper { + + if (marker == null) return ObjectWrapper.wrap(null) + + val showDefaultMarker = (marker.title != null) || (marker.snippet != null) + + return if (!showDefaultMarker) ObjectWrapper.wrap(null) + else ObjectWrapper.wrap( + LayoutInflater.from(context).inflate(R.layout.maps_default_bubble_layout, null, false).apply { + + marker.title?.let { + val titleTextView = findViewById(R.id.title) + titleTextView.text = it + titleTextView.visibility = VISIBLE + } + + marker.snippet?.let { + val snippetTextView = findViewById(R.id.snippet) + snippetTextView.text = it + snippetTextView.visibility = VISIBLE + } + } + ) + } + + override fun getInfoContents(marker: IMarkerDelegate?) = null +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt index 06da3657806e7f903c2ce9150c058a2a5d2c5c90..a1423b6cae6791c9d5c9901e178f49c6a3fe5abd 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt @@ -27,44 +27,167 @@ import com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager import com.mapbox.mapboxsdk.plugins.annotation.Symbol import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions import com.google.android.gms.dynamic.unwrap +import org.microg.gms.maps.mapbox.AbstractGoogleMap import org.microg.gms.maps.mapbox.GoogleMapImpl +import org.microg.gms.maps.mapbox.LiteGoogleMapImpl import org.microg.gms.maps.mapbox.utils.toMapbox -class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options: MarkerOptions) : IMarkerDelegate.Stub(), Markup { - private var position: LatLng = options.position - private var visible: Boolean = options.isVisible - private var rotation: Float = options.rotation - private var anchor: FloatArray = floatArrayOf(options.anchorU, options.anchorV) - private var icon: BitmapDescriptorImpl? = options.icon?.remoteObject.unwrap() - private var alpha: Float = options.alpha - private var title: String? = options.title - private var snippet: String? = options.snippet - private var zIndex: Float = options.zIndex - private var draggable: Boolean = options.isDraggable - private var tag: IObjectWrapper? = null - - private var infoWindowShown = false - - override var annotation: Symbol? = null - override var removed: Boolean = false - override val annotationOptions: SymbolOptions +abstract class AbstractMarker( + private val id: String, options: MarkerOptions, private val map: AbstractGoogleMap +) : IMarkerDelegate.Stub() { + + internal var position: LatLng = options.position + internal var visible: Boolean = options.isVisible + internal var anchor: FloatArray = floatArrayOf(options.anchorU, options.anchorV) + internal var infoWindowAnchor: FloatArray = floatArrayOf(0.5f, 1f) + internal var icon: BitmapDescriptorImpl? = options.icon?.remoteObject.unwrap() + internal var alpha: Float = options.alpha + internal var title: String? = options.title + internal var snippet: String? = options.snippet + internal var zIndex: Float = options.zIndex + internal var tag: IObjectWrapper? = null + internal open var draggable = false + + val annotationOptions: SymbolOptions get() { val symbolOptions = SymbolOptions() - .withIconOpacity(if (visible) alpha else 0f) - .withIconRotate(rotation) - .withSymbolSortKey(zIndex) - .withDraggable(draggable) + .withIconOpacity(if (visible) alpha else 0f) + .withIconRotate(rotation) + .withSymbolSortKey(zIndex) + .withDraggable(draggable) position.let { symbolOptions.withLatLng(it.toMapbox()) } icon?.applyTo(symbolOptions, anchor, map.dpiFactor) return symbolOptions } + internal abstract fun update() + + override fun getId(): String = id + + override fun setPosition(position: LatLng?) { + this.position = position ?: return + update() + } + + override fun getPosition(): LatLng = position + + override fun setIcon(obj: IObjectWrapper?) { + obj.unwrap()?.let { icon -> + this.icon = icon + update() + } + } + + override fun setVisible(visible: Boolean) { + this.visible = visible + update() + } + + override fun setTitle(title: String?) { + this.title = title + update() + } + + override fun getTitle(): String? = title + + override fun getSnippet(): String? = snippet + + override fun isVisible(): Boolean = visible + + override fun setAnchor(x: Float, y: Float) { + anchor = floatArrayOf(x, y) + update() + } + + override fun setAlpha(alpha: Float) { + this.alpha = alpha + update() + } + + override fun getAlpha(): Float = alpha + + override fun setZIndex(zIndex: Float) { + this.zIndex = zIndex + update() + } + + override fun getZIndex(): Float = zIndex + + fun getIconDimensions(): FloatArray? { + return icon?.size + } + + override fun showInfoWindow() { + if (isInfoWindowShown) { + // Per docs, don't call `onWindowClose` if info window is re-opened programmatically + map.currentInfoWindow?.close(silent = true) + } + map.showInfoWindow(this) + } + + override fun hideInfoWindow() { + if (isInfoWindowShown) { + map.currentInfoWindow?.close() + map.currentInfoWindow = null + } + } + + override fun isInfoWindowShown(): Boolean { + return map.currentInfoWindow?.marker == this + } + + override fun setTag(obj: IObjectWrapper?) { + this.tag = obj + } + + override fun getTag(): IObjectWrapper? = tag ?: ObjectWrapper.wrap(null) + + override fun setSnippet(snippet: String?) { + this.snippet = snippet + } + + override fun equalsRemote(other: IMarkerDelegate?): Boolean = equals(other) + + override fun hashCodeRemote(): Int = hashCode() + + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = + if (super.onTransact(code, data, reply, flags)) { + true + } else { + Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false + } + + companion object { + private val TAG = "GmsMapAbstractMarker" + } +} + +class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options: MarkerOptions) : + AbstractMarker(id, options, map), Markup { + + internal var rotation: Float = options.rotation + override var draggable: Boolean = options.isDraggable + + override var annotation: Symbol? = null + override var removed: Boolean = false + override fun remove() { removed = true map.symbolManager?.let { update(it) } } + override fun update() { + annotation?.let { + it.latLng = position.toMapbox() + it.isDraggable = draggable + it.iconOpacity = if (visible) alpha else 0f + it.symbolSortKey = zIndex + icon?.applyTo(it, anchor, map.dpiFactor) + } + map.symbolManager?.let { update(it) } + } + override fun update(manager: AnnotationManager<*, Symbol, SymbolOptions, *, *, *>) { synchronized(this) { val id = annotation?.id @@ -79,67 +202,47 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options } } - override fun getId(): String = id - override fun setPosition(position: LatLng?) { - this.position = position ?: return - annotation?.latLng = position.toMapbox() - map.symbolManager?.let { update(it) } + super.setPosition(position) + map.currentInfoWindow?.update() } - override fun getPosition(): LatLng = position + /** + * New position is already reflected on map while if drag is in progress. Calling + * `symbolManager.update` would interrupt the drag. + */ + internal fun setPositionWhileDragging(position: LatLng) { + this.position = position + map.currentInfoWindow?.update() + } override fun setTitle(title: String?) { - this.title = title + super.setTitle(title) + map.currentInfoWindow?.let { + if (it.marker == this) it.close() + } } - override fun getTitle(): String? = title - override fun setSnippet(snippet: String?) { - this.snippet = snippet + super.setSnippet(snippet) + map.currentInfoWindow?.let { + if (it.marker == this) it.close() + } } - override fun getSnippet(): String? = snippet - override fun setDraggable(draggable: Boolean) { this.draggable = draggable - annotation?.isDraggable = draggable map.symbolManager?.let { update(it) } } override fun isDraggable(): Boolean = draggable - override fun showInfoWindow() { - Log.d(TAG, "unimplemented Method: showInfoWindow") - infoWindowShown = true - } - - override fun hideInfoWindow() { - Log.d(TAG, "unimplemented Method: hideInfoWindow") - infoWindowShown = false - } - - override fun isInfoWindowShown(): Boolean { - Log.d(TAG, "unimplemented Method: isInfoWindowShow") - return infoWindowShown - } - - override fun setVisible(visible: Boolean) { - this.visible = visible - annotation?.iconOpacity = if (visible) alpha else 0f - map.symbolManager?.let { update(it) } - } - - override fun isVisible(): Boolean = visible - override fun equals(other: Any?): Boolean { if (this === other) return true if (other is IMarkerDelegate) return other.id == id return false } - override fun equalsRemote(other: IMarkerDelegate?): Boolean = equals(other) - override fun hashCode(): Int { return id.hashCode() } @@ -148,20 +251,9 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options return "$id ($title)" } - override fun hashCodeRemote(): Int = hashCode() - - override fun setIcon(obj: IObjectWrapper?) { - obj.unwrap()?.let { icon -> - this.icon = icon - annotation?.let { icon.applyTo(it, anchor, map.dpiFactor) } - } - map.symbolManager?.let { update(it) } - } - override fun setAnchor(x: Float, y: Float) { - anchor = floatArrayOf(x, y) - annotation?.let { icon?.applyTo(it, anchor, map.dpiFactor) } - map.symbolManager?.let { update(it) } + super.setAnchor(x, y) + map.currentInfoWindow?.update() } override fun setFlat(flat: Boolean) { @@ -177,44 +269,65 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options this.rotation = rotation annotation?.iconRotate = rotation map.symbolManager?.let { update(it) } + map.currentInfoWindow?.update() } override fun getRotation(): Float = rotation override fun setInfoWindowAnchor(x: Float, y: Float) { - Log.d(TAG, "unimplemented Method: setInfoWindowAnchor") + infoWindowAnchor = floatArrayOf(x, y) + map.currentInfoWindow?.update() } - override fun setAlpha(alpha: Float) { - this.alpha = alpha - annotation?.iconOpacity = if (visible) alpha else 0f - map.symbolManager?.let { update(it) } + companion object { + private val TAG = "GmsMapMarker" } +} - override fun getAlpha(): Float = alpha +class LiteMarkerImpl(id: String, options: MarkerOptions, private val map: LiteGoogleMapImpl) : + AbstractMarker(id, options, map) { + override fun remove() { + map.markers.remove(this) + map.postUpdateSnapshot() + } - override fun setZIndex(zIndex: Float) { - this.zIndex = zIndex - annotation?.symbolSortKey = zIndex - map.symbolManager?.let { update(it) } + override fun update() { + map.postUpdateSnapshot() } - override fun getZIndex(): Float = zIndex + override fun setDraggable(drag: Boolean) { + Log.d(TAG, "setDraggable: not available in lite mode") + } - override fun setTag(obj: IObjectWrapper?) { - this.tag = obj + override fun isDraggable(): Boolean { + Log.d(TAG, "isDraggable: markers are never draggable in lite mode") + return false } - override fun getTag(): IObjectWrapper = tag ?: ObjectWrapper.wrap(null) + override fun setFlat(flat: Boolean) { + Log.d(TAG, "setFlat: not available in lite mode") + } - override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = - if (super.onTransact(code, data, reply, flags)) { - true - } else { - Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false - } + override fun isFlat(): Boolean { + Log.d(TAG, "isFlat: markers in lite mode can never be flat") + return false + } + + override fun setRotation(rotation: Float) { + Log.d(TAG, "setRotation: not available in lite mode") + } + + override fun getRotation(): Float { + Log.d(TAG, "setRotation: markers in lite mode can never be rotated") + return 0f + } + + override fun setInfoWindowAnchor(x: Float, y: Float) { + infoWindowAnchor = floatArrayOf(x, y) + map.currentInfoWindow?.update() + } companion object { - private val TAG = "GmsMapMarker" + private val TAG = "GmsMapMarkerLite" } -} +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt index c737afccd4af5be9ddaf052d55386d300ddc6eb1..179c5a0b07e2b228b79f2f938c05bb3c4c02bd81 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt @@ -24,7 +24,7 @@ import com.mapbox.mapboxsdk.plugins.annotation.Options interface Markup, S : Options> { var annotation: T? val annotationOptions: S - val removed: Boolean + var removed: Boolean fun update(manager: AnnotationManager<*, T, S, *, *, *>) { synchronized(this) { diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt index 2c10af4a70dd638d77a9ee5c15f2d8ca5b28acc6..cfa95f629657bf161906bbb0e4630d24306928b7 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt @@ -7,6 +7,7 @@ package org.microg.gms.maps.mapbox.model import android.os.Parcel import android.util.Log +import androidx.annotation.CallSuper import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.ObjectWrapper import com.google.android.gms.maps.model.LatLng @@ -14,62 +15,55 @@ import com.google.android.gms.maps.model.PatternItem import com.google.android.gms.maps.model.PolygonOptions import com.google.android.gms.maps.model.PolylineOptions import com.google.android.gms.maps.model.internal.IPolygonDelegate -import com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager import com.mapbox.mapboxsdk.plugins.annotation.Fill import com.mapbox.mapboxsdk.plugins.annotation.FillOptions import com.mapbox.mapboxsdk.utils.ColorUtils import org.microg.gms.maps.mapbox.GoogleMapImpl +import org.microg.gms.maps.mapbox.LiteGoogleMapImpl import org.microg.gms.maps.mapbox.utils.toMapbox import org.microg.gms.utils.warnOnTransactionIssues -class PolygonImpl(private val map: GoogleMapImpl, private val id: String, options: PolygonOptions) : IPolygonDelegate.Stub(), Markup { - private var points = ArrayList(options.points.orEmpty()) - private var holes: List> = ArrayList(options.holes.map { ArrayList(it.orEmpty()) }) - private var fillColor = options.fillColor - private var strokeColor = options.strokeColor - private var strokeWidth = options.strokeWidth - private var strokeJointType = options.strokeJointType - private var strokePattern = ArrayList(options.strokePattern.orEmpty()) - private var visible: Boolean = options.isVisible - private var clickable: Boolean = options.isClickable - private var tag: IObjectWrapper? = null - - private var strokes = (listOf(PolylineImpl(map, "$id-stroke-main", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(points))) - + holes.mapIndexed { idx, it -> PolylineImpl(map, "$id-stroke-hole-$idx", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(it)) }).toMutableList() - - override var annotation: Fill? = null - override var removed: Boolean = false - override val annotationOptions: FillOptions +abstract class AbstractPolygon(private val id: String, options: PolygonOptions) : IPolygonDelegate.Stub() { + internal var points = ArrayList(options.points.orEmpty()) + internal var holes: List> = ArrayList(options.holes.map { ArrayList(it.orEmpty()) }) + internal var fillColor = options.fillColor + internal var strokeColor = options.strokeColor + internal var strokeWidth = options.strokeWidth + internal var strokeJointType = options.strokeJointType + internal var strokePattern = ArrayList(options.strokePattern.orEmpty()) + internal var visible: Boolean = options.isVisible + internal var clickable: Boolean = options.isClickable + internal var tag: IObjectWrapper? = null + + val annotationOptions: FillOptions get() = FillOptions() - .withLatLngs(mutableListOf(points.map { it.toMapbox() }).plus(holes.map { it.map { it.toMapbox() } })) - .withFillColor(ColorUtils.colorToRgbaString(fillColor)) - .withFillOpacity(if (visible) 1f else 0f) + .withLatLngs(mutableListOf(points.map { it.toMapbox() }).plus(holes.map { it.map { it.toMapbox() } })) + .withFillColor(ColorUtils.colorToRgbaString(fillColor)) + .withFillOpacity(if (visible) 1f else 0f) - override fun remove() { - removed = true - map.fillManager?.let { update(it) } - strokes.forEach { it.remove() } - } + internal abstract val strokes: MutableList + + internal abstract fun update() - override fun update(manager: AnnotationManager<*, Fill, FillOptions, *, *, *>) { - super.update(manager) - map.lineManager?.let { lineManager -> strokes.forEach { it.update(lineManager) } } + @CallSuper + override fun remove() { + for (stroke in strokes) stroke.remove() } override fun getId(): String = id override fun setPoints(points: List) { this.points = ArrayList(points) - annotation?.latLngs = mutableListOf(points.map { it.toMapbox() }).plus(holes.map { it.map { it.toMapbox() } }) - map.fillManager?.let { update(it) } - strokes[0].points = points + strokes[0].setPoints(points) + update() } override fun getPoints(): List = points + internal abstract fun addPolyline(id: String, options: PolylineOptions) + override fun setHoles(holes: List?) { this.holes = if (holes == null) emptyList() else ArrayList(holes.mapNotNull { if (it is List<*>) it.mapNotNull { if (it is LatLng) it else null }.let { if (it.isNotEmpty()) it else null } else null }) - annotation?.latLngs = mutableListOf(points.map { it.toMapbox() }).plus(this.holes.map { it.map { it.toMapbox() } }) while (strokes.size > this.holes.size + 1) { val last = strokes.last() last.remove() @@ -78,34 +72,40 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option strokes.forEachIndexed { idx, it -> if (idx > 0) it.points = this.holes[idx - 1] } if (this.holes.size + 1 > strokes.size) { try { - strokes.addAll(this.holes.subList(strokes.size, this.holes.size - 1).mapIndexed { idx, it -> PolylineImpl(map, "$id-stroke-hole-${strokes.size + idx}", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(it)) }) + this.holes.subList(strokes.size, this.holes.size - 1).mapIndexed { idx, it -> + addPolyline( + "$id-stroke-hole-${strokes.size + idx}", + PolylineOptions().color(strokeColor).width(strokeWidth).addAll(it) + ) + } } catch (e: Exception) { Log.w(TAG, e) } } - map.fillManager?.let { update(it) } } - override fun getHoles(): List = holes + override fun getHoles(): List> = holes + override fun setStrokeWidth(width: Float) { - this.strokeWidth = width - strokes.forEach { it.width = width } + strokeWidth = width + strokes.forEach { it.setWidth(width) } + update() } override fun getStrokeWidth(): Float = strokeWidth override fun setStrokeColor(color: Int) { - this.strokeColor = color - strokes.forEach { it.color = color } + strokeColor = color + strokes.forEach { it.setColor(color) } + update() } override fun getStrokeColor(): Int = strokeColor override fun setFillColor(color: Int) { - this.fillColor = color - annotation?.setFillColor(color) - map.fillManager?.let { update(it) } + fillColor = color + update() } override fun getFillColor(): Int = fillColor @@ -120,9 +120,8 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option } override fun setVisible(visible: Boolean) { - this.visible = visible - annotation?.fillOpacity = if (visible) 1f else 0f - map.fillManager?.let { update(it) } + isVisible = visible + update() } override fun isVisible(): Boolean = visible @@ -136,10 +135,6 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option return false } - override fun equalsRemote(other: IPolygonDelegate?): Boolean = equals(other) - - override fun hashCodeRemote(): Int = hashCode() - override fun setClickable(click: Boolean) { clickable = click } @@ -148,12 +143,14 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option override fun setStrokeJointType(type: Int) { strokeJointType = type + update() } override fun getStrokeJointType(): Int = strokeJointType override fun setStrokePattern(items: MutableList?) { strokePattern = ArrayList(items.orEmpty()) + update() } override fun getStrokePattern(): MutableList = strokePattern @@ -164,19 +161,65 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option override fun getTag(): IObjectWrapper = tag ?: ObjectWrapper.wrap(null) + override fun equalsRemote(other: IPolygonDelegate?): Boolean = equals(other) + + override fun hashCodeRemote(): Int = hashCode() + override fun hashCode(): Int { return id.hashCode() } + override fun equals(other: Any?): Boolean { + if (other is AbstractPolygon) { + return other.id == id + } + return false + } + override fun toString(): String { return id } - override fun equals(other: Any?): Boolean { - if (other is PolygonImpl) { - return other.id == id + companion object { + private val TAG = "GmsMapAbstractPolygon" + } +} + +class PolygonImpl(private val map: GoogleMapImpl, id: String, options: PolygonOptions) : + AbstractPolygon(id, options), Markup { + + + override val strokes = (listOf( + PolylineImpl( + map, "$id-stroke-main", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(points) + ) + ) + holes.mapIndexed { idx, it -> + PolylineImpl( + map, "$id-stroke-hole-$idx", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(it) + ) + }).toMutableList() + + override var annotation: Fill? = null + override var removed: Boolean = false + + override fun remove() { + removed = true + map.fillManager?.let { update(it) } + super.remove() + } + + override fun update() { + annotation?.let { + it.latLngs = mutableListOf(points.map { it.toMapbox() }).plus(holes.map { it.map { it.toMapbox() } }) + it.setFillColor(fillColor) + it.fillOpacity = if (visible) 1f else 0f + it.latLngs = mutableListOf(points.map { it.toMapbox() }).plus(this.holes.map { it.map { it.toMapbox() } }) } - return false + map.fillManager?.let { update(it) } + } + + override fun addPolyline(id: String, options: PolylineOptions) { + strokes.add(PolylineImpl(map, id, options)) } override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) } @@ -185,3 +228,31 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option private val TAG = "GmsMapPolygon" } } + +class LitePolygonImpl(id: String, options: PolygonOptions, private val map: LiteGoogleMapImpl) : AbstractPolygon(id, options) { + + override val strokes: MutableList = (listOf( + LitePolylineImpl( + map, "$id-stroke-main", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(points) + ) + ) + holes.mapIndexed { idx, it -> + LitePolylineImpl( + map, "$id-stroke-hole-$idx", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(it) + ) + }).toMutableList() + + + override fun remove() { + super.remove() + map.polygons.remove(this) + map.postUpdateSnapshot() + } + + override fun update() { + map.postUpdateSnapshot() + } + + override fun addPolyline(id: String, options: PolylineOptions) { + strokes.add(LitePolylineImpl(map, id, options)) + } +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt index 15751f906f1c1fea6ac5b70ee69625dad6bf62e4..1e762402a498b89cf5a296d23374bb8adf2236c9 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt @@ -27,55 +27,48 @@ import com.mapbox.mapboxsdk.plugins.annotation.Line import com.mapbox.mapboxsdk.plugins.annotation.LineOptions import com.mapbox.mapboxsdk.utils.ColorUtils import org.microg.gms.maps.mapbox.GoogleMapImpl +import org.microg.gms.maps.mapbox.LiteGoogleMapImpl import org.microg.gms.maps.mapbox.utils.toMapbox import com.google.android.gms.maps.model.PolylineOptions as GmsLineOptions -class PolylineImpl(private val map: GoogleMapImpl, private val id: String, options: GmsLineOptions) : IPolylineDelegate.Stub(), Markup { - private var points = ArrayList(options.points) - private var width = options.width - private var jointType = options.jointType - private var pattern = ArrayList(options.pattern.orEmpty()) - private var color = options.color - private var visible: Boolean = options.isVisible - private var clickable: Boolean = options.isClickable - private var tag: IObjectWrapper? = null - - override var annotation: Line? = null - override var removed: Boolean = false - override val annotationOptions: LineOptions +abstract class AbstractPolylineImpl(private val id: String, options: GmsLineOptions, private val dpiFactor: Function0) : IPolylineDelegate.Stub() { + internal var points: List = ArrayList(options.points) + internal var width = options.width + internal var jointType = options.jointType + internal var pattern = ArrayList(options.pattern.orEmpty()) + internal var color = options.color + internal var visible: Boolean = options.isVisible + internal var clickable: Boolean = options.isClickable + internal var tag: IObjectWrapper? = null + + val annotationOptions: LineOptions get() = LineOptions() - .withLatLngs(points.map { it.toMapbox() }) - .withLineWidth(width / map.dpiFactor) - .withLineColor(ColorUtils.colorToRgbaString(color)) - .withLineOpacity(if (visible) 1f else 0f) + .withLatLngs(points.map { it.toMapbox() }) + .withLineWidth(width / dpiFactor.invoke()) + .withLineColor(ColorUtils.colorToRgbaString(color)) + .withLineOpacity(if (visible) 1f else 0f) - override fun remove() { - removed = true - map.lineManager?.let { update(it) } - } + internal abstract fun update() override fun getId(): String = id override fun setPoints(points: List) { this.points = ArrayList(points) - annotation?.latLngs = points.map { it.toMapbox() } - map.lineManager?.let { update(it) } + update() } override fun getPoints(): List = points override fun setWidth(width: Float) { this.width = width - annotation?.lineWidth = width / map.dpiFactor - map.lineManager?.let { update(it) } + update() } override fun getWidth(): Float = width override fun setColor(color: Int) { this.color = color - annotation?.setLineColor(color) - map.lineManager?.let { update(it) } + update() } override fun getColor(): Int = color @@ -91,8 +84,7 @@ class PolylineImpl(private val map: GoogleMapImpl, private val id: String, optio override fun setVisible(visible: Boolean) { this.visible = visible - annotation?.lineOpacity = if (visible) 1f else 0f - map.lineManager?.let { update(it) } + update() } override fun isVisible(): Boolean = visible @@ -138,25 +130,63 @@ class PolylineImpl(private val map: GoogleMapImpl, private val id: String, optio return id.hashCode() } - override fun toString(): String { - return id - } - override fun equals(other: Any?): Boolean { - if (other is PolylineImpl) { + if (other is AbstractPolylineImpl) { return other.id == id } return false } + override fun toString(): String { + return id + } + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = - if (super.onTransact(code, data, reply, flags)) { - true - } else { - Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false - } + if (super.onTransact(code, data, reply, flags)) { + true + } else { + Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false + } + + companion object { + const val TAG = "GmsPolylineAbstract" + } +} + +class PolylineImpl(private val map: GoogleMapImpl, id: String, options: GmsLineOptions) : + AbstractPolylineImpl(id, options, { map.dpiFactor }), Markup { + + override var annotation: Line? = null + override var removed: Boolean = false + + override fun remove() { + removed = true + map.lineManager?.let { update(it) } + } + + override fun update() { + annotation?.apply { + latLngs = points.map { it.toMapbox() } + lineWidth = width / map.dpiFactor + setLineColor(color) + lineOpacity = if (visible) 1f else 0f + } + map.lineManager?.let { update(it) } + } companion object { private val TAG = "GmsMapPolyline" } } + +class LitePolylineImpl(private val map: LiteGoogleMapImpl, id: String, options: GmsLineOptions) : + AbstractPolylineImpl(id, options, { map.dpiFactor }) { + override fun remove() { + map.polylines.remove(this) + map.postUpdateSnapshot() + } + + override fun update() { + map.postUpdateSnapshot() + } +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt index 9664aea6f0556ca283aee329d7c358ac2298ed1c..7ab84808a7779e63e1087362c9340a5499e608bb 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt @@ -18,6 +18,7 @@ package org.microg.gms.maps.mapbox.utils import android.os.Bundle import com.google.android.gms.maps.internal.ICancelableCallback +import com.mapbox.geojson.Point import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.geometry.LatLngBounds @@ -31,6 +32,8 @@ import com.google.android.gms.maps.model.VisibleRegion as GmsVisibleRegion fun GmsLatLng.toMapbox(): LatLng = LatLng(latitude, longitude) +fun GmsLatLng.toPoint() = Point.fromLngLat(latitude, longitude) + fun GmsLatLngBounds.toMapbox(): LatLngBounds = LatLngBounds.from(this.northeast.latitude, this.northeast.longitude, this.southwest.latitude, this.southwest.longitude) @@ -68,10 +71,12 @@ fun Bundle.toMapbox(): Bundle { fun LatLng.toGms(): GmsLatLng = GmsLatLng(latitude, longitude) +fun LatLng.toPoint(): Point = Point.fromLngLat(latitude, longitude) + fun LatLngBounds.toGms(): GmsLatLngBounds = GmsLatLngBounds(southWest.toGms(), northEast.toGms()) fun CameraPosition.toGms(): GmsCameraPosition = - GmsCameraPosition(target.toGms(), zoom.toFloat() + 1.0f, tilt.toFloat(), bearing.toFloat()) + GmsCameraPosition(target?.toGms(), zoom.toFloat() + 1.0f, tilt.toFloat(), bearing.toFloat()) fun Bundle.toGms(): Bundle { val newBundle = Bundle(this) @@ -91,4 +96,4 @@ fun Bundle.toGms(): Bundle { } fun VisibleRegion.toGms(): GmsVisibleRegion = - GmsVisibleRegion(nearLeft.toGms(), nearRight.toGms(), farLeft.toGms(), farRight.toGms(), latLngBounds.toGms()) + GmsVisibleRegion(nearLeft?.toGms(), nearRight?.toGms(), farLeft?.toGms(), farRight?.toGms(), latLngBounds.toGms()) diff --git a/play-services-maps-core-mapbox/src/main/res/drawable/location_dot.xml b/play-services-maps-core-mapbox/src/main/res/drawable/location_dot.xml new file mode 100644 index 0000000000000000000000000000000000000000..af953b62bb55533bdf85354f4b431b2cdafa79f2 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/res/drawable/location_dot.xml @@ -0,0 +1,5 @@ + + + + diff --git a/play-services-maps-core-mapbox/src/main/res/drawable/maps_default_bubble.xml b/play-services-maps-core-mapbox/src/main/res/drawable/maps_default_bubble.xml new file mode 100644 index 0000000000000000000000000000000000000000..c172be81e9d1e8703f5012de272a7e56ed9bdad4 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/res/drawable/maps_default_bubble.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/res/layout/maps_default_bubble_layout.xml b/play-services-maps-core-mapbox/src/main/res/layout/maps_default_bubble_layout.xml new file mode 100644 index 0000000000000000000000000000000000000000..6f175407c2356c40587b4e6fef53e1ea5cb80339 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/res/layout/maps_default_bubble_layout.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java index 87a512091f20bcf01e2b92205fb965a2f666b198..8eae51a68e63bc3c6a09a353a525782e34ada03b 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java @@ -44,7 +44,10 @@ import com.google.android.gms.maps.internal.IOnCameraIdleListener; import com.google.android.gms.maps.internal.IOnCameraMoveCanceledListener; import com.google.android.gms.maps.internal.IOnCameraMoveListener; import com.google.android.gms.maps.internal.IOnCameraMoveStartedListener; +import com.google.android.gms.maps.internal.IOnCircleClickListener; import com.google.android.gms.maps.internal.IOnInfoWindowClickListener; +import com.google.android.gms.maps.internal.IOnInfoWindowCloseListener; +import com.google.android.gms.maps.internal.IOnInfoWindowLongClickListener; import com.google.android.gms.maps.internal.IOnMapClickListener; import com.google.android.gms.maps.internal.IOnMapLoadedCallback; import com.google.android.gms.maps.internal.IOnMapLongClickListener; @@ -212,6 +215,11 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub } + @Override + public void setCircleClickListener(IOnCircleClickListener listener) throws RemoteException { + Log.d(TAG, "unimplemented Method: setCircleClickListener"); + } + @Override public boolean setMapStyle(MapStyleOptions options) throws RemoteException { Log.d(TAG, "unimplemented Method: setMapStyle"); @@ -661,6 +669,16 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub } + @Override + public void setInfoWindowLongClickListener(IOnInfoWindowLongClickListener listener) throws RemoteException { + Log.d(TAG, "unimplemented Method: setInfoWindowLongClickListener"); + } + + @Override + public void setInfoWindowCloseListener(IOnInfoWindowCloseListener listener) throws RemoteException { + Log.d(TAG, "unimplemented Method: setInfoWindowCloseListener"); + } + @Override public void onStart() throws RemoteException { Log.d(TAG, "unimplemented Method: onStart"); diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java index 18b4a999450e3772d948d40c195775e465bdd5b5..8a30cd21ecd2b30505f153cdaa20f209dbb52f27 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java @@ -18,8 +18,12 @@ package org.microg.gms.maps.vtm.markup; import android.os.RemoteException; +import android.util.Log; +import com.google.android.gms.dynamic.IObjectWrapper; +import com.google.android.gms.dynamic.ObjectWrapper; import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.PatternItem; import com.google.android.gms.maps.model.internal.ICircleDelegate; import org.microg.gms.maps.vtm.GmsMapsTypeHelper; @@ -28,8 +32,12 @@ import org.oscim.layers.vector.geometries.Drawable; import org.oscim.layers.vector.geometries.Style; import org.oscim.map.Map; +import java.util.List; + public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { + private static final String TAG = "GmsMapCircle"; + private final String id; private final CircleOptions options; private final MarkupListener listener; @@ -139,6 +147,38 @@ public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { return id.hashCode(); } + @Override + public void setClickable(boolean clickable) throws RemoteException { + Log.d(TAG, "unimplemented method: setClickable"); + } + + @Override + public boolean isClickable() throws RemoteException { + return false; + } + + @Override + public void setStrokePattern(List object) throws RemoteException { + Log.d(TAG, "unimplemented method: setStrokePattern"); + } + + @Override + public List getStrokePattern() throws RemoteException { + Log.d(TAG, "unimplemented method: getStrokePattern"); + return null; + } + + @Override + public void setTag(IObjectWrapper object) throws RemoteException { + Log.d(TAG, "unimplemented method: setTag"); + } + + @Override + public IObjectWrapper getTag() throws RemoteException { + Log.d(TAG, "unimplemented method: getTag"); + return ObjectWrapper.wrap(null); + } + @Override public boolean onClick() { return listener.onClick(this); diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl index 0e4434451d35cd598426464b8cbdaf2fadac5ed8..6759dbbd9850ec64f65f7137b1def39b0d4e212e 100644 --- a/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl @@ -13,11 +13,14 @@ import com.google.android.gms.maps.internal.IOnCameraIdleListener; import com.google.android.gms.maps.internal.IOnCameraMoveCanceledListener; import com.google.android.gms.maps.internal.IOnCameraMoveListener; import com.google.android.gms.maps.internal.IOnCameraMoveStartedListener; +import com.google.android.gms.maps.internal.IOnCircleClickListener; import com.google.android.gms.maps.internal.IOnMapClickListener; import com.google.android.gms.maps.internal.IOnMapLongClickListener; import com.google.android.gms.maps.internal.IOnMarkerClickListener; import com.google.android.gms.maps.internal.IOnMarkerDragListener; import com.google.android.gms.maps.internal.IOnInfoWindowClickListener; +import com.google.android.gms.maps.internal.IOnInfoWindowCloseListener; +import com.google.android.gms.maps.internal.IOnInfoWindowLongClickListener; import com.google.android.gms.maps.internal.IInfoWindowAdapter; import com.google.android.gms.maps.internal.IOnMapLoadedCallback; import com.google.android.gms.maps.internal.IOnMyLocationChangeListener; @@ -121,11 +124,11 @@ interface IGoogleMapDelegate { void onExitAmbient() = 81; //void setOnGroundOverlayClickListener(IOnGroundOverlayClickListener listener) = 82; - //void setInfoWindowLongClickListener(IOnInfoWindowLongClickListener listener) = 83; + void setInfoWindowLongClickListener(IOnInfoWindowLongClickListener listener) = 83; //void setPolygonClickListener(IOnPolygonClickListener listener) = 84; - //void setInfoWindowCloseListener(IOnInfoWindowCloseListener listener) = 85; + void setInfoWindowCloseListener(IOnInfoWindowCloseListener listener) = 85; //void setPolylineClickListener(IOnPolylineClickListener listener) = 86; - //void setCircleClickListener(IOnCircleClickListener listener) = 88; + void setCircleClickListener(IOnCircleClickListener listener) = 88; boolean setMapStyle(in MapStyleOptions options) = 90; void setMinZoomPreference(float minZoom) = 91; diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl new file mode 100644 index 0000000000000000000000000000000000000000..cd7ad60e6c5875aa1e6468d86a77a176a8cc32e0 --- /dev/null +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl @@ -0,0 +1,7 @@ +package com.google.android.gms.maps.internal; + +import com.google.android.gms.maps.model.internal.ICircleDelegate; + +interface IOnCircleClickListener { + void onCircleClick(ICircleDelegate circle); +} diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowCloseListener.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowCloseListener.aidl new file mode 100644 index 0000000000000000000000000000000000000000..1ddae39c1baced905977198cf43896ee3b230210 --- /dev/null +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowCloseListener.aidl @@ -0,0 +1,7 @@ +package com.google.android.gms.maps.internal; + +import com.google.android.gms.maps.model.internal.IMarkerDelegate; + +interface IOnInfoWindowCloseListener { + void onInfoWindowClose(IMarkerDelegate marker); +} diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowLongClickListener.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowLongClickListener.aidl new file mode 100644 index 0000000000000000000000000000000000000000..536e55e994e067462fd364dff2ca0f4585d3e2be --- /dev/null +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowLongClickListener.aidl @@ -0,0 +1,7 @@ +package com.google.android.gms.maps.internal; + +import com.google.android.gms.maps.model.internal.IMarkerDelegate; + +interface IOnInfoWindowLongClickListener { + void onInfoWindowLongClick(IMarkerDelegate marker); +} diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl new file mode 100644 index 0000000000000000000000000000000000000000..256aedac9de3c55ebbadbc98d344dc75a287c671 --- /dev/null +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Dash; diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl new file mode 100644 index 0000000000000000000000000000000000000000..c8aa8afb0d23f65b263bd05e156d6f6e9df2449f --- /dev/null +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Dot; diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl new file mode 100644 index 0000000000000000000000000000000000000000..fd4fde3ae30932feb14ef01709e6c6d1ac221fa2 --- /dev/null +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Gap; diff --git a/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl index 719d8eab6b3094e799e6a49c0079ee1c92a5c8b6..0a2c088af8ce102d911e9f8172319916604dd439 100644 --- a/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl +++ b/play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl @@ -1,6 +1,8 @@ package com.google.android.gms.maps.model.internal; +import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.PatternItem; interface ICircleDelegate { void remove(); @@ -21,4 +23,10 @@ interface ICircleDelegate { boolean isVisible(); boolean equalsRemote(ICircleDelegate other); int hashCodeRemote(); + void setClickable(boolean clickable); + boolean isClickable(); + void setStrokePattern(in List items); + List getStrokePattern(); + void setTag(IObjectWrapper object); + IObjectWrapper getTag(); } diff --git a/play-services-maps/src/main/java/com/google/android/gms/maps/GoogleMapOptions.java b/play-services-maps/src/main/java/com/google/android/gms/maps/GoogleMapOptions.java index 405f31d11714a6344f88aac2d3cd0d05c47f0a4c..346660534db0792b25e5f90897952eef60b59eb5 100644 --- a/play-services-maps/src/main/java/com/google/android/gms/maps/GoogleMapOptions.java +++ b/play-services-maps/src/main/java/com/google/android/gms/maps/GoogleMapOptions.java @@ -46,7 +46,7 @@ public final class GoogleMapOptions extends AutoSafeParcelable { @SafeParceled(11) private boolean rotateGesturesEnabled = true; @SafeParceled(12) - private boolean liteMode = false; + private int liteMode = 0; @SafeParceled(14) private boolean mapToobarEnabled = false; @SafeParceled(15) @@ -79,8 +79,9 @@ public final class GoogleMapOptions extends AutoSafeParcelable { return boundsForCamera; } - public Boolean getLiteMode() { - return liteMode; + public boolean getLiteMode() { + // Is encoded as `-1` if null, `0` if false, `1` if true. The default is false. + return liteMode == 1; } public Boolean getMapToolbarEnabled() { diff --git a/play-services-maps/src/main/java/com/google/android/gms/maps/model/CircleOptions.java b/play-services-maps/src/main/java/com/google/android/gms/maps/model/CircleOptions.java index 9f61106023db2e59b13f7a09d3472ce8ca4fa62a..63ff492a765e1e760803390ae059061572d454e6 100644 --- a/play-services-maps/src/main/java/com/google/android/gms/maps/model/CircleOptions.java +++ b/play-services-maps/src/main/java/com/google/android/gms/maps/model/CircleOptions.java @@ -22,6 +22,10 @@ import org.microg.gms.common.PublicApi; import org.microg.safeparcel.AutoSafeParcelable; import org.microg.safeparcel.SafeParceled; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * Defines options for a Circle. */ @@ -43,6 +47,10 @@ public class CircleOptions extends AutoSafeParcelable { private float zIndex = 0; @SafeParceled(8) private boolean visible = true; + @SafeParceled(9) + private boolean clickable = false; + @SafeParceled(10) + private List strokePattern = null; /** * Creates circle options. @@ -144,6 +152,15 @@ public class CircleOptions extends AutoSafeParcelable { return visible; } + /** + * Gets the clickability setting for the circle. + * + * @return {@code true} if the circle is clickable; {@code false} if it is not. + */ + public boolean isClickable() { + return clickable; + } + /** * Sets the radius in meters. *

@@ -217,5 +234,35 @@ public class CircleOptions extends AutoSafeParcelable { return this; } + /** + * Specifies whether this circle is clickable. The default setting is {@code false}. + * + * @param clickable + * @return this {@code CircleOptions} object with a new clickability setting. + */ + public CircleOptions clickable(boolean clickable) { + this.clickable = clickable; + return this; + } + + /** + * Specifies a stroke pattern for the circle's outline. The default stroke pattern is solid, represented by {@code null}. + * + * @return this {@link CircleOptions} object with a new stroke pattern set. + */ + public CircleOptions strokePattern(List pattern) { + this.strokePattern = pattern; + return this; + } + + /** + * Gets the stroke pattern set in this {@link CircleOptions} object for the circle's outline. + * + * @return the stroke pattern of the circle's outline. + */ + public List getStrokePattern() { + return strokePattern; + } + public static Creator CREATOR = new AutoCreator(CircleOptions.class); } diff --git a/play-services-maps/src/main/java/com/google/android/gms/maps/model/PatternItem.java b/play-services-maps/src/main/java/com/google/android/gms/maps/model/PatternItem.java index 6f8e3f7ab60c6112751ad2d1bdeb5843e2e5e12c..1278df94d9b5c0e29a50a16ad43f24978f8f0b4b 100644 --- a/play-services-maps/src/main/java/com/google/android/gms/maps/model/PatternItem.java +++ b/play-services-maps/src/main/java/com/google/android/gms/maps/model/PatternItem.java @@ -21,7 +21,7 @@ public class PatternItem extends AutoSafeParcelable { @Field(2) private int type; @Field(3) - private float length; + private Float length; private PatternItem() { }