diff --git a/app/src/main/assets/map_style_good.json b/app/src/main/assets/map_style_good.json
new file mode 100644
index 0000000..f2b5836
--- /dev/null
+++ b/app/src/main/assets/map_style_good.json
@@ -0,0 +1,3147 @@
+{
+ "version": 8,
+ "metadata": {"maputnik:renderer": "mlgljs"},
+ "sources": {
+ "ne2_shaded": {
+ "maxzoom": 6,
+ "tileSize": 256,
+ "tiles": [
+ "https://tiles.openfreemap.org/natural_earth/ne2sr/{z}/{x}/{y}.png"
+ ],
+ "type": "raster"
+ },
+ "openmaptiles": {
+ "type": "vector",
+ "url": "https://tiles.openfreemap.org/planet"
+ }
+ },
+ "sprite": "https://tiles.openfreemap.org/sprites/ofm_f384/ofm",
+ "glyphs": "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf",
+ "layers": [
+ {
+ "id": "background",
+ "type": "background",
+ "paint": {"background-color": "#f8f4f0"}
+ },
+ {
+ "id": "landcover-glacier",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "subclass"], "glacier"],
+ "paint": {
+ "fill-color": "#fff",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 0, 0.9, 10, 0.3]
+ }
+ },
+ {
+ "id": "landuse-residential",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": [
+ "match",
+ ["get", "class"],
+ ["neighbourhood", "residential"],
+ true,
+ false
+ ],
+ "paint": {
+ "fill-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 12,
+ "hsla(30,19%,90%,0.4)",
+ 16,
+ "hsla(30,19%,90%,0.2)"
+ ]
+ }
+ },
+ {
+ "id": "landuse-suburb",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "maxzoom": 10,
+ "filter": ["==", ["get", "class"], "suburb"],
+ "paint": {
+ "fill-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 8,
+ "hsla(30,19%,90%,0.4)",
+ 10,
+ "hsla(30,19%,90%,0.0)"
+ ]
+ }
+ },
+ {
+ "id": "landuse-commercial",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["==", ["get", "class"], "commercial"]
+ ],
+ "paint": {"fill-color": "hsla(0,60%,87%,0.23)"}
+ },
+ {
+ "id": "landuse-industrial",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ [
+ "match",
+ ["get", "class"],
+ ["dam", "garages", "industrial"],
+ true,
+ false
+ ]
+ ],
+ "paint": {"fill-color": "hsla(49,100%,88%,0.34)"}
+ },
+ {
+ "id": "landuse-cemetery",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "cemetery"],
+ "paint": {"fill-color": "#e0e4dd"}
+ },
+ {
+ "id": "landuse-hospital",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "hospital"],
+ "paint": {"fill-color": "#fde"}
+ },
+ {
+ "id": "landuse-school",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "school"],
+ "paint": {"fill-color": "#f0e8f8"}
+ },
+ {
+ "id": "landuse-railway",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "railway"],
+ "paint": {"fill-color": "hsla(30,19%,90%,0.4)"}
+ },
+ {
+ "id": "park",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "park",
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["MultiPolygon", "Polygon"],
+ true,
+ false
+ ],
+ "paint": {
+ "fill-color": "#d8e8c8",
+ "fill-opacity": [
+ "interpolate",
+ ["exponential", 1.8],
+ ["zoom"],
+ 9,
+ 0.5,
+ 12,
+ 0.2
+ ]
+ }
+ },
+ {
+ "id": "landcover-wood",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "class"], "wood"],
+ "paint": {
+ "fill-antialias": ["step", ["zoom"], false, 9, true],
+ "fill-color": "#6a4",
+ "fill-opacity": 0.1,
+ "fill-outline-color": "hsla(0,0%,0%,0.03)"
+ }
+ },
+ {
+ "id": "landcover-grass",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "class"], "grass"],
+ "paint": {"fill-color": "#d8e8c8", "fill-opacity": 1}
+ },
+ {
+ "id": "landcover-grass-park",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "park",
+ "filter": ["==", ["get", "class"], "public_park"],
+ "paint": {"fill-color": "#d8e8c8", "fill-opacity": 0.8}
+ },
+ {
+ "id": "waterway_tunnel",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "river", "stream"], true, false],
+ ["==", ["get", "brunnel"], "tunnel"]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [2, 4],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-other",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "river", "stream"], false, true],
+ ["==", ["get", "intermittent"], 0]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "waterway-other-intermittent",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "river", "stream"], false, true],
+ ["==", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [4, 3],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "waterway-stream-canal",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "stream"], true, false],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "intermittent"], 0]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-stream-canal-intermittent",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "stream"], true, false],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [4, 3],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-river",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "river"],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["!=", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 10,
+ 0.8,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-river-intermittent",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "river"],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [3, 2.5],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 10,
+ 0.8,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "water",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "water",
+ "filter": [
+ "all",
+ ["!=", ["get", "intermittent"], 1],
+ ["!=", ["get", "brunnel"], "tunnel"]
+ ],
+ "paint": {"fill-color": "#AECFE2"}
+ },
+ {
+ "id": "water-intermittent",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "water",
+ "filter": ["==", ["get", "intermittent"], 1],
+ "paint": {"fill-color": "hsl(210,67%,85%)", "fill-opacity": 0.7}
+ },
+ {
+ "id": "landcover-ice-shelf",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "subclass"], "ice_shelf"],
+ "paint": {
+ "fill-color": "#fff",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 0, 0.9, 10, 0.3]
+ }
+ },
+ {
+ "id": "landcover-sand",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "class"], "sand"],
+ "paint": {"fill-color": "rgba(245, 238, 188, 1)", "fill-opacity": 1}
+ },
+ {
+ "id": "building",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "building",
+ "paint": {
+ "fill-antialias": true,
+ "fill-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 15.5,
+ "#f2eae2",
+ 16,
+ "#dfdbd7"
+ ]
+ }
+ },
+ {
+ "id": "building-top",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "building",
+ "paint": {
+ "fill-color": "#f2eae2",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 13, 0, 16, 1],
+ "fill-outline-color": "#dfdbd7",
+ "fill-translate": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 14,
+ ["literal", [0, 0]],
+ 16,
+ ["literal", [-2, -2]]
+ ]
+ }
+ },
+ {
+ "id": "tunnel-service-track-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["service", "track"], true, false]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-dasharray": [0.5, 0.25],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1,
+ 16,
+ 4,
+ 20,
+ 11
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "rgba(200, 147, 102, 1)",
+ "line-dasharray": [0.5, 0.25],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "tunnel-minor-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "minor"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-dasharray": [0.5, 0.25],
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 0.5,
+ 13,
+ 1,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "tunnel-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-dasharray": [0.5, 0.25],
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-dasharray": [0.5, 0.25],
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 8,
+ 1.5,
+ 20,
+ 17
+ ]
+ }
+ },
+ {
+ "id": "tunnel-trunk-primary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-dasharray": [0.5, 0.25],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "tunnel-path",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#cba",
+ "line-dasharray": [1.5, 0.75],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "rgba(244, 209, 158, 1)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-service-track",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["service", "track"], true, false]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15.5,
+ 0,
+ 16,
+ 2,
+ 20,
+ 7.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff4c6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-minor",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "minor"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 13.5,
+ 0,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff4c6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 10
+ ]
+ }
+ },
+ {
+ "id": "tunnel-trunk-primary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff4c6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#ffdaa6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "tunnel-railway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-dasharray": [2, 2],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 15,
+ 0.75,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "ferry",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": ["match", ["get", "class"], ["ferry"], true, false],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "rgba(108, 159, 182, 1)",
+ "line-dasharray": [2, 2],
+ "line-width": 1.1
+ }
+ },
+ {
+ "id": "aeroway-taxiway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 12,
+ "filter": ["match", ["get", "class"], ["taxiway"], true, false],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(153, 153, 153, 1)",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 2,
+ 17,
+ 12
+ ]
+ }
+ },
+ {
+ "id": "aeroway-runway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 12,
+ "filter": ["match", ["get", "class"], ["runway"], true, false],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(153, 153, 153, 1)",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 5,
+ 17,
+ 55
+ ]
+ }
+ },
+ {
+ "id": "aeroway-area",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["match", ["get", "class"], ["runway", "taxiway"], true, false]
+ ],
+ "paint": {
+ "fill-color": "rgba(255, 255, 255, 1)",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 13, 0, 14, 1]
+ }
+ },
+ {
+ "id": "aeroway-taxiway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["taxiway"], true, false],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(255, 255, 255, 1)",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 11, 0, 12, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 1,
+ 17,
+ 10
+ ]
+ }
+ },
+ {
+ "id": "aeroway-runway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["runway"], true, false],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(255, 255, 255, 1)",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 11, 0, 12, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 4,
+ 17,
+ 50
+ ]
+ }
+ },
+ {
+ "id": "road_area_pier",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["==", ["get", "class"], "pier"]
+ ],
+ "paint": {"fill-antialias": true, "fill-color": "#f8f4f0"}
+ },
+ {
+ "id": "road_pier",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "class"], ["pier"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#f8f4f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1,
+ 17,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "highway-area",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["match", ["get", "class"], ["pier"], false, true]
+ ],
+ "paint": {
+ "fill-antialias": false,
+ "fill-color": "hsla(0,0%,89%,0.56)",
+ "fill-opacity": 0.9,
+ "fill-outline-color": "#cfcdca"
+ }
+ },
+ {
+ "id": "highway-motorway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "highway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "highway-minor-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 0.5,
+ 13,
+ 1,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "highway-secondary-tertiary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 8,
+ 1.5,
+ 20,
+ 17
+ ]
+ }
+ },
+ {
+ "id": "highway-primary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["primary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 7, 0, 8, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 7,
+ 0,
+ 8,
+ 0.6,
+ 9,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "highway-trunk-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 5, 0, 6, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "highway-motorway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0, 5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 4,
+ 0,
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "highway-path",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#cba",
+ "line-dasharray": [1.5, 0.75],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "highway-motorway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "highway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "highway-minor",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 13.5,
+ 0,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "highway-secondary-tertiary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 8,
+ 0.5,
+ 20,
+ 13
+ ]
+ }
+ },
+ {
+ "id": "highway-primary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["primary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 8.5,
+ 0,
+ 9,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "highway-trunk",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "highway-motorway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "railway-transit",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "transit"],
+ ["match", ["get", "brunnel"], ["tunnel"], false, true]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.77)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 20,
+ 1
+ ]
+ }
+ },
+ {
+ "id": "railway-transit-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "transit"],
+ ["match", ["get", "brunnel"], ["tunnel"], false, true]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.68)",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 2,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "railway-service",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "rail"],
+ ["has", "service"]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.77)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 20,
+ 1
+ ]
+ }
+ },
+ {
+ "id": "railway-service-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "rail"],
+ ["has", "service"]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.68)",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 2,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "railway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!", ["has", "service"]],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 15,
+ 0.75,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "railway-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!", ["has", "service"]],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 3,
+ 20,
+ 8
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 19
+ ]
+ }
+ },
+ {
+ "id": "bridge-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 19
+ ]
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 7,
+ 0.6,
+ 8,
+ 1.5,
+ 20,
+ 21
+ ]
+ }
+ },
+ {
+ "id": "bridge-trunk-primary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "hsl(28,76%,67%)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 26
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 26
+ ]
+ }
+ },
+ {
+ "id": "bridge-minor-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 0.5,
+ 13,
+ 1,
+ 14,
+ 6,
+ 20,
+ 24
+ ]
+ }
+ },
+ {
+ "id": "bridge-path-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#f8f4f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "bridge-path",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#cba",
+ "line-dasharray": [1.5, 0.75],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "bridge-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "bridge-minor",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 13.5,
+ 0,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 8,
+ 0.5,
+ 20,
+ 13
+ ]
+ }
+ },
+ {
+ "id": "bridge-trunk-primary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "bridge-railway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 15,
+ 0.75,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "bridge-railway-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 3,
+ 20,
+ 8
+ ]
+ }
+ },
+ {
+ "id": "cablecar",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": ["==", ["get", "subclass"], "cable_car"],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "hsl(0,0%,70%)",
+ "line-width": ["interpolate", ["linear"], ["zoom"], 11, 1, 19, 2.5]
+ }
+ },
+ {
+ "id": "cablecar-dash",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": ["==", ["get", "subclass"], "cable_car"],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "hsl(0,0%,70%)",
+ "line-dasharray": [2, 3],
+ "line-width": ["interpolate", ["linear"], ["zoom"], 11, 3, 19, 5.5]
+ }
+ },
+ {
+ "id": "boundary_3",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "boundary",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ [">=", ["get", "admin_level"], 3],
+ ["<=", ["get", "admin_level"], 6],
+ ["!=", ["get", "maritime"], 1],
+ ["!=", ["get", "disputed"], 1],
+ ["!", ["has", "claimed_by"]]
+ ],
+ "paint": {
+ "line-color": "hsl(0,0%,70%)",
+ "line-dasharray": [1, 1],
+ "line-width": ["interpolate", ["linear", 1], ["zoom"], 7, 1, 11, 2]
+ }
+ },
+ {
+ "id": "boundary_2",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "boundary",
+ "filter": [
+ "all",
+ ["==", ["get", "admin_level"], 2],
+ ["!=", ["get", "maritime"], 1],
+ ["!=", ["get", "disputed"], 1],
+ ["!", ["has", "claimed_by"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "hsl(248,7%,66%)",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 0, 0.4, 4, 1],
+ "line-width": ["interpolate", ["linear"], ["zoom"], 3, 1, 5, 1.2, 12, 3]
+ }
+ },
+ {
+ "id": "boundary_disputed",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "boundary",
+ "filter": [
+ "all",
+ ["!=", ["get", "maritime"], 1],
+ ["==", ["get", "disputed"], 1]
+ ],
+ "paint": {
+ "line-color": "hsl(248,7%,66%)",
+ "line-dasharray": [1, 2],
+ "line-width": ["interpolate", ["linear"], ["zoom"], 3, 1, 5, 1.2, 12, 3]
+ }
+ },
+ {
+ "id": "road_oneway",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", ["get", "oneway"], 1],
+ [
+ "match",
+ ["get", "class"],
+ [
+ "minor",
+ "motorway",
+ "primary",
+ "secondary",
+ "service",
+ "tertiary",
+ "trunk"
+ ],
+ true,
+ false
+ ]
+ ],
+ "layout": {
+ "icon-image": "oneway",
+ "icon-padding": 2,
+ "icon-rotate": 90,
+ "icon-rotation-alignment": "map",
+ "icon-size": ["interpolate", ["linear"], ["zoom"], 15, 0.5, 19, 1],
+ "symbol-placement": "line",
+ "symbol-spacing": 75
+ },
+ "paint": {"icon-opacity": 0.5}
+ },
+ {
+ "id": "road_oneway_opposite",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", ["get", "oneway"], -1],
+ [
+ "match",
+ ["get", "class"],
+ [
+ "minor",
+ "motorway",
+ "primary",
+ "secondary",
+ "service",
+ "tertiary",
+ "trunk"
+ ],
+ true,
+ false
+ ]
+ ],
+ "layout": {
+ "icon-image": "oneway",
+ "icon-padding": 2,
+ "icon-rotate": -90,
+ "icon-rotation-alignment": "map",
+ "icon-size": ["interpolate", ["linear"], ["zoom"], 15, 0.5, 19, 1],
+ "symbol-placement": "line",
+ "symbol-spacing": 75
+ },
+ "paint": {"icon-opacity": 0.5}
+ },
+ {
+ "id": "waterway_line_label",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "minzoom": 10,
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "symbol-spacing": 350,
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 5,
+ "text-size": 14
+ },
+ "paint": {
+ "text-color": "#74aee9",
+ "text-halo-color": "rgba(255,255,255,0.7)",
+ "text-halo-width": 1.5
+ }
+ },
+ {
+ "id": "water_name_point_label",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "water_name",
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["MultiPoint", "Point"],
+ true,
+ false
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 5,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 0, 10, 8, 14]
+ },
+ "paint": {
+ "text-color": "#495e91",
+ "text-halo-color": "rgba(255,255,255,0.7)",
+ "text-halo-width": 1.5
+ }
+ },
+ {
+ "id": "water_name_line_label",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "water_name",
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "symbol-spacing": 350,
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 5,
+ "text-size": 14
+ },
+ "paint": {
+ "text-color": "#495e91",
+ "text-halo-color": "rgba(255,255,255,0.7)",
+ "text-halo-width": 1.5
+ }
+ },
+ {
+ "id": "poi_hos",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "poi",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "$type", "Point"],
+ ["has", "name"],
+ ["==", "class", "railway"],
+ ["==", "subclass", "station"]
+ ],
+ "layout": {
+ "icon-image": [
+ "match",
+ ["get", "subclass"],
+ ["florist", "furniture"],
+ ["get", "subclass"],
+ ["get", "class"]
+ ],
+ "text-anchor": "top",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-max-width": 9,
+ "text-offset": [0, 0.6],
+ "text-size": 12,
+ "visibility": "none"
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "poi_r1",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "poi",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPoint", "Point"], true, false],
+ [">=", ["get", "rank"], 1],
+ ["<=", ["get", "rank"], 6],
+ ["!=", ["get", "subclass"], "bus_stop"],
+ ["!=", ["get", "subclass"], "tram_stop"]
+ ],
+ "layout": {
+ "icon-image": [
+ "match",
+ ["get", "subclass"],
+ ["florist", "furniture"],
+ ["get", "subclass"],
+ ["get", "class"]
+ ],
+ "text-anchor": "top",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-max-width": 9,
+ "text-offset": [0, 0.6],
+ "text-size": 12,
+ "visibility": "visible"
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "highway-name-path",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 15.5,
+ "filter": ["==", ["get", "class"], "path"],
+ "layout": {
+ "symbol-placement": "line",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "map",
+ "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 14, 13]
+ },
+ "paint": {
+ "text-color": "hsl(30,23%,62%)",
+ "text-halo-color": "#f8f4f0",
+ "text-halo-width": 0.5
+ }
+ },
+ {
+ "id": "highway-name-minor",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "map",
+ "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 14, 13]
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "highway-name-major",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 12.2,
+ "filter": [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "map",
+ "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 14, 13]
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "highway-shield-non-us",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 8,
+ "filter": [
+ "all",
+ ["<=", ["get", "ref_length"], 6],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ [
+ "match",
+ ["get", "network"],
+ ["us-highway", "us-interstate", "us-state"],
+ false,
+ true
+ ]
+ ],
+ "layout": {
+ "icon-image": ["concat", "road_", ["get", "ref_length"]],
+ "icon-rotation-alignment": "viewport",
+ "icon-size": 1,
+ "symbol-placement": ["step", ["zoom"], "point", 11, "line"],
+ "symbol-spacing": 200,
+ "text-field": ["to-string", ["get", "ref"]],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "viewport",
+ "text-size": 10
+ }
+ },
+ {
+ "id": "highway-shield-us-interstate",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 7,
+ "filter": [
+ "all",
+ ["<=", ["get", "ref_length"], 6],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "network"], ["us-interstate"], true, false]
+ ],
+ "layout": {
+ "icon-image": [
+ "concat",
+ ["get", "network"],
+ "_",
+ ["get", "ref_length"]
+ ],
+ "icon-rotation-alignment": "viewport",
+ "icon-size": 1,
+ "symbol-placement": ["step", ["zoom"], "point", 7, "line", 8, "line"],
+ "symbol-spacing": 200,
+ "text-field": ["to-string", ["get", "ref"]],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "viewport",
+ "text-size": 10
+ }
+ },
+ {
+ "id": "road_shield_us",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 9,
+ "filter": [
+ "all",
+ ["<=", ["get", "ref_length"], 6],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "network"], ["us-highway", "us-state"], true, false]
+ ],
+ "layout": {
+ "icon-image": [
+ "concat",
+ ["get", "network"],
+ "_",
+ ["get", "ref_length"]
+ ],
+ "icon-rotation-alignment": "viewport",
+ "icon-size": 1,
+ "symbol-placement": ["step", ["zoom"], "point", 11, "line"],
+ "symbol-spacing": 200,
+ "text-field": ["to-string", ["get", "ref"]],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "viewport",
+ "text-size": 10
+ }
+ },
+ {
+ "id": "airport",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "aerodrome_label",
+ "minzoom": 10,
+ "filter": ["all", ["has", "iata"]],
+ "layout": {
+ "icon-image": "airport_11",
+ "icon-size": 1,
+ "text-anchor": "top",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 9,
+ "text-offset": [0, 0.6],
+ "text-optional": true,
+ "text-padding": 2,
+ "text-size": 12
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_other",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 8,
+ "filter": [
+ "match",
+ ["get", "class"],
+ ["city", "continent", "country", "state", "town", "village"],
+ false,
+ true
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.1,
+ "text-max-width": 9,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 8, 9, 12, 10],
+ "text-transform": "uppercase"
+ },
+ "paint": {
+ "text-color": "#333",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_village",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 9,
+ "filter": ["==", ["get", "class"], "village"],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 10, ""],
+ "icon-optional": false,
+ "icon-size": 0.2,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 8,
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 7,
+ 10,
+ 11,
+ 12
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_town",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 6,
+ "filter": ["==", ["get", "class"], "town"],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 10, ""],
+ "icon-optional": false,
+ "icon-size": 0.2,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 8,
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 7,
+ 12,
+ 11,
+ 14
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_state",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 5,
+ "maxzoom": 8,
+ "filter": ["==", ["get", "class"], "state"],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 9,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 5, 10, 8, 14],
+ "text-transform": "uppercase"
+ },
+ "paint": {
+ "text-color": "#333",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_city",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 3,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "city"],
+ ["!=", ["get", "capital"], 2]
+ ],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 9, ""],
+ "icon-optional": false,
+ "icon-size": 0.4,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 8,
+ "text-offset": [0, -0.1],
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 4,
+ 11,
+ 7,
+ 13,
+ 11,
+ 18
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_city_capital",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 3,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "city"],
+ ["==", ["get", "capital"], 2]
+ ],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 9, ""],
+ "icon-optional": false,
+ "icon-size": 0.5,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 8,
+ "text-offset": [0, -0.2],
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 4,
+ 12,
+ 7,
+ 14,
+ 11,
+ 20
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_country_3",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 2,
+ "maxzoom": 9,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "country"],
+ [">=", ["get", "rank"], 3]
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 6.25,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 3, 9, 7, 17]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_country_2",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "maxzoom": 9,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "country"],
+ ["==", ["get", "rank"], 2]
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 6.25,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 2, 9, 5, 17]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_country_1",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "maxzoom": 9,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "country"],
+ ["==", ["get", "rank"], 1]
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 6.25,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 1, 9, 4, 17]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ }
+ ],
+ "id": "94huyrm"
+}
diff --git a/app/src/main/assets/map_style_good_noshops.json b/app/src/main/assets/map_style_good_noshops.json
new file mode 100644
index 0000000..be46c83
--- /dev/null
+++ b/app/src/main/assets/map_style_good_noshops.json
@@ -0,0 +1,3107 @@
+{
+ "version": 8,
+ "metadata": {"maputnik:renderer": "mlgljs"},
+ "sources": {
+ "ne2_shaded": {
+ "maxzoom": 6,
+ "tileSize": 256,
+ "tiles": [
+ "https://tiles.openfreemap.org/natural_earth/ne2sr/{z}/{x}/{y}.png"
+ ],
+ "type": "raster"
+ },
+ "openmaptiles": {
+ "type": "vector",
+ "url": "https://tiles.openfreemap.org/planet"
+ }
+ },
+ "sprite": "https://tiles.openfreemap.org/sprites/ofm_f384/ofm",
+ "glyphs": "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf",
+ "layers": [
+ {
+ "id": "background",
+ "type": "background",
+ "paint": {"background-color": "#f8f4f0"}
+ },
+ {
+ "id": "landcover-glacier",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "subclass"], "glacier"],
+ "paint": {
+ "fill-color": "#fff",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 0, 0.9, 10, 0.3]
+ }
+ },
+ {
+ "id": "landuse-residential",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": [
+ "match",
+ ["get", "class"],
+ ["neighbourhood", "residential"],
+ true,
+ false
+ ],
+ "paint": {
+ "fill-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 12,
+ "hsla(30,19%,90%,0.4)",
+ 16,
+ "hsla(30,19%,90%,0.2)"
+ ]
+ }
+ },
+ {
+ "id": "landuse-suburb",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "maxzoom": 10,
+ "filter": ["==", ["get", "class"], "suburb"],
+ "paint": {
+ "fill-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 8,
+ "hsla(30,19%,90%,0.4)",
+ 10,
+ "hsla(30,19%,90%,0.0)"
+ ]
+ }
+ },
+ {
+ "id": "landuse-commercial",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["==", ["get", "class"], "commercial"]
+ ],
+ "paint": {"fill-color": "hsla(0,60%,87%,0.23)"}
+ },
+ {
+ "id": "landuse-industrial",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ [
+ "match",
+ ["get", "class"],
+ ["dam", "garages", "industrial"],
+ true,
+ false
+ ]
+ ],
+ "paint": {"fill-color": "hsla(49,100%,88%,0.34)"}
+ },
+ {
+ "id": "landuse-cemetery",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "cemetery"],
+ "paint": {"fill-color": "#e0e4dd"}
+ },
+ {
+ "id": "landuse-hospital",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "hospital"],
+ "paint": {"fill-color": "#fde"}
+ },
+ {
+ "id": "landuse-school",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "school"],
+ "paint": {"fill-color": "#f0e8f8"}
+ },
+ {
+ "id": "landuse-railway",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landuse",
+ "filter": ["==", ["get", "class"], "railway"],
+ "paint": {"fill-color": "hsla(30,19%,90%,0.4)"}
+ },
+ {
+ "id": "park",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "park",
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["MultiPolygon", "Polygon"],
+ true,
+ false
+ ],
+ "paint": {
+ "fill-color": "#d8e8c8",
+ "fill-opacity": [
+ "interpolate",
+ ["exponential", 1.8],
+ ["zoom"],
+ 9,
+ 0.5,
+ 12,
+ 0.2
+ ]
+ }
+ },
+ {
+ "id": "landcover-wood",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "class"], "wood"],
+ "paint": {
+ "fill-antialias": ["step", ["zoom"], false, 9, true],
+ "fill-color": "#6a4",
+ "fill-opacity": 0.1,
+ "fill-outline-color": "hsla(0,0%,0%,0.03)"
+ }
+ },
+ {
+ "id": "landcover-grass",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "class"], "grass"],
+ "paint": {"fill-color": "#d8e8c8", "fill-opacity": 1}
+ },
+ {
+ "id": "landcover-grass-park",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "park",
+ "filter": ["==", ["get", "class"], "public_park"],
+ "paint": {"fill-color": "#d8e8c8", "fill-opacity": 0.8}
+ },
+ {
+ "id": "waterway_tunnel",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "river", "stream"], true, false],
+ ["==", ["get", "brunnel"], "tunnel"]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [2, 4],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-other",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "river", "stream"], false, true],
+ ["==", ["get", "intermittent"], 0]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "waterway-other-intermittent",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "river", "stream"], false, true],
+ ["==", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [4, 3],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "waterway-stream-canal",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "stream"], true, false],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "intermittent"], 0]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-stream-canal-intermittent",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["canal", "stream"], true, false],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [4, 3],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.3],
+ ["zoom"],
+ 13,
+ 0.5,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-river",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "river"],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["!=", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 10,
+ 0.8,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "waterway-river-intermittent",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "river"],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "intermittent"], 1]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "#a0c8f0",
+ "line-dasharray": [3, 2.5],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 10,
+ 0.8,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "water",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "water",
+ "filter": [
+ "all",
+ ["!=", ["get", "intermittent"], 1],
+ ["!=", ["get", "brunnel"], "tunnel"]
+ ],
+ "paint": {"fill-color": "#AECFE2"}
+ },
+ {
+ "id": "water-intermittent",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "water",
+ "filter": ["==", ["get", "intermittent"], 1],
+ "paint": {"fill-color": "hsl(210,67%,85%)", "fill-opacity": 0.7}
+ },
+ {
+ "id": "landcover-ice-shelf",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "subclass"], "ice_shelf"],
+ "paint": {
+ "fill-color": "#fff",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 0, 0.9, 10, 0.3]
+ }
+ },
+ {
+ "id": "landcover-sand",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "landcover",
+ "filter": ["==", ["get", "class"], "sand"],
+ "paint": {"fill-color": "rgba(245, 238, 188, 1)", "fill-opacity": 1}
+ },
+ {
+ "id": "building",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "building",
+ "paint": {
+ "fill-antialias": true,
+ "fill-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 15.5,
+ "#f2eae2",
+ 16,
+ "#dfdbd7"
+ ]
+ }
+ },
+ {
+ "id": "building-top",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "building",
+ "paint": {
+ "fill-color": "#f2eae2",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 13, 0, 16, 1],
+ "fill-outline-color": "#dfdbd7",
+ "fill-translate": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 14,
+ ["literal", [0, 0]],
+ 16,
+ ["literal", [-2, -2]]
+ ]
+ }
+ },
+ {
+ "id": "tunnel-service-track-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["service", "track"], true, false]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-dasharray": [0.5, 0.25],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1,
+ 16,
+ 4,
+ 20,
+ 11
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "rgba(200, 147, 102, 1)",
+ "line-dasharray": [0.5, 0.25],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "tunnel-minor-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "minor"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-dasharray": [0.5, 0.25],
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 0.5,
+ 13,
+ 1,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "tunnel-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-dasharray": [0.5, 0.25],
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-dasharray": [0.5, 0.25],
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 8,
+ 1.5,
+ 20,
+ 17
+ ]
+ }
+ },
+ {
+ "id": "tunnel-trunk-primary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-dasharray": [0.5, 0.25],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "tunnel-path",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#cba",
+ "line-dasharray": [1.5, 0.75],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "rgba(244, 209, 158, 1)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-service-track",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["service", "track"], true, false]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15.5,
+ 0,
+ 16,
+ 2,
+ 20,
+ 7.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff4c6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-minor",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "minor"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 13.5,
+ 0,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff4c6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 10
+ ]
+ }
+ },
+ {
+ "id": "tunnel-trunk-primary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fff4c6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "tunnel-motorway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#ffdaa6",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "tunnel-railway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "tunnel"],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-dasharray": [2, 2],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 15,
+ 0.75,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "ferry",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": ["match", ["get", "class"], ["ferry"], true, false],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "rgba(108, 159, 182, 1)",
+ "line-dasharray": [2, 2],
+ "line-width": 1.1
+ }
+ },
+ {
+ "id": "aeroway-taxiway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 12,
+ "filter": ["match", ["get", "class"], ["taxiway"], true, false],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(153, 153, 153, 1)",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 2,
+ 17,
+ 12
+ ]
+ }
+ },
+ {
+ "id": "aeroway-runway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 12,
+ "filter": ["match", ["get", "class"], ["runway"], true, false],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(153, 153, 153, 1)",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 5,
+ 17,
+ 55
+ ]
+ }
+ },
+ {
+ "id": "aeroway-area",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["match", ["get", "class"], ["runway", "taxiway"], true, false]
+ ],
+ "paint": {
+ "fill-color": "rgba(255, 255, 255, 1)",
+ "fill-opacity": ["interpolate", ["linear"], ["zoom"], 13, 0, 14, 1]
+ }
+ },
+ {
+ "id": "aeroway-taxiway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["taxiway"], true, false],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(255, 255, 255, 1)",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 11, 0, 12, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 1,
+ 17,
+ 10
+ ]
+ }
+ },
+ {
+ "id": "aeroway-runway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "aeroway",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["get", "class"], ["runway"], true, false],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "rgba(255, 255, 255, 1)",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 11, 0, 12, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.5],
+ ["zoom"],
+ 11,
+ 4,
+ 17,
+ 50
+ ]
+ }
+ },
+ {
+ "id": "road_area_pier",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["==", ["get", "class"], "pier"]
+ ],
+ "paint": {"fill-antialias": true, "fill-color": "#f8f4f0"}
+ },
+ {
+ "id": "road_pier",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "class"], ["pier"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#f8f4f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1,
+ 17,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "highway-area",
+ "type": "fill",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPolygon", "Polygon"], true, false],
+ ["match", ["get", "class"], ["pier"], false, true]
+ ],
+ "paint": {
+ "fill-antialias": false,
+ "fill-color": "hsla(0,0%,89%,0.56)",
+ "fill-opacity": 0.9,
+ "fill-outline-color": "#cfcdca"
+ }
+ },
+ {
+ "id": "highway-motorway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "highway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "highway-minor-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 0.5,
+ 13,
+ 1,
+ 14,
+ 4,
+ 20,
+ 15
+ ]
+ }
+ },
+ {
+ "id": "highway-secondary-tertiary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 8,
+ 1.5,
+ 20,
+ 17
+ ]
+ }
+ },
+ {
+ "id": "highway-primary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["primary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 7, 0, 8, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 7,
+ 0,
+ 8,
+ 0.6,
+ 9,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "highway-trunk-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 5, 0, 6, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "highway-motorway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 4,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0, 5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 4,
+ 0,
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 22
+ ]
+ }
+ },
+ {
+ "id": "highway-path",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#cba",
+ "line-dasharray": [1.5, 0.75],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "highway-motorway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "highway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "highway-minor",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!=", ["get", "brunnel"], "tunnel"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 13.5,
+ 0,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "highway-secondary-tertiary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 8,
+ 0.5,
+ 20,
+ 13
+ ]
+ }
+ },
+ {
+ "id": "highway-primary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["primary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 8.5,
+ 0,
+ 9,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "highway-trunk",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["match", ["get", "class"], ["trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "highway-motorway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "railway-transit",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "transit"],
+ ["match", ["get", "brunnel"], ["tunnel"], false, true]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.77)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 20,
+ 1
+ ]
+ }
+ },
+ {
+ "id": "railway-transit-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "transit"],
+ ["match", ["get", "brunnel"], ["tunnel"], false, true]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.68)",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 2,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "railway-service",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "rail"],
+ ["has", "service"]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.77)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 20,
+ 1
+ ]
+ }
+ },
+ {
+ "id": "railway-service-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "class"], "rail"],
+ ["has", "service"]
+ ],
+ "paint": {
+ "line-color": "hsla(0,0%,73%,0.68)",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 2,
+ 20,
+ 6
+ ]
+ }
+ },
+ {
+ "id": "railway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!", ["has", "service"]],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 15,
+ 0.75,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "railway-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["!", ["has", "service"]],
+ ["match", ["get", "brunnel"], ["bridge", "tunnel"], false, true],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 3,
+ 20,
+ 8
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 19
+ ]
+ }
+ },
+ {
+ "id": "bridge-link-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 1,
+ 13,
+ 3,
+ 14,
+ 4,
+ 20,
+ 19
+ ]
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 7,
+ 0.6,
+ 8,
+ 1.5,
+ 20,
+ 21
+ ]
+ }
+ },
+ {
+ "id": "bridge-trunk-primary-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "hsl(28,76%,67%)",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 26
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#e9ac77",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 5,
+ 0.4,
+ 6,
+ 0.6,
+ 7,
+ 1.5,
+ 20,
+ 26
+ ]
+ }
+ },
+ {
+ "id": "bridge-minor-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "butt", "line-join": "round"},
+ "paint": {
+ "line-color": "#cfcdca",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12,
+ 0.5,
+ 13,
+ 1,
+ 14,
+ 6,
+ 20,
+ 24
+ ]
+ }
+ },
+ {
+ "id": "bridge-path-casing",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#f8f4f0",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "bridge-path",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "path"]
+ ],
+ "paint": {
+ "line-color": "#cba",
+ "line-dasharray": [1.5, 0.75],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 15,
+ 1.2,
+ 20,
+ 4
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "bridge-link",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ ["==", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 12.5,
+ 0,
+ 13,
+ 1.5,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "bridge-minor",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "#fff",
+ "line-opacity": 1,
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 13.5,
+ 0,
+ 14,
+ 2.5,
+ 20,
+ 11.5
+ ]
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["secondary", "tertiary"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 8,
+ 0.5,
+ 20,
+ 13
+ ]
+ }
+ },
+ {
+ "id": "bridge-trunk-primary",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["match", ["get", "class"], ["primary", "trunk"], true, false],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fea",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "bridge-motorway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "motorway"],
+ ["!=", ["get", "ramp"], 1]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "#fc8",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 6.5,
+ 0,
+ 7,
+ 0.5,
+ 20,
+ 18
+ ]
+ }
+ },
+ {
+ "id": "bridge-railway",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14,
+ 0.4,
+ 15,
+ 0.75,
+ 20,
+ 2
+ ]
+ }
+ },
+ {
+ "id": "bridge-railway-hatching",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "filter": [
+ "all",
+ ["==", ["get", "brunnel"], "bridge"],
+ ["==", ["get", "class"], "rail"]
+ ],
+ "paint": {
+ "line-color": "#bbb",
+ "line-dasharray": [0.2, 8],
+ "line-width": [
+ "interpolate",
+ ["exponential", 1.4],
+ ["zoom"],
+ 14.5,
+ 0,
+ 15,
+ 3,
+ 20,
+ 8
+ ]
+ }
+ },
+ {
+ "id": "cablecar",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": ["==", ["get", "subclass"], "cable_car"],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "hsl(0,0%,70%)",
+ "line-width": ["interpolate", ["linear"], ["zoom"], 11, 1, 19, 2.5]
+ }
+ },
+ {
+ "id": "cablecar-dash",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 13,
+ "filter": ["==", ["get", "subclass"], "cable_car"],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-color": "hsl(0,0%,70%)",
+ "line-dasharray": [2, 3],
+ "line-width": ["interpolate", ["linear"], ["zoom"], 11, 3, 19, 5.5]
+ }
+ },
+ {
+ "id": "boundary_3",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "boundary",
+ "minzoom": 5,
+ "filter": [
+ "all",
+ [">=", ["get", "admin_level"], 3],
+ ["<=", ["get", "admin_level"], 6],
+ ["!=", ["get", "maritime"], 1],
+ ["!=", ["get", "disputed"], 1],
+ ["!", ["has", "claimed_by"]]
+ ],
+ "paint": {
+ "line-color": "hsl(0,0%,70%)",
+ "line-dasharray": [1, 1],
+ "line-width": ["interpolate", ["linear", 1], ["zoom"], 7, 1, 11, 2]
+ }
+ },
+ {
+ "id": "boundary_2",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "boundary",
+ "filter": [
+ "all",
+ ["==", ["get", "admin_level"], 2],
+ ["!=", ["get", "maritime"], 1],
+ ["!=", ["get", "disputed"], 1],
+ ["!", ["has", "claimed_by"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-color": "hsl(248,7%,66%)",
+ "line-opacity": ["interpolate", ["linear"], ["zoom"], 0, 0.4, 4, 1],
+ "line-width": ["interpolate", ["linear"], ["zoom"], 3, 1, 5, 1.2, 12, 3]
+ }
+ },
+ {
+ "id": "boundary_disputed",
+ "type": "line",
+ "source": "openmaptiles",
+ "source-layer": "boundary",
+ "filter": [
+ "all",
+ ["!=", ["get", "maritime"], 1],
+ ["==", ["get", "disputed"], 1]
+ ],
+ "paint": {
+ "line-color": "hsl(248,7%,66%)",
+ "line-dasharray": [1, 2],
+ "line-width": ["interpolate", ["linear"], ["zoom"], 3, 1, 5, 1.2, 12, 3]
+ }
+ },
+ {
+ "id": "road_oneway",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", ["get", "oneway"], 1],
+ [
+ "match",
+ ["get", "class"],
+ [
+ "minor",
+ "motorway",
+ "primary",
+ "secondary",
+ "service",
+ "tertiary",
+ "trunk"
+ ],
+ true,
+ false
+ ]
+ ],
+ "layout": {
+ "icon-image": "oneway",
+ "icon-padding": 2,
+ "icon-rotate": 90,
+ "icon-rotation-alignment": "map",
+ "icon-size": ["interpolate", ["linear"], ["zoom"], 15, 0.5, 19, 1],
+ "symbol-placement": "line",
+ "symbol-spacing": 75
+ },
+ "paint": {"icon-opacity": 0.5}
+ },
+ {
+ "id": "road_oneway_opposite",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", ["get", "oneway"], -1],
+ [
+ "match",
+ ["get", "class"],
+ [
+ "minor",
+ "motorway",
+ "primary",
+ "secondary",
+ "service",
+ "tertiary",
+ "trunk"
+ ],
+ true,
+ false
+ ]
+ ],
+ "layout": {
+ "icon-image": "oneway",
+ "icon-padding": 2,
+ "icon-rotate": -90,
+ "icon-rotation-alignment": "map",
+ "icon-size": ["interpolate", ["linear"], ["zoom"], 15, 0.5, 19, 1],
+ "symbol-placement": "line",
+ "symbol-spacing": 75
+ },
+ "paint": {"icon-opacity": 0.5}
+ },
+ {
+ "id": "waterway_line_label",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "waterway",
+ "minzoom": 10,
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "symbol-spacing": 350,
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 5,
+ "text-size": 14
+ },
+ "paint": {
+ "text-color": "#74aee9",
+ "text-halo-color": "rgba(255,255,255,0.7)",
+ "text-halo-width": 1.5
+ }
+ },
+ {
+ "id": "water_name_point_label",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "water_name",
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["MultiPoint", "Point"],
+ true,
+ false
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 5,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 0, 10, 8, 14]
+ },
+ "paint": {
+ "text-color": "#495e91",
+ "text-halo-color": "rgba(255,255,255,0.7)",
+ "text-halo-width": 1.5
+ }
+ },
+ {
+ "id": "water_name_line_label",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "water_name",
+ "filter": [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "symbol-spacing": 350,
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 5,
+ "text-size": 14
+ },
+ "paint": {
+ "text-color": "#495e91",
+ "text-halo-color": "rgba(255,255,255,0.7)",
+ "text-halo-width": 1.5
+ }
+ },
+ {
+ "id": "poi_r1",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "poi",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["match", ["geometry-type"], ["MultiPoint", "Point"], true, false],
+ [">=", ["get", "rank"], 1],
+ ["<=", ["get", "rank"], 6],
+ ["!=", ["get", "subclass"], "bus_stop"],
+ ["!=", ["get", "subclass"], "tram_stop"],
+ ["!=", ["get", "class"], "shop"]
+ ],
+ "layout": {
+ "icon-image": [
+ "match",
+ ["get", "subclass"],
+ ["florist", "furniture"],
+ ["get", "subclass"],
+ ["get", "class"]
+ ],
+ "text-anchor": "top",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-max-width": 9,
+ "text-offset": [0, 0.6],
+ "text-size": 12,
+ "visibility": "visible"
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "highway-name-path",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 15.5,
+ "filter": ["==", ["get", "class"], "path"],
+ "layout": {
+ "symbol-placement": "line",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "map",
+ "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 14, 13]
+ },
+ "paint": {
+ "text-color": "hsl(30,23%,62%)",
+ "text-halo-color": "#f8f4f0",
+ "text-halo-width": 0.5
+ }
+ },
+ {
+ "id": "highway-name-minor",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "class"], ["minor", "service", "track"], true, false]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "map",
+ "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 14, 13]
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "highway-name-major",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 12.2,
+ "filter": [
+ "match",
+ ["get", "class"],
+ ["primary", "secondary", "tertiary", "trunk"],
+ true,
+ false
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], " ", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "map",
+ "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 14, 13]
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "highway-shield-non-us",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 8,
+ "filter": [
+ "all",
+ ["<=", ["get", "ref_length"], 6],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ [
+ "match",
+ ["get", "network"],
+ ["us-highway", "us-interstate", "us-state"],
+ false,
+ true
+ ]
+ ],
+ "layout": {
+ "icon-image": ["concat", "road_", ["get", "ref_length"]],
+ "icon-rotation-alignment": "viewport",
+ "icon-size": 1,
+ "symbol-placement": ["step", ["zoom"], "point", 11, "line"],
+ "symbol-spacing": 200,
+ "text-field": ["to-string", ["get", "ref"]],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "viewport",
+ "text-size": 10
+ }
+ },
+ {
+ "id": "highway-shield-us-interstate",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 7,
+ "filter": [
+ "all",
+ ["<=", ["get", "ref_length"], 6],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "network"], ["us-interstate"], true, false]
+ ],
+ "layout": {
+ "icon-image": [
+ "concat",
+ ["get", "network"],
+ "_",
+ ["get", "ref_length"]
+ ],
+ "icon-rotation-alignment": "viewport",
+ "icon-size": 1,
+ "symbol-placement": ["step", ["zoom"], "point", 7, "line", 8, "line"],
+ "symbol-spacing": 200,
+ "text-field": ["to-string", ["get", "ref"]],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "viewport",
+ "text-size": 10
+ }
+ },
+ {
+ "id": "road_shield_us",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "transportation_name",
+ "minzoom": 9,
+ "filter": [
+ "all",
+ ["<=", ["get", "ref_length"], 6],
+ [
+ "match",
+ ["geometry-type"],
+ ["LineString", "MultiLineString"],
+ true,
+ false
+ ],
+ ["match", ["get", "network"], ["us-highway", "us-state"], true, false]
+ ],
+ "layout": {
+ "icon-image": [
+ "concat",
+ ["get", "network"],
+ "_",
+ ["get", "ref_length"]
+ ],
+ "icon-rotation-alignment": "viewport",
+ "icon-size": 1,
+ "symbol-placement": ["step", ["zoom"], "point", 11, "line"],
+ "symbol-spacing": 200,
+ "text-field": ["to-string", ["get", "ref"]],
+ "text-font": ["Noto Sans Regular"],
+ "text-rotation-alignment": "viewport",
+ "text-size": 10
+ }
+ },
+ {
+ "id": "airport",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "aerodrome_label",
+ "minzoom": 10,
+ "filter": ["all", ["has", "iata"]],
+ "layout": {
+ "icon-image": "airport_11",
+ "icon-size": 1,
+ "text-anchor": "top",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 9,
+ "text-offset": [0, 0.6],
+ "text-optional": true,
+ "text-padding": 2,
+ "text-size": 12
+ },
+ "paint": {
+ "text-color": "#666",
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_other",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 8,
+ "filter": [
+ "match",
+ ["get", "class"],
+ ["city", "continent", "country", "state", "town", "village"],
+ false,
+ true
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.1,
+ "text-max-width": 9,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 8, 9, 12, 10],
+ "text-transform": "uppercase"
+ },
+ "paint": {
+ "text-color": "#333",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_village",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 9,
+ "filter": ["==", ["get", "class"], "village"],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 10, ""],
+ "icon-optional": false,
+ "icon-size": 0.2,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 8,
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 7,
+ 10,
+ 11,
+ 12
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_town",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 6,
+ "filter": ["==", ["get", "class"], "town"],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 10, ""],
+ "icon-optional": false,
+ "icon-size": 0.2,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 8,
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 7,
+ 12,
+ 11,
+ 14
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_state",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 5,
+ "maxzoom": 8,
+ "filter": ["==", ["get", "class"], "state"],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Italic"],
+ "text-letter-spacing": 0.2,
+ "text-max-width": 9,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 5, 10, 8, 14],
+ "text-transform": "uppercase"
+ },
+ "paint": {
+ "text-color": "#333",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_city",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 3,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "city"],
+ ["!=", ["get", "capital"], 2]
+ ],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 9, ""],
+ "icon-optional": false,
+ "icon-size": 0.4,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Regular"],
+ "text-max-width": 8,
+ "text-offset": [0, -0.1],
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 4,
+ 11,
+ 7,
+ 13,
+ 11,
+ 18
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_city_capital",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 3,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "city"],
+ ["==", ["get", "capital"], 2]
+ ],
+ "layout": {
+ "icon-allow-overlap": true,
+ "icon-image": ["step", ["zoom"], "circle_11_black", 9, ""],
+ "icon-optional": false,
+ "icon-size": 0.5,
+ "text-anchor": "bottom",
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 8,
+ "text-offset": [0, -0.2],
+ "text-size": [
+ "interpolate",
+ ["exponential", 1.2],
+ ["zoom"],
+ 4,
+ 12,
+ 7,
+ 14,
+ 11,
+ 20
+ ]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_country_3",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "minzoom": 2,
+ "maxzoom": 9,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "country"],
+ [">=", ["get", "rank"], 3]
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 6.25,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 3, 9, 7, 17]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_country_2",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "maxzoom": 9,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "country"],
+ ["==", ["get", "rank"], 2]
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 6.25,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 2, 9, 5, 17]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "label_country_1",
+ "type": "symbol",
+ "source": "openmaptiles",
+ "source-layer": "place",
+ "maxzoom": 9,
+ "filter": [
+ "all",
+ ["==", ["get", "class"], "country"],
+ ["==", ["get", "rank"], 1]
+ ],
+ "layout": {
+ "text-field": [
+ "case",
+ ["has", "name:nonlatin"],
+ ["concat", ["get", "name:latin"], "\n", ["get", "name:nonlatin"]],
+ ["coalesce", ["get", "name_en"], ["get", "name"]]
+ ],
+ "text-font": ["Noto Sans Bold"],
+ "text-max-width": 6.25,
+ "text-size": ["interpolate", ["linear"], ["zoom"], 1, 9, 4, 17]
+ },
+ "paint": {
+ "text-color": "#000",
+ "text-halo-blur": 1,
+ "text-halo-color": "#fff",
+ "text-halo-width": 1
+ }
+ }
+ ],
+ "id": "94huyrm"
+}
\ No newline at end of file
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MapFragmentKt.kt b/app/src/main/java/it/reyboz/bustorino/fragments/MapFragmentKt.kt
index 08aa2fe..2a319a4 100644
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MapFragmentKt.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapFragmentKt.kt
@@ -1,771 +1,768 @@
/*
BusTO - Fragments components
Copyright (C) 2020 Andrea Ugo
Copyright (C) 2021 Fabio Mazza
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package it.reyboz.bustorino.fragments
import android.Manifest
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.location.LocationManager
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.Toast
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.res.ResourcesCompat
+import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager
import it.reyboz.bustorino.R
import it.reyboz.bustorino.backend.Stop
import it.reyboz.bustorino.backend.gtfs.LivePositionUpdate
import it.reyboz.bustorino.backend.mato.MQTTMatoClient
import it.reyboz.bustorino.backend.utils
import it.reyboz.bustorino.data.gtfs.MatoPattern
import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops
import it.reyboz.bustorino.map.BusInfoWindow
import it.reyboz.bustorino.map.CustomInfoWindow
import it.reyboz.bustorino.map.CustomInfoWindow.TouchResponder
import it.reyboz.bustorino.map.LocationOverlay
import it.reyboz.bustorino.map.LocationOverlay.OverlayCallbacks
import it.reyboz.bustorino.map.MarkerUtils
import it.reyboz.bustorino.middleware.GeneralActivity
import it.reyboz.bustorino.util.Permissions
import it.reyboz.bustorino.viewmodels.LivePositionsViewModel
import it.reyboz.bustorino.viewmodels.StopsMapViewModel
import org.osmdroid.config.Configuration
import org.osmdroid.events.DelayedMapListener
import org.osmdroid.events.MapListener
import org.osmdroid.events.ScrollEvent
import org.osmdroid.events.ZoomEvent
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.FolderOverlay
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.infowindow.InfoWindow
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
open class MapFragmentKt : ScreenBaseFragment() {
protected var listenerMain: FragmentListenerMain? = null
private var shownStops: HashSet? = null
private lateinit var map: MapView
var ctx: Context? = null
private lateinit var mLocationOverlay: LocationOverlay
private lateinit var stopsFolderOverlay: FolderOverlay
private var savedMapState: Bundle? = null
protected lateinit var btCenterMap: ImageButton
protected lateinit var btFollowMe: ImageButton
protected var coordLayout: CoordinatorLayout? = null
private var hasMapStartFinished = false
private var followingLocation = false
//the ViewModel from which we get the stop to display in the map
- private var stopsViewModel: StopsMapViewModel? = null
+ private val stopsViewModel: StopsMapViewModel by viewModels()
//private GtfsPositionsViewModel gtfsPosViewModel; //= new ViewModelProvider(this).get(MapViewModel.class);
- private var livePositionsViewModel: LivePositionsViewModel? = null
+ private val livePositionsViewModel: LivePositionsViewModel by viewModels()
private var useMQTTViewModel = true
private val busPositionMarkersByTrip = HashMap()
private var busPositionsOverlay: FolderOverlay? = null
private val tripMarkersAnimators = HashMap()
protected val responder = TouchResponder { stopID, stopName ->
if (listenerMain != null) {
Log.d(DEBUG_TAG, "Asked to show arrivals for stop ID: $stopID")
listenerMain!!.requestArrivalsForStopID(stopID)
}
}
protected val locationCallbacks: OverlayCallbacks = object : OverlayCallbacks {
override fun onDisableFollowMyLocation() {
updateGUIForLocationFollowing(false)
followingLocation = false
}
override fun onEnableFollowMyLocation() {
updateGUIForLocationFollowing(true)
followingLocation = true
}
}
private val positionRequestLauncher =
registerForActivityResult, Map>(
ActivityResultContracts.RequestMultiplePermissions(),
ActivityResultCallback { result ->
if (result == null) {
Log.w(DEBUG_TAG, "Got asked permission but request is null, doing nothing?")
- } else if (java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_COARSE_LOCATION] && java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_FINE_LOCATION]) {
+ } else if (java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_COARSE_LOCATION]
+ && java.lang.Boolean.TRUE == result[Manifest.permission.ACCESS_FINE_LOCATION]) {
+ // We can use the position, restart location overlay
map.overlays.remove(mLocationOverlay)
startLocationOverlay(true, map)
if (context == null || requireContext().getSystemService(Context.LOCATION_SERVICE) == null)
return@ActivityResultCallback ///@registerForActivityResult
val locationManager =
requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
@SuppressLint("MissingPermission") val userLocation =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (userLocation != null) {
map!!.controller.setZoom(POSITION_FOUND_ZOOM)
val startPoint = GeoPoint(userLocation)
setLocationFollowing(true)
map!!.controller.setCenter(startPoint)
}
} else Log.w(DEBUG_TAG, "No location permission")
})
//public static MapFragment getInstance(@NonNull Stop stop){
// return getInstance(stop.getLatitude(), stop.getLongitude(), stop.getStopDisplayName(), stop.ID);
//}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//use the same layout as the activity
val root = inflater.inflate(R.layout.fragment_map, container, false)
val context = requireContext()
ctx = context.applicationContext
Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(context))
map = root.findViewById(R.id.map)
map.setTileSource(TileSourceFactory.MAPNIK)
//map.setTilesScaledToDpi(true);
map.setFlingEnabled(true)
// add ability to zoom with 2 fingers
map.setMultiTouchControls(true)
btCenterMap = root.findViewById(R.id.icon_center_map)
btFollowMe = root.findViewById(R.id.icon_follow)
coordLayout = root.findViewById(R.id.coord_layout)
//setup FolderOverlay
stopsFolderOverlay = FolderOverlay()
//setup Bus Markers Overlay
busPositionsOverlay = FolderOverlay()
//reset shown bus updates
busPositionMarkersByTrip.clear()
tripMarkersAnimators.clear()
//set map not done
hasMapStartFinished = false
val keySourcePositions = getString(R.string.pref_positions_source)
useMQTTViewModel = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getString(keySourcePositions, SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE)
.contentEquals(SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE)
//Start map from bundle
if (savedInstanceState != null) startMap(arguments, savedInstanceState) else startMap(
arguments, savedMapState
)
//set listeners
map.addMapListener(DelayedMapListener(object : MapListener {
override fun onScroll(paramScrollEvent: ScrollEvent): Boolean {
requestStopsToShow()
//Log.d(DEBUG_TAG, "Scrolling");
//if (moveTriggeredByCode) moveTriggeredByCode =false;
//else setLocationFollowing(false);
return true
}
override fun onZoom(event: ZoomEvent): Boolean {
requestStopsToShow()
return true
}
}))
btCenterMap.setOnClickListener(View.OnClickListener { v: View? ->
//Log.i(TAG, "centerMap clicked ");
if (Permissions.bothLocationPermissionsGranted(context)) {
val myPosition = mLocationOverlay!!.myLocation
map.getController().animateTo(myPosition)
} else Toast.makeText(context, R.string.enable_position_message_map, Toast.LENGTH_SHORT)
.show()
})
btFollowMe.setOnClickListener(View.OnClickListener { v: View? ->
//Log.i(TAG, "btFollowMe clicked ");
if (Permissions.bothLocationPermissionsGranted(context)) setLocationFollowing(!followingLocation) else Toast.makeText(
context, R.string.enable_position_message_map, Toast.LENGTH_SHORT
)
.show()
})
return root
}
override fun onAttach(context: Context) {
super.onAttach(context)
- val provider = ViewModelProvider(this)
- //gtfsPosViewModel = provider.get(GtfsPositionsViewModel.class);
- livePositionsViewModel = provider.get(LivePositionsViewModel::class.java)
- stopsViewModel = provider.get(StopsMapViewModel::class.java)
listenerMain = if (context is FragmentListenerMain) {
context
} else {
throw RuntimeException(
context.toString()
+ " must implement FragmentListenerMain"
)
}
}
override fun onDetach() {
super.onDetach()
listenerMain = null
- //stop animations
- // setupOnAttached = true;
Log.w(DEBUG_TAG, "Fragment detached")
}
override fun onPause() {
super.onPause()
Log.w(DEBUG_TAG, "On pause called mapfrag")
saveMapState()
for (animator in tripMarkersAnimators.values) {
if (animator != null && animator.isRunning) {
animator.cancel()
}
}
tripMarkersAnimators.clear()
if (useMQTTViewModel) livePositionsViewModel!!.stopMatoUpdates()
}
/**
* Save the map state inside the fragment
* (calls saveMapState(bundle))
*/
private fun saveMapState() {
savedMapState = Bundle()
saveMapState(savedMapState!!)
}
/**
* Save the state of the map to restore it to a later time
* @param bundle the bundle in which to save the data
*/
private fun saveMapState(bundle: Bundle) {
Log.d(DEBUG_TAG, "Saving state, location following: $followingLocation")
bundle.putBoolean(FOLLOWING_LOCAT_KEY, followingLocation)
if (map == null) {
//The map is null, it can happen?
Log.e(DEBUG_TAG, "Cannot save map center, map is null")
return
}
val loc = map!!.mapCenter
bundle.putDouble(MAP_CENTER_LAT_KEY, loc.latitude)
bundle.putDouble(MAP_CENTER_LON_KEY, loc.longitude)
bundle.putDouble(MAP_CURRENT_ZOOM_KEY, map!!.zoomLevelDouble)
}
override fun onResume() {
super.onResume()
//TODO: cleanup duplicate code (maybe merging the positions classes?)
if (listenerMain != null) listenerMain!!.readyGUIfor(FragmentKind.MAP)
/// choose which to use
val keySourcePositions = getString(R.string.pref_positions_source)
useMQTTViewModel = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getString(keySourcePositions, SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE)
.contentEquals(
SettingsFragment.LIVE_POSITIONS_PREF_MQTT_VALUE
)
if (livePositionsViewModel != null) {
//gtfsPosViewModel.requestUpdates();
if (useMQTTViewModel) livePositionsViewModel!!.requestMatoPosUpdates(MQTTMatoClient.LINES_ALL)
else livePositionsViewModel!!.requestGTFSUpdates()
//mapViewModel.testCascade();
livePositionsViewModel!!.isLastWorkResultGood.observe(this) { d: Boolean ->
Log.d(
DEBUG_TAG, "Last trip download result is $d"
)
}
livePositionsViewModel!!.tripsGtfsIDsToQuery.observe(this) { dat: List ->
Log.i(DEBUG_TAG, "Have these trips IDs missing from the DB, to be queried: $dat")
livePositionsViewModel!!.downloadTripsFromMato(dat)
}
} /*else if(gtfsPosViewModel!=null){
gtfsPosViewModel.requestUpdates();
gtfsPosViewModel.getTripsGtfsIDsToQuery().observe(this, dat -> {
Log.i(DEBUG_TAG, "Have these trips IDs missing from the DB, to be queried: "+dat);
//gtfsPosViewModel.downloadTripsFromMato(dat);
MatoTripsDownloadWorker.Companion.downloadTripsFromMato(dat,getContext().getApplicationContext(),
"BusTO-MatoTripDownload");
});
}
*/ else Log.e(DEBUG_TAG, "livePositionsViewModel is null at onResume")
//rerequest stop
stopsViewModel!!.requestStopsInBoundingBox(map!!.boundingBox)
}
private fun startRequestsPositions() {
if (livePositionsViewModel != null) {
//should always be the case
livePositionsViewModel!!.updatesWithTripAndPatterns.observe(viewLifecycleOwner) { data: HashMap> ->
Log.d(
DEBUG_TAG,
"Have " + data.size + " trip updates, has Map start finished: " + hasMapStartFinished
)
if (hasMapStartFinished) updateBusPositionsInMap(data)
if (!isDetached && !useMQTTViewModel) livePositionsViewModel!!.requestDelayedGTFSUpdates(
3000
)
}
} else {
Log.e(DEBUG_TAG, "PositionsViewModel is null")
}
}
override fun onSaveInstanceState(outState: Bundle) {
saveMapState(outState)
super.onSaveInstanceState(outState)
}
//own methods
/**
* Switch following the location on and off
* @param value true if we want to follow location
*/
fun setLocationFollowing(value: Boolean) {
followingLocation = value
if (mLocationOverlay == null || context == null || map == null) //nothing else to do
return
if (value) {
mLocationOverlay!!.enableFollowLocation()
} else {
mLocationOverlay!!.disableFollowLocation()
}
}
/**
* Do all the stuff you need to do on the gui, when parameter is changed to value
* @param following value
*/
protected fun updateGUIForLocationFollowing(following: Boolean) {
if (following) btFollowMe!!.setImageResource(R.drawable.ic_follow_me_on) else btFollowMe!!.setImageResource(
R.drawable.ic_follow_me
)
}
/**
* Build the location overlay. Enable only when
* a) we know we have the permission
* b) the location map is set
*/
private fun startLocationOverlay(enableLocation: Boolean, map: MapView?) {
checkNotNull(activity) { "Cannot enable LocationOverlay now" }
// Location Overlay
// from OpenBikeSharing (THANK GOD)
Log.d(DEBUG_TAG, "Starting position overlay")
val imlp = GpsMyLocationProvider(requireActivity().baseContext)
imlp.locationUpdateMinDistance = 5f
imlp.locationUpdateMinTime = 2000
val overlay = LocationOverlay(imlp, map, locationCallbacks)
if (enableLocation) overlay.enableMyLocation()
overlay.isOptionsMenuEnabled = true
//map.getOverlays().add(this.mLocationOverlay);
mLocationOverlay = overlay
map!!.overlays.add(mLocationOverlay)
}
fun startMap(incoming: Bundle?, savedInstanceState: Bundle?) {
//Check that we're attached
val activity = if (activity is GeneralActivity) activity as GeneralActivity? else null
if (context == null || activity == null) {
//we are not attached
Log.e(DEBUG_TAG, "Calling startMap when not attached")
return
} else {
Log.d(DEBUG_TAG, "Starting map from scratch")
}
//clear previous overlays
map!!.overlays.clear()
//parse incoming bundle
var marker: GeoPoint? = null
var name: String? = null
var ID: String? = null
var routesStopping: String? = ""
if (incoming != null) {
val lat = incoming.getDouble(BUNDLE_LATIT)
val lon = incoming.getDouble(BUNDLE_LONGIT)
marker = GeoPoint(lat, lon)
name = incoming.getString(BUNDLE_NAME)
ID = incoming.getString(BUNDLE_ID)
routesStopping = incoming.getString(BUNDLE_ROUTES_STOPPING, "")
}
//ask for location permission
if (!Permissions.bothLocationPermissionsGranted(activity)) {
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
//TODO: show dialog for permission rationale
Toast.makeText(activity, R.string.enable_position_message_map, Toast.LENGTH_SHORT)
.show()
}
positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS)
}
shownStops = HashSet()
// move the map on the marker position or on a default view point: Turin, Piazza Castello
// and set the start zoom
val mapController = map!!.controller
var startPoint: GeoPoint? = null
startLocationOverlay(
Permissions.bothLocationPermissionsGranted(activity),
map
)
// set the center point
if (marker != null) {
//startPoint = marker;
mapController.setZoom(POSITION_FOUND_ZOOM)
setLocationFollowing(false)
// put the center a little bit off (animate later)
startPoint = GeoPoint(marker)
startPoint.latitude = marker.latitude + utils.angleRawDifferenceFromMeters(20.0)
startPoint.longitude = marker.longitude - utils.angleRawDifferenceFromMeters(20.0)
//don't need to do all the rest since we want to show a point
} else if (savedInstanceState != null && savedInstanceState.containsKey(MAP_CURRENT_ZOOM_KEY)) {
mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY))
mapController.setCenter(
GeoPoint(
savedInstanceState.getDouble(MAP_CENTER_LAT_KEY),
savedInstanceState.getDouble(MAP_CENTER_LON_KEY)
)
)
Log.d(
DEBUG_TAG,
"Location following from savedInstanceState: " + savedInstanceState.getBoolean(
FOLLOWING_LOCAT_KEY
)
)
setLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY))
} else {
Log.d(DEBUG_TAG, "No position found from intent or saved state")
var found = false
val locationManager =
requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
//check for permission
if (Permissions.bothLocationPermissionsGranted(activity)) {
@SuppressLint("MissingPermission") val userLocation =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (userLocation != null) {
val distan = utils.measuredistanceBetween(
userLocation.latitude, userLocation.longitude,
DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON
)
if (distan < 100000.0) {
mapController.setZoom(POSITION_FOUND_ZOOM)
startPoint = GeoPoint(userLocation)
found = true
setLocationFollowing(true)
}
}
}
if (!found) {
startPoint = GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON)
mapController.setZoom(NO_POSITION_ZOOM)
setLocationFollowing(false)
}
}
// set the minimum zoom level
map!!.minZoomLevel = 15.0
//add contingency check (shouldn't happen..., but)
if (startPoint != null) {
mapController.setCenter(startPoint)
}
//add stops overlay
//map.getOverlays().add(mLocationOverlay);
map!!.overlays.add(stopsFolderOverlay)
Log.d(DEBUG_TAG, "Requesting stops load")
// This is not necessary, by setting the center we already move
// the map and we trigger a stop request
//requestStopsToShow();
if (marker != null) {
// make a marker with the info window open for the searched marker
//TODO: make Stop Bundle-able
val stopMarker = makeMarker(marker, ID, name, routesStopping, true)
map!!.controller.animateTo(marker)
}
//add the overlays with the bus stops
if (busPositionsOverlay == null) {
//Log.i(DEBUG_TAG, "Null bus positions overlay,redo");
busPositionsOverlay = FolderOverlay()
}
startRequestsPositions()
if (stopsViewModel != null) {
stopsViewModel!!.stopsInBoundingBox.observe(viewLifecycleOwner) { stops: List? ->
showStopsMarkers(
stops
)
}
} else Log.d(DEBUG_TAG, "Cannot observe new stops in map, stopsViewModel is null")
map!!.overlays.add(busPositionsOverlay)
//set map as started
hasMapStartFinished = true
}
/**
* Start a request to load the stops that are in the current view
* from the database
*/
private fun requestStopsToShow() {
// get the top, bottom, left and right screen's coordinate
val bb = map!!.boundingBox
Log.d(
DEBUG_TAG,
"Requesting stops in bounding box, stopViewModel is null " + (stopsViewModel == null)
)
if (stopsViewModel != null) {
stopsViewModel!!.requestStopsInBoundingBox(bb)
}
}
private fun updateBusMarker(
marker: Marker?,
posUpdate: LivePositionUpdate,
justCreated: Boolean
) {
val position: GeoPoint
val updateID = posUpdate.tripID
if (!justCreated) {
position = marker!!.position
if (posUpdate.latitude != position.latitude || posUpdate.longitude != position.longitude) {
val newpos = GeoPoint(posUpdate.latitude, posUpdate.longitude)
val valueAnimator = MarkerUtils.makeMarkerAnimator(
map, marker, newpos, MarkerUtils.LINEAR_ANIMATION, 1200
)
valueAnimator.setAutoCancel(true)
tripMarkersAnimators[updateID] = valueAnimator
valueAnimator.start()
}
//marker.setPosition(new GeoPoint(posUpdate.getLatitude(), posUpdate.getLongitude()));
} else {
position = GeoPoint(posUpdate.latitude, posUpdate.longitude)
marker!!.position = position
}
if (posUpdate.bearing != null) marker.rotation = posUpdate.bearing * -1f
}
private fun updateBusPositionsInMap(tripsPatterns: HashMap>) {
Log.d(DEBUG_TAG, "Updating positions of the buses")
//if(busPositionsOverlay == null) busPositionsOverlay = new FolderOverlay();
val noPatternsTrips = ArrayList()
for (tripID in tripsPatterns.keys) {
val (update, tripWithPatternStops) = tripsPatterns[tripID] ?: continue
//check if Marker is already created
if (busPositionMarkersByTrip.containsKey(tripID)) {
//need to change the position of the marker
val marker = busPositionMarkersByTrip[tripID]!!
updateBusMarker(marker, update, false)
if (marker.infoWindow != null && marker.infoWindow is BusInfoWindow) {
val window = marker.infoWindow as BusInfoWindow
if (tripWithPatternStops != null) {
//Log.d(DEBUG_TAG, "Update pattern for trip: "+tripID);
window.setPatternAndDraw(tripWithPatternStops.pattern)
}
}
} else {
//marker is not there, need to make it
if (map == null) Log.e(
DEBUG_TAG,
"Creating marker with null map, things will explode"
)
val marker = Marker(map)
/*final Drawable mDrawable = DrawableUtils.Companion.getScaledDrawableResources(
getResources(),
R.drawable.point_heading_icon,
R.dimen.map_icons_size, R.dimen.map_icons_size);
*/
//String route = GtfsUtils.getLineNameFromGtfsID(update.getRouteID());
val mdraw =
ResourcesCompat.getDrawable(resources, R.drawable.map_bus_position_icon, null)!!
//mdraw.setBounds(0,0,28,28);
marker.icon = mdraw
if (tripWithPatternStops == null) {
noPatternsTrips.add(tripID)
}
var markerPattern: MatoPattern? = null
if (tripWithPatternStops != null && tripWithPatternStops.pattern != null) markerPattern =
tripWithPatternStops.pattern
marker.infoWindow =
BusInfoWindow(map!!, update, markerPattern, false) { pattern: MatoPattern? -> }
marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
updateBusMarker(marker, update, true)
// the overlay is null when it's not attached yet?5
// cannot recreate it because it becomes null very soon
// if(busPositionsOverlay == null) busPositionsOverlay = new FolderOverlay();
//save the marker
if (busPositionsOverlay != null) {
busPositionsOverlay!!.add(marker)
busPositionMarkersByTrip[tripID] = marker
}
}
}
if (noPatternsTrips.size > 0) {
Log.i(DEBUG_TAG, "These trips have no matching pattern: $noPatternsTrips")
}
}
/**
* Add stops as Markers on the map
* @param stops the list of stops that must be included
*/
protected fun showStopsMarkers(stops: List?) {
if (context == null || stops == null) {
//we are not attached
return
}
var good = true
for (stop in stops) {
if (shownStops!!.contains(stop.ID)) {
continue
}
if (stop.longitude == null || stop.latitude == null) continue
shownStops!!.add(stop.ID)
if (!map!!.isShown) {
if (good) Log.d(
DEBUG_TAG,
"Need to show stop but map is not shown, probably detached already"
)
good = false
continue
} else if (map!!.repository == null) {
Log.e(DEBUG_TAG, "Map view repository is null")
}
val marker = GeoPoint(stop.latitude!!, stop.longitude!!)
val stopMarker = makeMarker(marker, stop, false)
stopsFolderOverlay!!.add(stopMarker)
if (!map!!.overlays.contains(stopsFolderOverlay)) {
Log.w(DEBUG_TAG, "Map doesn't have folder overlay")
}
good = true
}
//Log.d(DEBUG_TAG,"We have " +stopsFolderOverlay.getItems().size()+" stops in the folderOverlay");
//force redraw of markers
map!!.invalidate()
}
fun makeMarker(geoPoint: GeoPoint?, stop: Stop, isStartMarker: Boolean): Marker {
return makeMarker(
geoPoint, stop.ID,
stop.stopDefaultName,
stop.routesThatStopHereToString(), isStartMarker
)
}
fun makeMarker(
geoPoint: GeoPoint?, stopID: String?, stopName: String?,
routesStopping: String?, isStartMarker: Boolean
): Marker {
// add a marker
val marker = Marker(map)
// set custom info window as info window
val popup = CustomInfoWindow(
map, stopID, stopName, routesStopping,
responder, R.layout.linedetail_stop_infowindow, R.color.red_darker
)
marker.infoWindow = popup
// make the marker clickable
marker.setOnMarkerClickListener { thisMarker: Marker, mapView: MapView? ->
if (thisMarker.isInfoWindowOpen) {
// on second click
Log.w(DEBUG_TAG, "Pressed on the click marker")
} else {
// on first click
// hide all opened info window
InfoWindow.closeAllInfoWindowsOn(map)
// show this particular info window
thisMarker.showInfoWindow()
// move the map to its position
map!!.controller.animateTo(thisMarker.position)
}
true
}
// set its position
marker.position = geoPoint
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
// add to it an icon
//marker.setIcon(getResources().getDrawable(R.drawable.bus_marker));
marker.icon = ResourcesCompat.getDrawable(resources, R.drawable.bus_stop, ctx!!.theme)
// add to it a title
marker.title = stopName
// set the description as the ID
marker.snippet = stopID
// show popup info window of the searched marker
if (isStartMarker) {
marker.showInfoWindow()
//map.getController().animateTo(marker.getPosition());
}
return marker
}
override fun getBaseViewForSnackBar(): View? {
return coordLayout
}
companion object {
//private static final String TAG = "Busto-MapActivity";
private const val MAP_CURRENT_ZOOM_KEY = "map-current-zoom"
private const val MAP_CENTER_LAT_KEY = "map-center-lat"
private const val MAP_CENTER_LON_KEY = "map-center-lon"
private const val FOLLOWING_LOCAT_KEY = "following"
const val BUNDLE_LATIT = "lat"
const val BUNDLE_LONGIT = "lon"
const val BUNDLE_NAME = "name"
const val BUNDLE_ID = "ID"
const val BUNDLE_ROUTES_STOPPING = "routesStopping"
const val FRAGMENT_TAG = "BusTOMapFragment"
private const val DEFAULT_CENTER_LAT = 45.0708
private const val DEFAULT_CENTER_LON = 7.6858
private const val POSITION_FOUND_ZOOM = 18.3
const val NO_POSITION_ZOOM = 17.1
private const val DEBUG_TAG = FRAGMENT_TAG
@JvmStatic
fun getInstance(): MapFragmentKt {
return MapFragmentKt()
}
@JvmStatic
fun getInstance(stop: Stop): MapFragmentKt {
val fragment = MapFragmentKt()
val args = Bundle()
args.putDouble(MapFragment.BUNDLE_LATIT, stop.latitude!!)
args.putDouble(MapFragment.BUNDLE_LONGIT, stop.longitude!!)
args.putString(MapFragment.BUNDLE_NAME, stop.stopDisplayName)
args.putString(MapFragment.BUNDLE_ID, stop.ID)
args.putString(MapFragment.BUNDLE_ROUTES_STOPPING, stop.routesThatStopHereToString())
fragment.arguments = args
return fragment
}
}
}
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
index de3c814..3ce278c 100644
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
@@ -1,363 +1,366 @@
package it.reyboz.bustorino.fragments
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.Drawable
import android.location.Location
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.google.gson.JsonObject
import it.reyboz.bustorino.R
import it.reyboz.bustorino.backend.Stop
import it.reyboz.bustorino.map.Styles
+import it.reyboz.bustorino.util.ViewUtils
import it.reyboz.bustorino.viewmodels.StopsMapViewModel
import org.maplibre.android.MapLibre
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.maps.MapView
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.geometry.LatLngBounds
import org.maplibre.android.location.LocationComponent
import org.maplibre.android.location.LocationComponentActivationOptions
import org.maplibre.android.location.LocationComponentOptions
import org.maplibre.android.location.engine.LocationEngineRequest
import org.maplibre.android.location.modes.CameraMode
import org.maplibre.android.maps.MapLibreMap
import org.maplibre.android.maps.OnMapReadyCallback
import org.maplibre.android.maps.Style
import org.maplibre.android.style.layers.PropertyFactory
import org.maplibre.android.style.layers.SymbolLayer
import org.maplibre.android.style.sources.GeoJsonSource
import org.maplibre.geojson.Feature
import org.maplibre.geojson.FeatureCollection
import org.maplibre.geojson.Point
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [MapLibreFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class MapLibreFragment : Fragment(), OnMapReadyCallback {
//private var param1: String? = null
//private var param2: String? = null
// Declare a variable for MapView
private lateinit var mapView: MapView
private lateinit var locationComponent: LocationComponent
private var lastLocation: Location? = null
private val stopsViewModel: StopsMapViewModel by viewModels()
private val gson = Gson()
private var stopsShowing = ArrayList(0)
protected var map: MapLibreMap? = null
// Sources for stops and buses
private lateinit var stopsSource: GeoJsonSource
private lateinit var busesSource: GeoJsonSource
private var isStopsLayerStarted = false
private var lastStopsSizeShown = 0
private var lastBBox = LatLngBounds.from(2.0, 2.0, 1.0,1.0)
private lateinit var mapStyle: Style
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
*/
MapLibre.getInstance(requireContext())
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val rootView = inflater.inflate(R.layout.fragment_map_libre,
container, false)
// Init layout view
// Init the MapView
mapView = rootView.findViewById(R.id.libreMapView)
mapView.getMapAsync(this) //{ //map ->
//map.setStyle("https://demotiles.maplibre.org/style.json") }
return rootView
}
override fun onMapReady(mapReady: MapLibreMap) {
this.map = mapReady
mapReady.cameraPosition = CameraPosition.Builder().target(LatLng(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON)).zoom(
15.0).build()
+ val mjson = Styles.getJsonStyleFromAsset(requireContext(), "map_style_good_noshops.json")//ViewUtils.loadJsonFromAsset(requireContext(),"map_style_good.json")
activity?.run {
- mapReady.setStyle(Styles.CARTO_VOYAGER ) { style ->
+
+ mapReady.setStyle(Style.Builder().fromJson(mjson!!)) { style ->
mapStyle = style
setupLayers(style)
// Start observing data
observeViewModels()
initLocation(style, mapReady, requireContext())
}
mapReady.addOnCameraIdleListener {
map?.let {
val newBbox = it.projection.visibleRegion.latLngBounds
if ((newBbox.center==lastBBox.center) && (newBbox.latitudeSpan==lastBBox.latitudeSpan) && (newBbox.longitudeSpan==lastBBox.latitudeSpan)){
//do nothing
} else {
stopsViewModel.loadStopsInLatLngBounds(newBbox)
lastBBox = newBbox
}
}
}
//makeStyleMapBoxUrl(false))
}
}
@SuppressLint("MissingPermission")
private fun initLocation(style: Style, map: MapLibreMap, context: Context){
locationComponent = map.locationComponent
val locationComponentOptions =
LocationComponentOptions.builder(context)
.pulseEnabled(true)
.build()
val locationComponentActivationOptions =
buildLocationComponentActivationOptions(style, locationComponentOptions, context)
locationComponent.activateLocationComponent(locationComponentActivationOptions)
locationComponent.isLocationComponentEnabled = true
locationComponent.cameraMode = CameraMode.TRACKING //CameraMode.TRACKING
locationComponent.forceLocationUpdate(lastLocation)
}
private fun buildLocationComponentActivationOptions(
style: Style,
locationComponentOptions: LocationComponentOptions,
context: Context
): LocationComponentActivationOptions {
return LocationComponentActivationOptions
.builder(context, style)
.locationComponentOptions(locationComponentOptions)
.useDefaultLocationEngine(true)
.locationEngineRequest(
LocationEngineRequest.Builder(750)
.setFastestInterval(750)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build()
)
.build()
}
private fun startLayerStops(style: Style, features:FeatureCollection){
stopsSource = GeoJsonSource(STOPS_SOURCE_ID,features)
style.addSource(stopsSource)
// add icon
style.addImage(STOP_IMAGE_ID,
ResourcesCompat.getDrawable(resources,R.drawable.bus_stop, activity?.theme)!!)
// Stops layer
val stopsLayer = SymbolLayer(STOPS_LAYER_ID, STOPS_SOURCE_ID)
stopsLayer.withProperties(
PropertyFactory.iconImage(STOP_IMAGE_ID),
PropertyFactory.iconAllowOverlap(true),
PropertyFactory.iconIgnorePlacement(true)
)
style.addLayerBelow(stopsLayer, "label_country_1")
isStopsLayerStarted = true
}
/**
* Setup the Map Layers
*/
private fun setupLayers(style: Style) {
// Stops source
// Buses source
// TODO when adding the buses
//busesSource = GeoJsonSource(BUSES_SOURCE_ID)
//style.addSource(busesSource)
/*
// TODO when adding the buses
// Buses layer
val busesLayer = SymbolLayer(BUSES_LAYER_ID, BUSES_SOURCE_ID).apply {
withProperties(
PropertyFactory.iconImage("bus"),
PropertyFactory.iconSize(1.0f),
PropertyFactory.iconAllowOverlap(true),
PropertyFactory.iconRotate(Expression.get("bearing"))
)
}
style.addLayer(busesLayer)
*/
}
/**
* Incremental updates of the layers
*/
fun updateLayerIncrementally(newPoints: List, layerSourceId: String) {
val source = map?.style?.getSourceAs(layerSourceId) ?: return
//source.querySourceFeatures(null)
// Get existing features
val existingFeatures = source.querySourceFeatures(null).toMutableList()
// Add new features
val newFeatures = newPoints.map { point ->
Feature.fromGeometry(point)
}
existingFeatures.addAll(newFeatures)
// Update source
source.setGeoJson(FeatureCollection.fromFeatures(existingFeatures))
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
private fun observeViewModels() {
// Observe stops
stopsViewModel.stopsToShow.observe(viewLifecycleOwner) { stops ->
stopsShowing = stops
displayStops(stops)
}
}
/**
* Add the stops to the layers
*/
private fun displayStops(stops: List?) {
if (stops.isNullOrEmpty()) return
if (stops.size==lastStopsSizeShown){
Log.d(DEBUG_TAG, "Not updating, we have the same stop (can only increase!)")
return
}
val features = stops.mapNotNull { stop ->
stop.latitude?.let { lat ->
stop.longitude?.let { lon ->
Feature.fromGeometry(
Point.fromLngLat(lon, lat),
JsonObject().apply {
addProperty("id", stop.ID)
addProperty("name", stop.stopDefaultName)
addProperty("routes", stop.routesThatStopHereToString()) // Add routes array to JSON object
}
)
}
}
}
Log.d(DEBUG_TAG,"Have put ${features.size} stops to display")
if (isStopsLayerStarted) {
stopsSource.setGeoJson(FeatureCollection.fromFeatures(features))
lastStopsSizeShown = features.size
} else
map?.let { startLayerStops(mapStyle, FeatureCollection.fromFeatures(features))
Log.d(DEBUG_TAG,"Started stops layer on map")
lastStopsSizeShown = features.size
}
}
companion object {
private const val STOPS_SOURCE_ID = "stops-source"
private const val STOPS_LAYER_ID = "stops-layer"
private const val BUSES_SOURCE_ID = "buses-source"
private const val BUSES_LAYER_ID = "buses-layer"
private const val STOP_IMAGE_ID ="bus-stop-icon"
private const val DEFAULT_CENTER_LAT = 45.0708
private const val DEFAULT_CENTER_LON = 7.6858
private const val POSITION_FOUND_ZOOM = 16.5
private const val NO_POSITION_ZOOM = 17.1
private const val ACCESS_TOKEN="KxO8lF4U3kiO63m0c7lzqDCDrMUVg1OA2JVzRXxxmYSyjugr1xpe4W4Db5rFNvbQ"
private const val MAPLIBRE_URL = "https://api.jawg.io/styles/"
private const val DEBUG_TAG = "BusTO-MapLibreFrag"
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment MapLibreFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
MapLibreFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
private fun makeStyleUrl(style: String = "jawg-streets") =
"${MAPLIBRE_URL+ style}.json?access-token=${ACCESS_TOKEN}"
private fun makeStyleMapBoxUrl(dark: Boolean) =
if(dark)
"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
else //"https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"
"https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
const val OPENFREEMAP_LIBERY = "https://tiles.openfreemap.org/styles/liberty"
const val OPENFREEMAP_BRIGHT = "https://tiles.openfreemap.org/styles/bright"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/it/reyboz/bustorino/map/Styles.kt b/app/src/main/java/it/reyboz/bustorino/map/Styles.kt
index d797f66..8c76ada 100644
--- a/app/src/main/java/it/reyboz/bustorino/map/Styles.kt
+++ b/app/src/main/java/it/reyboz/bustorino/map/Styles.kt
@@ -1,50 +1,56 @@
package it.reyboz.bustorino.map
+import android.content.Context
+import it.reyboz.bustorino.util.ViewUtils
import org.maplibre.android.maps.Style
object Styles {
const val DEMOTILES = "https://demotiles.maplibre.org/style.json"
const val VERSATILES = "https://tiles.versatiles.org/assets/styles/colorful.json"
const val AMERICANA = "https://americanamap.org/style.json"
- const val OPENFREEMAP_LIBERY = "https://tiles.openfreemap.org/styles/liberty"
+ const val OPENFREEMAP_LIBERTY = "https://tiles.openfreemap.org/styles/liberty"
const val OPENFREEMAP_BRIGHT = "https://tiles.openfreemap.org/styles/bright"
+ const val BASIC_V8 = "mapbox://styles/mapbox/streets-v8"
+
+
const val AWS_OPEN_DATA_STANDARD_LIGHT =
"https://maps.geo.us-east-2.amazonaws.com/maps/v0/maps/OpenDataStyle/style-descriptor?key=v1.public.eyJqdGkiOiI1NjY5ZTU4My0yNWQwLTQ5MjctODhkMS03OGUxOTY4Y2RhMzgifR_7GLT66TNRXhZJ4KyJ-GK1TPYD9DaWuc5o6YyVmlikVwMaLvEs_iqkCIydspe_vjmgUVsIQstkGoInXV_nd5CcmqRMMa-_wb66SxDdbeRDvmmkpy2Ow_LX9GJDgL2bbiCws0wupJPFDwWCWFLwpK9ICmzGvNcrPbX5uczOQL0N8V9iUvziA52a1WWkZucIf6MUViFRf3XoFkyAT15Ll0NDypAzY63Bnj8_zS8bOaCvJaQqcXM9lrbTusy8Ftq8cEbbK5aMFapXRjug7qcrzUiQ5sr0g23qdMvnKJQFfo7JuQn8vwAksxrQm6A0ByceEXSfyaBoVpFcTzEclxUomhY.NjAyMWJkZWUtMGMyOS00NmRkLThjZTMtODEyOTkzZTUyMTBi"
private fun protomaps(style: String): String {
return "https://api.protomaps.com/styles/v2/${style}.json?key=e761cc7daedf832a"
}
private fun makeStyleMapBoxUrl(dark: Boolean) =
if (dark)
"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
else //"https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"
"https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
val PROTOMAPS_LIGHT = protomaps("light")
val PROTOMAPS_DARK = protomaps("dark")
val PROTOMAPS_GRAYSCALE = protomaps("grayscale")
val PROTOMAPS_WHITE = protomaps("white")
val PROTOMAPS_BLACK = protomaps("black")
val CARTO_DARK = makeStyleMapBoxUrl(true)
val CARTO_VOYAGER = makeStyleMapBoxUrl(false)
fun getPredefinedStyleWithFallback(name: String): String {
try {
val style = Style.getPredefinedStyle(name)
return style
} catch (e: Exception) {
- return OPENFREEMAP_LIBERY
+ return OPENFREEMAP_LIBERTY
}
}
+ fun getJsonStyleFromAsset(context: Context, filename: String) = ViewUtils.loadJsonFromAsset(context,filename)
}
\ No newline at end of file
diff --git a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt
index bb4071c..0a3947a 100644
--- a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt
+++ b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt
@@ -1,109 +1,119 @@
package it.reyboz.bustorino.util
import android.R
import android.content.Context
import android.content.res.Resources.Theme
import android.graphics.Rect
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.view.WindowManager
import android.view.animation.Animation
import android.view.animation.Transformation
import androidx.annotation.ColorInt
import androidx.core.widget.NestedScrollView
+import java.io.IOException
class ViewUtils {
companion object{
const val DEBUG_TAG="BusTO:ViewUtils"
fun isViewFullyVisibleInScroll(view: View, scrollView: NestedScrollView): Boolean {
val scrollBounds = Rect()
scrollView.getDrawingRect(scrollBounds)
val top = view.y
val bottom = top + view.height
Log.d(DEBUG_TAG, "Scroll bounds are $scrollBounds, top:${view.y}, bottom $bottom")
return (scrollBounds.top < top && scrollBounds.bottom > bottom)
}
fun isViewPartiallyVisibleInScroll(view: View, scrollView: NestedScrollView): Boolean{
val scrollBounds = Rect()
scrollView.getHitRect(scrollBounds)
Log.d(DEBUG_TAG, "Scroll bounds are $scrollBounds")
if (view.getLocalVisibleRect(scrollBounds)) {
return true
} else {
return false
}
}
//from https://stackoverflow.com/questions/4946295/android-expand-collapse-animation
fun expand(v: View,duration: Long, layoutHeight: Int = WindowManager.LayoutParams.WRAP_CONTENT) {
val matchParentMeasureSpec =
View.MeasureSpec.makeMeasureSpec((v.parent as View).width, View.MeasureSpec.EXACTLY)
val wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
v.measure(matchParentMeasureSpec, wrapContentMeasureSpec)
val targetHeight = v.measuredHeight
// Older versions of android (pre API 21) cancel animations for views with a height of 0.
v.layoutParams.height = 1
v.visibility = View.VISIBLE
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
v.layoutParams.height =
if (interpolatedTime == 1f) layoutHeight
else (targetHeight * interpolatedTime).toInt()
v.requestLayout()
}
override fun willChangeBounds(): Boolean {
return true
}
}
// Expansion speed of 1dp/ms
if(duration == DEF_DURATION)
a.duration = (targetHeight / v.context.resources.displayMetrics.density).toInt().toLong()
else
a.duration = duration
v.startAnimation(a)
}
fun collapse(v: View, duration: Long): Animation {
val initialHeight = v.measuredHeight
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
if (interpolatedTime == 1f) {
v.visibility = View.GONE
} else {
v.layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
v.requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
}
}
// Collapse speed of 1dp/ms
if (duration == DEF_DURATION)
a.duration = (initialHeight / v.context.resources.displayMetrics.density).toInt().toLong()
else
a.duration = duration
v.startAnimation(a)
return a
}
const val DEF_DURATION: Long = -2
fun getColorFromTheme(context: Context, resId: Int): Int {
val typedValue = TypedValue()
val theme: Theme = context.getTheme()
theme.resolveAttribute(resId, typedValue, true)
val color = typedValue.data
return color
}
+ fun loadJsonFromAsset(context: Context, fileName: String): String? {
+ return try {
+ context.assets.open(fileName).bufferedReader().use { it.readText() }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ null
+ }
+ }
+
}
}
\ No newline at end of file