diff --git a/src/config/config.ts b/src/config/config.ts index 4adf8f5..628f290 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -7,7 +7,7 @@ import { setStoredTokens, } from "@/auth/tokenStore" -const baseURL = API_URL_ROOT || "https://history-api.kain.id.vn" +const baseURL = API_URL_ROOT const api = axios.create({ baseURL, diff --git a/src/uhm/api/config.ts b/src/uhm/api/config.ts index 90cc619..ac0cec8 100644 --- a/src/uhm/api/config.ts +++ b/src/uhm/api/config.ts @@ -1,9 +1,50 @@ -// Production BackEndGo API base URL. -// For local development, override with NEXT_PUBLIC_API_BASE_URL (e.g. http://localhost:3344). -const FALLBACK_API_BASE_URL = "https://history-api.kain.id.vn"; +import { API_URL_ROOT } from "../../../api"; -export const API_BASE_URL = - process.env.NEXT_PUBLIC_API_BASE_URL || FALLBACK_API_BASE_URL; +const GOONG_TILES_BASE_URL = "https://tiles.goong.io"; + +export const API_BASE_URL = normalizeApiBaseUrl(API_URL_ROOT); +const GOONG_PROXY_BASE_PATH = `${API_BASE_URL}/proxy`; + +export const GOONG_SATELLITE_STYLE_UPSTREAM_URL = `${GOONG_TILES_BASE_URL}/assets/goong_satellite.json`; +export const GOONG_VECTOR_OVERLAY_STYLE_UPSTREAM_URL = `${GOONG_TILES_BASE_URL}/assets/goong_map_web.json`; +export const GOONG_GLYPHS_UPSTREAM_URL = `${GOONG_TILES_BASE_URL}/fonts/{fontstack}/{range}.pbf`; + +export const USE_EXTERNAL_BACKGROUND_RASTER = API_BASE_URL.length > 0; + +function normalizeApiBaseUrl(rawUrl: string): string { + return rawUrl.trim().replace(/\/+$/, ""); +} + +export function stripGoongApiKeyFromUrl(rawUrl: string): string { + const [basePart, hashPart = ""] = rawUrl.split("#", 2); + const [pathPart, queryString = ""] = basePart.split("?", 2); + const sanitizedQuery = queryString + .split("&") + .filter((segment) => segment && !segment.toLowerCase().startsWith("api_key=")) + .join("&"); + + return `${pathPart}${sanitizedQuery ? `?${sanitizedQuery}` : ""}${hashPart ? `#${hashPart}` : ""}`; +} + +export function buildGoongProxyUrl(rawUrl: string): string { + const sanitizedUrl = stripGoongApiKeyFromUrl(rawUrl); + const templateTokens: string[] = []; + const tokenizedUrl = sanitizedUrl.replace(/\{[^}]+\}/g, (match) => { + const tokenId = `__UHM_GOONG_URL_TOKEN_${templateTokens.length}__`; + templateTokens.push(match); + return tokenId; + }); + + let encodedUrl = encodeURIComponent(tokenizedUrl); + templateTokens.forEach((token, index) => { + const encodedTokenId = encodeURIComponent(`__UHM_GOONG_URL_TOKEN_${index}__`); + encodedUrl = encodedUrl.replace(encodedTokenId, token); + }); + + return `${GOONG_PROXY_BASE_PATH}/${encodedUrl}`; +} + +export const GOONG_GLYPHS_PROXY_URL = buildGoongProxyUrl(GOONG_GLYPHS_UPSTREAM_URL); export const API_ENDPOINTS = { geometries: `${API_BASE_URL}/geometries`, @@ -18,8 +59,4 @@ export const API_ENDPOINTS = { currentUserProjects: `${API_BASE_URL}/users/current/project`, projects: `${API_BASE_URL}/projects`, submissions: `${API_BASE_URL}/submissions`, - vectorTiles: `${API_BASE_URL}/tiles/{z}/{x}/{y}`, - rasterTiles: `${API_BASE_URL}/raster-tiles/{z}/{x}/{y}`, - vectorTilesMetadata: `${API_BASE_URL}/tiles/metadata`, - rasterTilesMetadata: `${API_BASE_URL}/raster-tiles/metadata`, } as const; diff --git a/src/uhm/api/tiles.ts b/src/uhm/api/tiles.ts index 3f76442..48ed99d 100644 --- a/src/uhm/api/tiles.ts +++ b/src/uhm/api/tiles.ts @@ -1,20 +1,584 @@ -import { API_ENDPOINTS } from "@/uhm/api/config"; -import { requestJson } from "@/uhm/api/http"; +import { + buildGoongProxyUrl, + GOONG_SATELLITE_STYLE_UPSTREAM_URL, + GOONG_VECTOR_OVERLAY_STYLE_UPSTREAM_URL, + USE_EXTERNAL_BACKGROUND_RASTER, +} from "@/uhm/api/config"; +import { GOONG_LABEL_FALLBACK_FONT_STACK } from "@/uhm/lib/map/styles/shared/textFonts"; +import maplibregl from "maplibre-gl"; -export type TileMetadata = Record; +export type GoongBackgroundGroupId = + | "bg-country-borders-line" + | "bg-province-borders-line" + | "bg-district-borders-line" + | "country-labels" + | "rivers-line"; -export function getVectorTileTemplateUrl(): string { - return API_ENDPOINTS.vectorTiles; +type GoongStyleSource = { + type?: string; + url?: string; + tiles?: string[]; + tileSize?: number; + attribution?: string; + bounds?: number[]; + scheme?: "xyz" | "tms"; + minzoom?: number; + maxzoom?: number; +}; + +type GoongSourceManifest = { + tiles?: string[]; + tileSize?: number; + pixel_scale?: number | string; + attribution?: string; + bounds?: number[]; + scheme?: "xyz" | "tms"; + minzoom?: number; + maxzoom?: number; +}; + +type GoongStyleDocument = { + glyphs?: string; + sprite?: string; + sources?: Record; + layers?: maplibregl.LayerSpecification[]; +}; + +let externalRasterSourcePromise: Promise | null = null; +let goongOverlayBundlePromise: Promise | null = null; +const goongStyleDocumentPromises = new Map>(); +const goongSourceSpecificationPromises = new Map>(); + +type GoongBackgroundOverlayBundle = { + sources: Record; + layers: maplibregl.LayerSpecification[]; +}; + +export async function getBackgroundRasterSourceSpecification(): Promise { + if (!USE_EXTERNAL_BACKGROUND_RASTER) { + throw new Error("NEXT_PUBLIC_API_URL_ROOT is not configured."); + } + + if (!externalRasterSourcePromise) { + externalRasterSourcePromise = loadGoongRasterSourceSpecification( + GOONG_SATELLITE_STYLE_UPSTREAM_URL + ); + } + + try { + return await externalRasterSourcePromise; + } catch (error) { + externalRasterSourcePromise = null; + throw error; + } } -export function getRasterTileTemplateUrl(): string { - return API_ENDPOINTS.rasterTiles; +export async function getGoongBackgroundOverlayBundle(): Promise { + if (!USE_EXTERNAL_BACKGROUND_RASTER) { + throw new Error("NEXT_PUBLIC_API_URL_ROOT is not configured."); + } + + if (!goongOverlayBundlePromise) { + goongOverlayBundlePromise = loadGoongBackgroundOverlayBundle( + GOONG_VECTOR_OVERLAY_STYLE_UPSTREAM_URL + ); + } + + try { + return await goongOverlayBundlePromise; + } catch (error) { + goongOverlayBundlePromise = null; + throw error; + } } -export async function fetchVectorTilesMetadata(): Promise { - return requestJson(API_ENDPOINTS.vectorTilesMetadata); +async function loadGoongRasterSourceSpecification( + styleUpstreamUrl: string +): Promise { + const style = await loadGoongStyleDocument(styleUpstreamUrl); + const sources = style.sources || {}; + + for (const source of Object.values(sources)) { + if (source.type !== "raster") continue; + + const spec = await normalizeGoongSourceSpecification(source, styleUpstreamUrl); + if (spec.type === "raster" && (spec.tiles?.length || "url" in spec)) { + return spec; + } + } + + throw new Error("No raster source found in Goong satellite style."); } -export async function fetchRasterTilesMetadata(): Promise { - return requestJson(API_ENDPOINTS.rasterTilesMetadata); +async function loadGoongBackgroundOverlayBundle( + styleUpstreamUrl: string +): Promise { + const style = await loadGoongStyleDocument(styleUpstreamUrl); + const layers = style.layers || []; + const sources = style.sources || {}; + const layerById = new Map(layers.map((layer) => [layer.id, layer])); + const selectedLayersByGroup = new Map([ + ["bg-country-borders-line", []], + ["bg-province-borders-line", []], + ["bg-district-borders-line", []], + ["rivers-line", []], + ["country-labels", []], + ]); + + for (const rawLayer of layers) { + const resolvedLayer = resolveLayerReference(rawLayer, layerById); + const groupId = detectGoongBackgroundGroup(resolvedLayer); + if (!groupId) continue; + selectedLayersByGroup.get(groupId)?.push(resolvedLayer); + } + + const selectedSourceIds = new Set(); + for (const groupLayers of selectedLayersByGroup.values()) { + for (const layer of groupLayers) { + if ("source" in layer && typeof layer.source === "string") { + selectedSourceIds.add(layer.source); + } + } + } + + if (selectedSourceIds.size === 0) { + return null; + } + + const sourceIdMap = new Map(); + const overlaySources: Record = {}; + const overlaySourceEntries = await Promise.all( + [...selectedSourceIds].map(async (sourceId) => { + const source = sources[sourceId]; + if (!source) { + return null; + } + + const prefixedId = `goong-overlay-${sourceId}`; + const normalizedSource = await normalizeGoongSourceSpecification( + source, + styleUpstreamUrl + ); + + return { sourceId, prefixedId, normalizedSource }; + }) + ); + + for (const entry of overlaySourceEntries) { + if (!entry) continue; + sourceIdMap.set(entry.sourceId, entry.prefixedId); + overlaySources[entry.prefixedId] = entry.normalizedSource; + } + + const overlayLayers: maplibregl.LayerSpecification[] = []; + for (const groupId of [ + "rivers-line", + "bg-country-borders-line", + "bg-province-borders-line", + "bg-district-borders-line", + "country-labels", + ] as const) { + const groupLayers = [...(selectedLayersByGroup.get(groupId) || [])].sort(compareOverlayLayers); + groupLayers.forEach((layer, index) => { + overlayLayers.push( + cloneOverlayLayer(layer, { + id: `goong-${groupId}-${index}`, + groupId, + sourceIdMap, + }) + ); + }); + } + + return { + sources: overlaySources, + layers: overlayLayers, + }; +} + +async function loadGoongStyleDocument(styleUpstreamUrl: string): Promise { + const existingPromise = goongStyleDocumentPromises.get(styleUpstreamUrl); + if (existingPromise) { + return existingPromise; + } + + const styleProxyUrl = buildGoongProxyUrl(styleUpstreamUrl); + const promise = fetch(styleProxyUrl, { cache: "force-cache" }) + .then(async (response) => { + if (!response.ok) { + throw new Error(`Goong style request failed with status ${response.status}`); + } + return (await response.json()) as GoongStyleDocument; + }); + goongStyleDocumentPromises.set(styleUpstreamUrl, promise); + + try { + return await promise; + } catch (error) { + goongStyleDocumentPromises.delete(styleUpstreamUrl); + throw error; + } +} + +async function loadGoongSourceSpecification( + sourceUpstreamUrl: string, + parentSource: GoongStyleSource +): Promise { + const cacheKey = JSON.stringify({ + sourceUpstreamUrl, + type: parentSource.type, + tileSize: parentSource.tileSize, + minzoom: parentSource.minzoom, + maxzoom: parentSource.maxzoom, + }); + const existingPromise = goongSourceSpecificationPromises.get(cacheKey); + if (existingPromise) { + return existingPromise; + } + + const sourceProxyUrl = buildGoongProxyUrl(sourceUpstreamUrl); + const promise = fetch(sourceProxyUrl, { cache: "force-cache" }) + .then(async (response) => { + if (!response.ok) { + throw new Error(`Goong source request failed with status ${response.status}`); + } + return (await response.json()) as GoongSourceManifest; + }) + .then((sourceDocument) => + normalizeManifestBackedGoongSourceSpecification(parentSource, sourceDocument, sourceUpstreamUrl) + ); + goongSourceSpecificationPromises.set(cacheKey, promise); + + try { + return await promise; + } catch (error) { + goongSourceSpecificationPromises.delete(cacheKey); + throw error; + } +} + +async function normalizeGoongSourceSpecification( + source: GoongStyleSource, + parentDocumentUrl: string +): Promise { + if (typeof source.url === "string" && source.url) { + const sourceUpstreamUrl = resolveGoongResourceUrl(source.url, parentDocumentUrl); + return loadGoongSourceSpecification(sourceUpstreamUrl, source); + } + + return normalizeInlineGoongSourceSpecification(source, parentDocumentUrl); +} + +function normalizeInlineGoongSourceSpecification( + source: GoongStyleSource, + parentDocumentUrl: string +): maplibregl.SourceSpecification { + return buildMapLibreSourceSpecification(source, parentDocumentUrl); +} + +function normalizeManifestBackedGoongSourceSpecification( + parentSource: GoongStyleSource, + sourceManifest: GoongSourceManifest, + sourceUpstreamUrl: string +): maplibregl.SourceSpecification { + const mergedSource: GoongStyleSource = { + ...parentSource, + attribution: sourceManifest.attribution ?? parentSource.attribution, + bounds: sourceManifest.bounds ?? parentSource.bounds, + maxzoom: sourceManifest.maxzoom ?? parentSource.maxzoom, + minzoom: sourceManifest.minzoom ?? parentSource.minzoom, + scheme: sourceManifest.scheme ?? parentSource.scheme, + tileSize: + sourceManifest.tileSize ?? + normalizeGoongTileSize(sourceManifest.pixel_scale) ?? + parentSource.tileSize, + tiles: sourceManifest.tiles ?? parentSource.tiles, + }; + + return buildMapLibreSourceSpecification(mergedSource, sourceUpstreamUrl); +} + +function buildMapLibreSourceSpecification( + source: GoongStyleSource, + parentDocumentUrl: string +): maplibregl.SourceSpecification { + const resolvedTiles = Array.isArray(source.tiles) + ? source.tiles.map((tileUrl) => { + const upstreamTileUrl = resolveGoongResourceUrl(tileUrl, parentDocumentUrl); + return buildGoongProxyUrl(upstreamTileUrl); + }) + : undefined; + + if (source.type === "raster") { + const rasterSource: maplibregl.RasterSourceSpecification = { + type: "raster", + ...(resolvedTiles?.length ? { tiles: resolvedTiles } : {}), + ...(typeof source.tileSize === "number" ? { tileSize: source.tileSize } : {}), + ...(typeof source.minzoom === "number" ? { minzoom: source.minzoom } : {}), + ...(typeof source.maxzoom === "number" ? { maxzoom: source.maxzoom } : {}), + ...(Array.isArray(source.bounds) ? { bounds: source.bounds as [number, number, number, number] } : {}), + ...(source.scheme ? { scheme: source.scheme } : {}), + ...(source.attribution ? { attribution: source.attribution } : {}), + }; + + return rasterSource; + } + + if (source.type === "vector") { + const vectorSource: maplibregl.VectorSourceSpecification = { + type: "vector", + ...(resolvedTiles?.length ? { tiles: resolvedTiles } : {}), + ...(typeof source.minzoom === "number" ? { minzoom: source.minzoom } : {}), + ...(typeof source.maxzoom === "number" ? { maxzoom: source.maxzoom } : {}), + ...(Array.isArray(source.bounds) ? { bounds: source.bounds as [number, number, number, number] } : {}), + ...(source.scheme ? { scheme: source.scheme } : {}), + ...(source.attribution ? { attribution: source.attribution } : {}), + }; + + return vectorSource; + } + + throw new Error(`Unsupported Goong source type: ${String(source.type || "unknown")}`); +} + +function normalizeGoongTileSize(value: number | string | undefined): number | undefined { + if (typeof value === "number" && Number.isFinite(value)) { + return value; + } + + if (typeof value === "string") { + const parsedValue = Number.parseInt(value, 10); + if (Number.isFinite(parsedValue)) { + return parsedValue; + } + } + + return undefined; +} + +function resolveLayerReference( + layer: maplibregl.LayerSpecification, + layerById: Map +): maplibregl.LayerSpecification { + const withRef = layer as maplibregl.LayerSpecification & { ref?: string }; + if (!withRef.ref) { + return deepClone(layer); + } + + const parent = layerById.get(withRef.ref); + if (!parent) { + return deepClone(layer); + } + + const resolvedParent = resolveLayerReference(parent, layerById); + const merged = { + ...resolvedParent, + ...deepClone(layer), + } as maplibregl.LayerSpecification & { + ref?: string; + layout?: Record; + paint?: Record; + metadata?: Record; + }; + + merged.layout = { + ...(resolvedParent as { layout?: Record }).layout, + ...(withRef as { layout?: Record }).layout, + }; + merged.paint = { + ...(resolvedParent as { paint?: Record }).paint, + ...(withRef as { paint?: Record }).paint, + }; + merged.metadata = { + ...(resolvedParent as { metadata?: Record }).metadata, + ...(withRef as { metadata?: Record }).metadata, + }; + delete merged.ref; + return merged; +} + +function detectGoongBackgroundGroup( + layer: maplibregl.LayerSpecification +): GoongBackgroundGroupId | null { + const haystack = [ + layer.id, + "source" in layer && typeof layer.source === "string" ? layer.source : "", + "source-layer" in layer && typeof layer["source-layer"] === "string" ? layer["source-layer"] : "", + ] + .join(" ") + .toLowerCase(); + + if (layer.type === "symbol" && hasTextField(layer) && isPreferredPlaceLabelLayer(haystack)) { + return "country-labels"; + } + + if (layer.type === "line") { + const boundaryGroup = detectBoundaryGroup(layer, haystack); + if (boundaryGroup) { + return boundaryGroup; + } + } + + if (layer.type === "line" && /(water|waterway|river|stream|canal)/.test(haystack)) { + return "rivers-line"; + } + + if (layer.type === "fill" && /(water|lake|reservoir|sea|ocean)/.test(haystack)) { + return "rivers-line"; + } + + return null; +} + +function hasTextField(layer: maplibregl.LayerSpecification): boolean { + const layout = (layer as { layout?: Record }).layout; + return Boolean(layout && "text-field" in layout && layout["text-field"]); +} + +function isPreferredPlaceLabelLayer(haystack: string): boolean { + if (/(poi|airport|station|transit|rail|metro|bus|road|street|highway|path|route)/.test(haystack)) { + return false; + } + + return /(country|state|province|district|admin|place|city|town|village|settlement|capital|label)/.test(haystack); +} + +function detectBoundaryGroup( + _layer: maplibregl.LayerSpecification, + haystack: string +): GoongBackgroundGroupId | null { + if (/(road|street|highway|path|route|rail|transit|water|waterway|river|stream|canal)/.test(haystack)) { + return null; + } + + if (!/(boundary|border|admin|country|state|province|district|ward|commune|county)/.test(haystack)) { + return null; + } + + // Goong's public styles expose the boundary hierarchy most clearly + // through boundary-land-type-{0,1,2}. Prefer these exact matches over + // keyword heuristics because the heuristic buckets were mixing levels. + if (/boundary-land-type-0/.test(haystack)) { + if (/boundary-land-type-0-bg/.test(haystack)) { + return null; + } + return "bg-country-borders-line"; + } + + if (/boundary-land-type-1/.test(haystack)) { + if (/boundary-land-type-1-bg/.test(haystack)) { + return null; + } + return "bg-province-borders-line"; + } + + if (/boundary-land-type-2/.test(haystack)) { + return "bg-district-borders-line"; + } + + const adminLevels = extractAdminLevels(haystack); + if (adminLevels.length > 0) { + const minAdminLevel = Math.min(...adminLevels); + if (minAdminLevel <= 2) return "bg-country-borders-line"; + if (minAdminLevel <= 5) return "bg-province-borders-line"; + return "bg-district-borders-line"; + } + + if (/(district|ward|commune|subdistrict|neighbou?rhood)/.test(haystack)) { + return "bg-district-borders-line"; + } + + if (/(province|state|region)/.test(haystack)) { + return "bg-province-borders-line"; + } + + if (/(country|national|international)/.test(haystack)) { + return "bg-country-borders-line"; + } + + return null; +} + +function extractAdminLevels(haystack: string): number[] { + const matches = Array.from( + haystack.matchAll(/(?:admin[_ -]?level|adminlevel|admin|level)[_ -]?(\d{1,2})/g) + ); + + return matches + .map((match) => Number.parseInt(match[1] || "", 10)) + .filter((value) => Number.isFinite(value)); +} + +function cloneOverlayLayer( + layer: maplibregl.LayerSpecification, + options: { + id: string; + groupId: GoongBackgroundGroupId; + sourceIdMap: Map; + } +): maplibregl.LayerSpecification { + const cloned = deepClone(layer) as maplibregl.LayerSpecification & { + source?: string; + layout?: Record; + metadata?: Record; + }; + + cloned.id = options.id; + if (typeof cloned.source === "string" && options.sourceIdMap.has(cloned.source)) { + cloned.source = options.sourceIdMap.get(cloned.source); + } + + cloned.metadata = { + ...(cloned.metadata || {}), + uhmBackgroundGroupId: options.groupId, + uhmBackgroundProvider: "goong", + }; + + if (options.groupId === "country-labels") { + const layout = { ...(cloned.layout || {}) }; + delete layout["icon-image"]; + delete layout["icon-size"]; + delete layout["icon-allow-overlap"]; + delete layout["icon-ignore-placement"]; + if (!Array.isArray(layout["text-font"])) { + layout["text-font"] = [...GOONG_LABEL_FALLBACK_FONT_STACK]; + } + cloned.layout = layout; + } + + return cloned; +} + +function compareOverlayLayers( + left: maplibregl.LayerSpecification, + right: maplibregl.LayerSpecification +): number { + const leftMinzoom = "minzoom" in left && typeof left.minzoom === "number" + ? left.minzoom + : -1; + const rightMinzoom = "minzoom" in right && typeof right.minzoom === "number" + ? right.minzoom + : -1; + + if (leftMinzoom !== rightMinzoom) { + return leftMinzoom - rightMinzoom; + } + + return left.id.localeCompare(right.id); +} + +function resolveGoongResourceUrl(value: string, parentDocumentUrl: string): string { + if (/^[a-z]+:\/\//i.test(value) || value.startsWith("data:")) { + return value; + } + + try { + return new URL(value, parentDocumentUrl).toString(); + } catch { + return value; + } +} + +function deepClone(value: T): T { + return JSON.parse(JSON.stringify(value)) as T; } diff --git a/src/uhm/components/map/mapUtils.ts b/src/uhm/components/map/mapUtils.ts index a192aca..137baa1 100644 --- a/src/uhm/components/map/mapUtils.ts +++ b/src/uhm/components/map/mapUtils.ts @@ -5,13 +5,12 @@ import { Feature, FeatureCollection, Geometry } from "@/uhm/lib/editor/state/use import { FEATURE_STATE_SOURCE_IDS, PATH_ARROW_ICON_ID, - RASTER_BASE_INSERT_BEFORE_LAYER_ID, RASTER_BASE_LAYER_ID, RASTER_BASE_SOURCE_ID, PATH_ARROW_SOURCE_ID } from "@/uhm/lib/map/constants"; import { PATH_RENDER_BY_TYPE } from "@/uhm/lib/map/styles/style"; -import { getRasterTileTemplateUrl } from "@/uhm/api/tiles"; +import { getBackgroundRasterSourceSpecification } from "@/uhm/api/tiles"; import { newId } from "@/uhm/lib/utils/id"; import { normalizeGeoTypeKey } from "@/uhm/lib/map/geo/geoTypeMap"; @@ -30,33 +29,46 @@ export function applyBackgroundLayerVisibility( for (const layer of BACKGROUND_LAYER_OPTIONS) { if (layer.id === RASTER_BASE_LAYER_ID) continue; - if (!map.getLayer(layer.id)) continue; - map.setLayoutProperty( - layer.id, - "visibility", - visibility[layer.id] ? "visible" : "none" - ); + const nextVisibility = visibility[layer.id] ? "visible" : "none"; + + if (map.getLayer(layer.id)) { + map.setLayoutProperty(layer.id, "visibility", nextVisibility); + } + + const groupedLayerIds = getBackgroundGroupLayerIds(map, layer.id); + for (const groupedLayerId of groupedLayerIds) { + if (!map.getLayer(groupedLayerId)) continue; + map.setLayoutProperty(groupedLayerId, "visibility", nextVisibility); + } } } export function syncRasterBaseVisibility(map: maplibregl.Map, shouldShow: boolean) { if (shouldShow) { - ensureRasterBaseLayer(map); + void ensureRasterBaseLayer(map).catch((error) => { + console.error("Failed to load proxied raster background.", error); + removeRasterBaseLayer(map); + }); return; } removeRasterBaseLayer(map); } -export function ensureRasterBaseLayer(map: maplibregl.Map) { +export async function ensureRasterBaseLayer(map: maplibregl.Map) { if (!map.getSource(RASTER_BASE_SOURCE_ID)) { - map.addSource(RASTER_BASE_SOURCE_ID, createRasterBaseSource()); + const source = await createRasterBaseSource(); + if (map.getSource(RASTER_BASE_SOURCE_ID)) { + // Another caller already added the source while we were waiting. + } else { + map.addSource(RASTER_BASE_SOURCE_ID, source); + } } + const beforeId = getRasterBaseInsertBeforeLayerId(map); if (!map.getLayer(RASTER_BASE_LAYER_ID)) { - const beforeId = map.getLayer(RASTER_BASE_INSERT_BEFORE_LAYER_ID) - ? RASTER_BASE_INSERT_BEFORE_LAYER_ID - : undefined; map.addLayer(createRasterBaseLayer(), beforeId); + } else if (beforeId && beforeId !== RASTER_BASE_LAYER_ID) { + map.moveLayer(RASTER_BASE_LAYER_ID, beforeId); } map.setLayoutProperty(RASTER_BASE_LAYER_ID, "visibility", "visible"); @@ -73,13 +85,7 @@ export function removeRasterBaseLayer(map: maplibregl.Map) { } export function createRasterBaseSource() { - return { - type: "raster" as const, - tiles: [getRasterTileTemplateUrl()], - tileSize: 256, - minzoom: 0, - maxzoom: 6, - }; + return getBackgroundRasterSourceSpecification(); } export function createRasterBaseLayer() { @@ -94,6 +100,30 @@ export function createRasterBaseLayer() { }; } +function getRasterBaseInsertBeforeLayerId(map: maplibregl.Map): string | undefined { + const style = map.getStyle(); + const layers = style?.layers || []; + + return layers.find((layer) => { + return layer.id !== "background" && layer.id !== RASTER_BASE_LAYER_ID; + })?.id; +} + +function getBackgroundGroupLayerIds( + map: maplibregl.Map, + groupId: string +): string[] { + const style = map.getStyle(); + if (!style?.layers?.length) return []; + + return style.layers + .filter((layer) => { + const metadata = (layer as { metadata?: Record }).metadata; + return metadata?.uhmBackgroundGroupId === groupId; + }) + .map((layer) => layer.id); +} + export function getSelectableLayers(map: maplibregl.Map): string[] { const selectableSources = ["countries", "places", PATH_ARROW_SOURCE_ID]; const style = map.getStyle(); diff --git a/src/uhm/components/map/useMapLayers.ts b/src/uhm/components/map/useMapLayers.ts index af9e322..cbfd9f8 100644 --- a/src/uhm/components/map/useMapLayers.ts +++ b/src/uhm/components/map/useMapLayers.ts @@ -1,20 +1,11 @@ -import { useEffect } from "react"; import maplibregl from "maplibre-gl"; -import { getVectorTileTemplateUrl } from "@/uhm/api/tiles"; -import { - COUNTRY_FILL_COLOR_EXPRESSION, - LINE_COLOR_BY_TYPE, - PATH_RENDER_BY_TYPE, - POLYGON_FILL_BY_TYPE, - POLYGON_OPACITY_BY_TYPE, - POLYGON_STROKE_BY_TYPE, -} from "@/uhm/lib/map/styles/style"; +import { GOONG_GLYPHS_PROXY_URL } from "@/uhm/api/config"; +import { getGoongBackgroundOverlayBundle } from "@/uhm/api/tiles"; import { EMPTY_FEATURE_COLLECTION } from "@/uhm/lib/map/geo/constants"; import { PATH_ARROW_ICON_ID, PATH_ARROW_SOURCE_ID, POLYGON_LABEL_SOURCE_ID } from "@/uhm/lib/map/constants"; import { ensurePointGeotypeIcons, getAllGeotypeLabelLayers, getAllGeotypeLayers } from "@/uhm/lib/map/styles/geotypeLayers"; import { applyBackgroundLayerVisibility, - buildTypeMatchExpression, ensurePathArrowIcon, } from "./mapUtils"; import { BackgroundLayerVisibility } from "@/uhm/lib/map/styles/backgroundLayers"; @@ -23,15 +14,8 @@ import { FeatureCollection } from "@/uhm/lib/editor/state/useEditorState"; export function getBaseMapStyle(): maplibregl.StyleSpecification { return { version: 8, - glyphs: "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf", - sources: { - base: { - type: "vector", - tiles: [getVectorTileTemplateUrl()], - minzoom: 0, - maxzoom: 6, - }, - }, + glyphs: GOONG_GLYPHS_PROXY_URL, + sources: {}, layers: [ { id: "background", @@ -40,157 +24,6 @@ export function getBaseMapStyle(): maplibregl.StyleSpecification { "background-color": "#0b1220", }, }, - { - id: "graticules-line", - type: "line", - source: "base", - "source-layer": "ne_10m_graticules_10", - paint: { - "line-color": "#334155", - "line-width": [ - "interpolate", - ["linear"], - ["zoom"], - 0, 0.3, - 4, 0.6, - 6, 0.8, - ], - "line-opacity": 0.55, - }, - }, - { - id: "land", - type: "fill", - source: "base", - "source-layer": "ne_10m_land", - paint: { - "fill-color": "#1e293b", - "fill-opacity": 0.25, - }, - }, - { - id: "bg-countries-fill", - type: "fill", - source: "base", - "source-layer": "ne_10m_admin_0_countries", - paint: { - "fill-color": COUNTRY_FILL_COLOR_EXPRESSION, - "fill-opacity": 0.38, - }, - }, - { - id: "bg-country-borders-line", - type: "line", - source: "base", - "source-layer": "ne_10m_admin_0_boundary_lines_land", - paint: { - "line-color": "#cbd5e1", - "line-width": [ - "interpolate", - ["linear"], - ["zoom"], - 0, 0.2, - 4, 0.5, - 6, 1.1, - ], - "line-opacity": 0.85, - }, - }, - { - id: "country-labels", - type: "symbol", - source: "base", - "source-layer": "country_labels", - minzoom: 0, - layout: { - "text-field": [ - "coalesce", - ["get", "NAME_EN"], - ["get", "NAME"], - ["get", "ADMIN"], - ["get", "name"], - "", - ], - "text-size": [ - "interpolate", - ["linear"], - ["zoom"], - 0, 15, - 1, 16, - 2, 17, - 4, 19, - 6, 23, - ], - "text-padding": 0, - "text-max-width": 10, - "text-allow-overlap": true, - "text-ignore-placement": true, - "symbol-placement": "point", - }, - paint: { - "text-color": "#e2e8f0", - "text-halo-color": "#0b1220", - "text-halo-width": 1.2, - "text-halo-blur": 0.5, - }, - }, - { - id: "regions-line", - type: "line", - source: "base", - "source-layer": "ne_10m_geography_regions_polys", - paint: { - "line-color": "#475569", - "line-width": [ - "interpolate", - ["linear"], - ["zoom"], - 0, 0.2, - 4, 0.6, - 6, 1, - ], - "line-opacity": 0.6, - }, - }, - { - id: "lakes-fill", - type: "fill", - source: "base", - "source-layer": "ne_10m_lakes", - paint: { - "fill-color": "#1d4ed8", - "fill-opacity": 0.45, - }, - }, - { - id: "rivers-line", - type: "line", - source: "base", - "source-layer": "ne_10m_rivers_lake_centerlines", - paint: { - "line-color": "#38bdf8", - "line-width": [ - "interpolate", - ["linear"], - ["zoom"], - 0, 0.25, - 4, 0.8, - 6, 1.5, - ], - "line-opacity": 0.85, - }, - }, - { - id: "geolines-line", - type: "line", - source: "base", - "source-layer": "ne_10m_geographic_lines", - paint: { - "line-color": "#94a3b8", - "line-width": 1.2, - "line-opacity": 0.8, - }, - }, ], }; } @@ -202,6 +35,9 @@ export function setupMapLayers( applyHighlightToMap: (fc: FeatureCollection) => void ) { applyBackgroundLayerVisibility(map, backgroundVisibility); + void replaceBackgroundLayersWithGoong(map, backgroundVisibility).catch((error) => { + console.error("Failed to load proxied background overlay bundle.", error); + }); const hasPathArrowIcon = ensurePathArrowIcon(map); // preview (drawing) @@ -432,3 +268,29 @@ export function setupMapLayers( }); applyHighlightToMap(highlightFeatures || EMPTY_FEATURE_COLLECTION); } + +async function replaceBackgroundLayersWithGoong( + map: maplibregl.Map, + backgroundVisibility: BackgroundLayerVisibility +) { + const bundle = await getGoongBackgroundOverlayBundle(); + if (!bundle || map.getLayer("goong-country-labels-0")) { + return; + } + + for (const [sourceId, source] of Object.entries(bundle.sources)) { + if (!map.getSource(sourceId)) { + map.addSource(sourceId, source); + } + } + + const insertBeforeId = map.getLayer("draw-preview-fill") + ? "draw-preview-fill" + : undefined; + for (const layer of bundle.layers) { + if (map.getLayer(layer.id)) continue; + map.addLayer(layer, insertBeforeId); + } + + applyBackgroundLayerVisibility(map, backgroundVisibility); +} diff --git a/src/uhm/doc/goong_apis_in_use.md b/src/uhm/doc/goong_apis_in_use.md new file mode 100644 index 0000000..4a97d59 --- /dev/null +++ b/src/uhm/doc/goong_apis_in_use.md @@ -0,0 +1,425 @@ +# Goong APIs In Use + +Mục tiêu của tài liệu này: + +- mô tả **chính xác** frontend hiện tại đang dùng gì từ Goong +- mô tả **backend cần proxy gì** để giấu `api_key` +- mô tả **response nào phải rewrite** +- tránh liệt kê thừa các API Goong mà app hiện tại không đụng tới + +Phạm vi kiểm tra: + +- [config.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/config.ts:1) +- [tiles.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/tiles.ts:1) +- [useMapLayers.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/components/map/useMapLayers.ts:1) +- style JSON đã tải về: + - [goong_map_web.json](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/tmp/goong-styles/goong_map_web.json) + - [goong_satellite.json](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/tmp/goong-styles/goong_satellite.json) + +## 1. Tóm tắt kỹ thuật + +Frontend hiện tại **không** `map.setStyle(goongStyleJson)` trực tiếp. + +Thay vào đó: + +1. app tự `fetch()` 2 style JSON của Goong +2. app parse style JSON để lấy: + - `raster source` từ `goong_satellite.json` + - `sources + layers` cần thiết từ `goong_map_web.json` +3. app `map.addSource(...)` và `map.addLayer(...)` thủ công +4. từ thời điểm đó, **MapLibre tự request tiếp** các `source.url` +5. rồi từ các source manifest đó, **MapLibre lại tự request tiếp** các tile URLs nằm trong `tiles[]` + +Hệ quả: + +- nếu BE chỉ proxy `assets/*.json` thì **chưa đủ** +- nếu BE chỉ proxy `sources/*.json` mà **không rewrite `tiles[]`** thì **vẫn lộ key ở request tile** + +## 2. Luồng request thật hiện tại + +### 2.1. App fetch trực tiếp style JSON + +Frontend gọi trực tiếp: + +1. `https://tiles.goong.io/assets/goong_satellite.json?api_key=...` +2. `https://tiles.goong.io/assets/goong_map_web.json?api_key=...` + +Nguồn trong code: + +- `GOONG_SATELLITE_STYLE_URL` ở [config.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/config.ts:15) +- `GOONG_VECTOR_OVERLAY_STYLE_URL` ở [config.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/config.ts:19) +- `loadGoongStyleDocument(...)` ở [tiles.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/tiles.ts:211) + +Mục đích: + +- `goong_satellite.json` + - app lấy ra raster source đầu tiên + - dùng làm nền satellite +- `goong_map_web.json` + - app lấy ra các layer/source phục vụ: + - `Country Borders` + - `Province Borders` + - `District Borders` + - `Country Labels` + - `Rivers` + +### 2.2. MapLibre fetch source manifests + +Sau khi app clone source spec từ style JSON và `addSource(...)`, MapLibre tự bắn tiếp các request `source.url`. + +Các source URL đang xuất hiện trong style JSON: + +#### Trong `goong_satellite.json` + +- `https://tiles.goong.io/sources/satellite.json?api_key=...` +- `https://tiles.goong.io/sources/base.json?api_key=...` +- `https://tiles.goong.io/sources/goong.json?api_key=...` + +#### Trong `goong_map_web.json` + +- `https://tiles.goong.io/sources/base.json?api_key=...` +- `https://tiles.goong.io/sources/goong.json?api_key=...` + +Ý nghĩa: + +- `sources/satellite.json` + - raster source manifest cho nền satellite +- `sources/base.json` + - vector source manifest cho các lớp `boundary`, `worldcountriespoints`, `worldnationalcapitals` +- `sources/goong.json` + - vector source manifest cho các lớp `riversandlakes`, `vietnam_administrator` + +### 2.3. MapLibre fetch tile URLs nằm trong source manifests + +Đây là phần dễ bị bỏ sót nhất. + +Khi MapLibre đã tải `sources/satellite.json`, `sources/base.json`, `sources/goong.json`, nó sẽ tiếp tục request các URL nằm trong field: + +- `tiles[]` + +Tức là runtime thật của frontend hiện tại là: + +1. fetch style JSON +2. fetch source manifest +3. fetch tile URL bên trong source manifest + +Nếu backend muốn che key hoàn toàn, thì **bước 3 bắt buộc phải được proxy hoặc rewrite về domain backend**. + +## 3. Những upstream Goong resource đang dùng thật + +Tính theo runtime hiện tại, upstream Goong đang được dùng thật là: + +### 3.1. Style JSON + +- `assets/goong_satellite.json` +- `assets/goong_map_web.json` + +### 3.2. Source manifests + +- `sources/satellite.json` +- `sources/base.json` +- `sources/goong.json` + +### 3.3. Tile endpoints bên trong source manifests + +- raster tile URLs nằm trong `sources/satellite.json` +- vector tile URLs nằm trong `sources/base.json` +- vector tile URLs nằm trong `sources/goong.json` + +Lưu ý: + +- tile URL pattern chính xác phải đọc từ source manifest upstream ở runtime +- backend không nên hardcode khi chưa xác minh nội dung `tiles[]` + +## 4. Những thứ frontend hiện tại dùng thêm hoặc KHÔNG dùng + +### 4.1. Goong glyphs / fonts + +Style JSON của Goong có field: + +- `glyphs: https://tiles.goong.io/fonts/{fontstack}/{range}.pbf?api_key=...` + +Flow hiện tại **có dùng glyphs của Goong qua proxy**. + +Map đang trỏ `glyphs` vào: + +- `/proxy/{encoded-https://tiles.goong.io/fonts/{fontstack}/{range}.pbf}` + +Nguồn trong code: + +- [useMapLayers.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/components/map/useMapLayers.ts:17) +- [config.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/config.ts:12) + +Kết luận: + +- **backend proxy Goong fonts/glyphs là bắt buộc cho flow hiện tại** + +### 4.2. Goong sprite + +Style JSON của Goong có: + +- `sprite: https://tiles.goong.io/sprite` + +Nhưng flow hiện tại **không phụ thuộc sprite** vì: + +- app không nạp toàn bộ Goong style vào map +- app chỉ nhặt `sources` và `layers` +- khi clone overlay labels, code còn chủ động loại bớt icon fields + +Nguồn trong code: + +- `cloneOverlayLayer(...)` ở [tiles.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/tiles.ts:411) + +Kết luận: + +- **không cần backend proxy Goong sprite cho flow hiện tại** + +### 4.3. Các REST API khác của Goong + +Không dùng: + +- geocoding +- autocomplete +- directions +- distance matrix +- place details +- static map + +## 5. Backend cần làm gì + +### 5.1. Mục tiêu backend + +Backend phải đảm bảo: + +1. browser không gọi Goong trực tiếp +2. browser không nhìn thấy `api_key` +3. frontend vẫn nhận được dữ liệu theo format mà MapLibre/app hiện tại cần + +### 5.2. Hai kiểu triển khai + +Có 2 cách: + +#### Cách A: Transparent proxy + +BE trả về gần như đúng response của Goong, chỉ rewrite URL. + +Ưu điểm: + +- gần với Goong +- ít phải đổi frontend hơn + +Nhược điểm: + +- BE phải rewrite nhiều chỗ + +#### Cách B: Normalize thành API nội bộ + +BE không trả nguyên style/source của Goong mà trả dữ liệu đã xử lý sẵn cho FE. + +Ưu điểm: + +- hợp đồng BE-FE rõ hơn +- ít phụ thuộc format Goong hơn + +Nhược điểm: + +- cần sửa frontend nhiều hơn + +Với frontend hiện tại, **Cách A** là hợp lý nhất. + +## 6. Contract backend được khuyến nghị + +### 6.1. Proxy style JSON + +#### `GET /proxy/goong/assets/goong_satellite.json` + +Upstream: + +- `https://tiles.goong.io/assets/goong_satellite.json?api_key=` + +Backend phải: + +- fetch upstream bằng key server-side +- parse JSON +- rewrite `sources.*.url` về domain backend +- có thể giữ nguyên các field khác + +Response: + +- `Content-Type: application/json` +- body: style JSON đã rewrite + +#### `GET /proxy/goong/assets/goong_map_web.json` + +Upstream: + +- `https://tiles.goong.io/assets/goong_map_web.json?api_key=` + +Backend phải: + +- fetch upstream bằng key server-side +- parse JSON +- rewrite `sources.*.url` về domain backend +- có thể giữ nguyên các field khác + +Response: + +- `Content-Type: application/json` +- body: style JSON đã rewrite + +### 6.2. Proxy source manifests + +#### `GET /proxy/goong/sources/satellite.json` + +Upstream: + +- `https://tiles.goong.io/sources/satellite.json?api_key=` + +Backend phải: + +- fetch upstream +- parse JSON +- rewrite mọi URL trong `tiles[]` về domain backend +- giữ nguyên metadata quan trọng: + - `tileSize` + - `minzoom` + - `maxzoom` + - `bounds` + - `scheme` + - `attribution` + +Response: + +- `Content-Type: application/json` +- body: source manifest đã rewrite + +#### `GET /proxy/goong/sources/base.json` + +Upstream: + +- `https://tiles.goong.io/sources/base.json?api_key=` + +Backend phải: + +- fetch upstream +- parse JSON +- rewrite mọi URL trong `tiles[]` về domain backend +- giữ nguyên metadata tilejson khác + +#### `GET /proxy/goong/sources/goong.json` + +Upstream: + +- `https://tiles.goong.io/sources/goong.json?api_key=` + +Backend phải: + +- fetch upstream +- parse JSON +- rewrite mọi URL trong `tiles[]` về domain backend +- giữ nguyên metadata tilejson khác + +### 6.3. Proxy tile endpoints + +Backend bắt buộc phải có route để trả tile thật. + +Có thể làm generic, ví dụ: + +- `GET /proxy/goong/tiles/*` + +hoặc explicit hơn theo source: + +- `GET /proxy/goong/tiles/satellite/...` +- `GET /proxy/goong/tiles/base/...` +- `GET /proxy/goong/tiles/goong/...` + +Yêu cầu: + +- request browser -> backend +- backend -> upstream Goong bằng key server-side +- stream response về browser +- pass through hoặc preserve: + - `Content-Type` + - `Cache-Control` + - `ETag` + - `Last-Modified` + +Response type có thể là: + +- raster image +- vector tile protobuf + +## 7. Runtime dependency map cho BE + +### 7.1. Satellite background + +Luồng: + +1. FE đọc `goong_satellite.json` +2. FE lấy `sources.satellite` +3. MapLibre gọi `sources/satellite.json` +4. MapLibre gọi raster tile URLs trong `tiles[]` + +BE cần cover: + +- style JSON +- source manifest +- raster tile URLs + +### 7.2. Overlay borders / labels / rivers + +Luồng: + +1. FE đọc `goong_map_web.json` +2. FE lấy selected layers + selected sources +3. MapLibre gọi `sources/base.json` +4. MapLibre gọi `sources/goong.json` +5. MapLibre gọi vector tile URLs của 2 source manifest này + +BE cần cover: + +- style JSON +- 2 source manifests +- vector tile URLs tương ứng + +## 8. Danh sách tối thiểu BE phải cover + +Nếu chỉ làm đúng những gì frontend hiện tại dùng, checklist tối thiểu là: + +1. proxy `assets/goong_satellite.json` +2. proxy `assets/goong_map_web.json` +3. proxy `sources/satellite.json` +4. proxy `sources/base.json` +5. proxy `sources/goong.json` +6. proxy toàn bộ tile URL được khai báo trong `sources/satellite.json` +7. proxy toàn bộ tile URL được khai báo trong `sources/base.json` +8. proxy toàn bộ tile URL được khai báo trong `sources/goong.json` + +## 9. Những gì BE chưa cần làm ngay + +Cho flow hiện tại, BE **chưa cần**: + +- proxy Goong `glyphs` +- proxy Goong `sprite` +- proxy geocoding / directions / autocomplete + +Điều này chỉ đúng khi frontend vẫn giữ kiến trúc hiện tại. + +Nếu sau này frontend chuyển sang `map.setStyle(goongStyleJson)` trực tiếp, hãy đánh giá lại: + +- `glyphs` +- `sprite` + +vì khi đó chúng có thể trở thành dependency bắt buộc. + +## 10. Gợi ý ngắn cho team BE + +Nếu muốn làm ít rủi ro nhất: + +1. làm proxy `assets/*.json` +2. rewrite `sources.*.url` +3. làm proxy `sources/*.json` +4. rewrite `tiles[]` +5. làm proxy generic cho tile + +Nếu làm thiếu bước 4 hoặc 5 thì key vẫn có thể lộ ở request tile. diff --git a/src/uhm/doc/goong_map_web_structure.md b/src/uhm/doc/goong_map_web_structure.md new file mode 100644 index 0000000..f22ff49 --- /dev/null +++ b/src/uhm/doc/goong_map_web_structure.md @@ -0,0 +1,129 @@ +# Goong Map Web Structure + +Nguồn JSON gốc được tải về tại: + +- `FrontEndUser/tmp/goong-styles/goong_map_web.json` + +File này là style vector/label đầy đủ hơn, phù hợp để dò: + +- water và water labels +- boundary theo cấp +- place labels cho lịch sử + +## Mermaid overview + +```mermaid +graph TD + ROOT[goong_map_web.json] + + ROOT --> S1[source: base] + ROOT --> S2[source: composite] + + S1 --> B1[source-layer: boundary] + S1 --> B2[source-layer: worldcountriespoints] + S1 --> B3[source-layer: worldnationalcapitals] + + S2 --> C1[source-layer: riversandlakes] + S2 --> C2[source-layer: rivernames] + S2 --> C3[source-layer: lakenames] + S2 --> C4[source-layer: vietnam_administrator] + S2 --> C5[source-layer: streets_label] + + B1 --> BL0[boundary-land-type-0 / type-0-bg] + B1 --> BL1[boundary-land-type-1 / type-1-bg] + B1 --> BL2[boundary-land-type-2 / type-2-bg] + + B2 --> PC1[place-country-1] + B2 --> PC2[place-country-2] + + B3 --> CAP0[place-city-capital] + + C1 --> W1[water] + C1 --> W2[water-shadow] + + C2 --> RN0[river-name-0] + C2 --> RN1[river-name-1] + C2 --> RN2[river-name-2] + + C3 --> LN0[lake-name_priority_0] + C3 --> LN1[lake-name_priority_1] + C3 --> LN2[lake-name_priority_2] + + C4 --> VA0[place-city-capital-vietnam] + C4 --> VA1[place-city1 / place-city2] + C4 --> VA2[place-town1 / place-town2] + C4 --> VA3[place-suburb / borough / neighbourhood] + C4 --> VA4[place-village] + + C5 --> RD0[highway-name-minor] + C5 --> RD1[highway-name-medium] + C5 --> RD2[highway-name-major] +``` + +## Boundary layers + +Các layer boundary nổi bật: + +- `boundary-land-type-0-bg` +- `boundary-land-type-0` +- `boundary-land-type-1-bg` +- `boundary-land-type-1` +- `boundary-land-type-2-bg` +- `boundary-land-type-2` + +Minzoom quan sát được: + +- `type-0`: từ zoom `1` +- `type-1`: từ zoom `5` +- `type-2-bg`: từ zoom `7` +- `type-2`: từ zoom `13` + +Suy luận thực dụng: + +- `type-0` có khả năng là biên giới quốc gia +- `type-1` có khả năng là cấp tỉnh/thành +- `type-2` có khả năng là cấp sâu hơn + +## Water layers + +Water fill: + +- `water` +- `water-shadow` + +Water labels: + +- `river-name-0` +- `river-name-1` +- `river-name-2` +- `lake-name_priority_0` +- `lake-name_priority_1` +- `lake-name_priority_2` + +## Place labels + +Những label đáng quan tâm cho historical use: + +- `place-country-1` +- `place-country-2` +- `place-city-capital` +- `place-city-capital-vietnam` +- `place-city1` +- `place-city2` +- `place-town1` +- `place-town2` + +Những label dễ gây rối nếu bật nhiều: + +- `highway-name-*` +- `place-suburb*` +- `place-neighbourhood*` +- `place-village` + +## Gợi ý mapping cho UI + +- `Country Borders` -> `boundary-land-type-0` + `boundary-land-type-0-bg` +- `Province Borders` -> `boundary-land-type-1` + `boundary-land-type-1-bg` +- `District Borders` -> `boundary-land-type-2` + `boundary-land-type-2-bg` +- `Country Labels` -> `place-country-*`, `place-city-capital*`, `place-city*`, `place-town*` +- `Rivers` -> `water`, `water-shadow`, `river-name-*`, `lake-name_*` diff --git a/src/uhm/doc/goong_proxy_backend_guide.md b/src/uhm/doc/goong_proxy_backend_guide.md new file mode 100644 index 0000000..c26207a --- /dev/null +++ b/src/uhm/doc/goong_proxy_backend_guide.md @@ -0,0 +1,384 @@ +# Goong Proxy Backend Guide + +Tài liệu này mô tả: + +- luồng request thật của frontend hiện tại +- backend cần proxy chỗ nào +- backend cần rewrite chỗ nào +- trade-off hiệu suất nếu proxy/rewrite toàn bộ Goong +- khuyến nghị triển khai thực dụng cho team BE + +Tài liệu liên quan: + +- [goong_apis_in_use.md](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/doc/goong_apis_in_use.md) +- [goong_map_web_structure.md](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/doc/goong_map_web_structure.md) +- [goong_satellite_structure.md](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/doc/goong_satellite_structure.md) + +Code liên quan: + +- [config.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/config.ts:1) +- [tiles.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/api/tiles.ts:1) +- [useMapLayers.ts](/home/amoratran/wsp/ultimate-history-map/FrontEndUser/src/uhm/components/map/useMapLayers.ts:1) + +## 1. Bối cảnh hiện tại + +Frontend hiện tại không `setStyle(goongStyle)` trực tiếp cho MapLibre. + +Thay vào đó: + +1. FE tự `fetch()` style JSON của Goong +2. FE parse style JSON +3. FE lấy ra: + - raster source cho satellite + - selected vector sources/layers cho borders, labels, rivers +4. FE `addSource()` và `addLayer()` thủ công +5. MapLibre tự request tiếp `source.url` +6. Từ source manifest, MapLibre tự request tiếp các tile URLs trong `tiles[]` + +Điểm quan trọng: + +- browser có thể không chỉ gọi `assets/*.json` +- browser sẽ đi sâu thêm ít nhất 2 tầng: + - `sources/*.json` + - tile URLs trong `tiles[]` + +## 2. Luồng request hiện tại + +```mermaid +sequenceDiagram + participant FE as Frontend + participant GL as MapLibre + participant GO as Goong + + FE->>GO: GET assets/goong_satellite.json?api_key=... + FE->>GO: GET assets/goong_map_web.json?api_key=... + + FE->>GL: addSource(raster/vector) + addLayer(...) + + GL->>GO: GET sources/satellite.json?api_key=... + GL->>GO: GET sources/base.json?api_key=... + GL->>GO: GET sources/goong.json?api_key=... + + GL->>GO: GET raster tile URLs from satellite tiles[] + GL->>GO: GET vector tile URLs from base tiles[] + GL->>GO: GET vector tile URLs from goong tiles[] +``` + +## 3. Mục tiêu của backend proxy + +Nếu mục tiêu là: + +- không lộ `api_key` ở browser +- vẫn giữ frontend hiện tại gần như nguyên + +thì backend phải đảm bảo: + +1. browser chỉ gọi domain BE +2. BE gọi Goong bằng key server-side +3. mọi URL Goong lồng bên trong JSON đều được rewrite về domain BE + +Nếu thiếu bước 3: + +- `api_key` vẫn có thể lộ ở request tầng sau + +## 4. Những gì cần rewrite + +### 4.1. Style JSON + +Trong `goong_satellite.json` và `goong_map_web.json`, BE cần rewrite: + +- `sources.*.url` + +Ví dụ: + +- từ `https://tiles.goong.io/sources/base.json?api_key=...` +- thành `/proxy/goong/sources/base.json` + +### 4.2. Source manifests + +Trong `sources/satellite.json`, `sources/base.json`, `sources/goong.json`, BE cần rewrite: + +- mọi phần tử trong `tiles[]` + +Ví dụ: + +- từ `https://.../{z}/{x}/{y}...api_key=...` +- thành `/proxy/goong/tiles/...` + +### 4.3. Những field còn phải để ý cho flow hiện tại + +Với kiến trúc frontend hiện tại: + +- `glyphs` đang được FE dùng qua proxy +- `sprite` hiện chưa dùng + +Nghĩa là: + +- BE **phải** proxy được `fonts/{fontstack}/{range}.pbf` +- BE hiện **chưa cần** proxy `sprite` + +Nếu sau này FE chuyển sang `map.setStyle(goongStyleJson)` trực tiếp thì phải đánh giá lại `sprite` ngay. + +## 5. Backend endpoint được khuyến nghị + +### 5.1. Style endpoints + +- `GET /proxy/goong/assets/goong_satellite.json` +- `GET /proxy/goong/assets/goong_map_web.json` + +Nhiệm vụ: + +- gọi upstream Goong bằng key server-side +- parse JSON +- rewrite `sources.*.url` +- trả JSON đã rewrite + +### 5.2. Source endpoints + +- `GET /proxy/goong/sources/satellite.json` +- `GET /proxy/goong/sources/base.json` +- `GET /proxy/goong/sources/goong.json` + +Nhiệm vụ: + +- gọi upstream Goong bằng key server-side +- parse JSON +- rewrite `tiles[]` +- giữ nguyên: + - `bounds` + - `minzoom` + - `maxzoom` + - `scheme` + - `tileSize` + - `attribution` + +### 5.3. Tile endpoint + +Gợi ý route generic: + +- `GET /proxy/goong/tiles/*` + +Nhiệm vụ: + +- nhận tile request từ browser +- map sang upstream tile URL tương ứng +- gọi Goong bằng key server-side nếu upstream yêu cầu +- stream response về browser + +Điểm quan trọng: + +- tile response không nên parse lại +- tile response nên stream/pass-through +- giữ cache headers càng nhiều càng tốt + +## 6. Luồng request sau khi proxy + +```mermaid +sequenceDiagram + participant FE as Frontend + participant GL as MapLibre + participant BE as Backend Proxy + participant GO as Goong + + FE->>BE: GET /proxy/goong/assets/goong_satellite.json + FE->>BE: GET /proxy/goong/assets/goong_map_web.json + + BE->>GO: fetch upstream style JSON + GO-->>BE: style JSON + BE-->>FE: rewritten style JSON + + FE->>GL: addSource(raster/vector) + addLayer(...) + + GL->>BE: GET /proxy/goong/sources/satellite.json + GL->>BE: GET /proxy/goong/sources/base.json + GL->>BE: GET /proxy/goong/sources/goong.json + + BE->>GO: fetch upstream source manifests + GO-->>BE: source manifests + BE-->>GL: rewritten source manifests + + GL->>BE: GET /proxy/goong/tiles/... + BE->>GO: fetch upstream tile + GO-->>BE: tile bytes + BE-->>GL: tile bytes +``` + +## 7. Trade-off hiệu suất + +### 7.1. Rewrite JSON có chậm không? + +Có overhead, nhưng **rất nhỏ** so với tile traffic. + +JSON cần rewrite hiện tại chỉ gồm: + +- 2 style JSON +- 3 source manifests + +Những file này nhỏ, số lượng ít, và có thể cache rất mạnh. + +Kết luận: + +- rewrite JSON không phải bottleneck chính + +### 7.2. Tile proxy mới là chỗ đắt + +Chi phí hiệu suất chính nằm ở: + +- mọi tile phải đi qua backend +- backend phải giữ thêm một hop mạng +- mất lợi thế gọi trực tiếp CDN của Goong từ browser + +Các ảnh hưởng có thể thấy: + +- tăng latency +- tăng bandwidth qua BE +- tăng CPU/memory nếu BE buffer response thay vì stream +- tăng load connection pool tới Goong + +### 7.3. Nếu không rewrite tile URL + +Nếu BE chỉ rewrite style/source JSON nhưng không rewrite `tiles[]`: + +- browser vẫn gọi Goong trực tiếp ở bước tile +- `api_key` vẫn có thể lộ + +Tức là: + +- hiệu suất tốt hơn +- nhưng mục tiêu bảo mật key không đạt + +## 8. Cách giảm thiểu impact hiệu suất + +### 8.1. Cache rewritten JSON ở BE + +Khuyến nghị: + +- cache in-memory hoặc Redis cho: + - `goong_satellite.json` + - `goong_map_web.json` + - `sources/satellite.json` + - `sources/base.json` + - `sources/goong.json` + +TTL có thể dài vì: + +- style/source manifest không đổi liên tục + +Tối ưu: + +- chỉ rewrite một lần rồi reuse + +### 8.2. Stream tile response + +Cho tile route: + +- không parse body +- không buffer toàn bộ file vào memory nếu không cần +- stream thẳng upstream -> client + +### 8.3. Preserve cache headers + +Với tile route, BE nên pass-through hoặc preserve: + +- `Cache-Control` +- `ETag` +- `Last-Modified` +- `Content-Type` + +Nếu BE/ngược phía CDN có cache tốt, impact sẽ giảm rất nhiều. + +### 8.4. Dùng CDN/reverse proxy trước BE nếu có thể + +Nếu production có CDN/nginx/edge cache: + +- cache mạnh cho: + - rewritten style JSON + - rewritten source manifests + - tile responses + +Điều này quan trọng hơn tối ưu code rewrite. + +### 8.5. Đừng rewrite tile mỗi request theo kiểu string building phức tạp + +Nên: + +- rewrite `tiles[]` một lần ở source manifest +- tile route chỉ resolve path đơn giản và forward + +Không nên: + +- parse lại manifest ở mỗi tile request + +## 9. Recommendation thực dụng + +Nếu team BE muốn giải pháp cân bằng giữa bảo mật và hiệu suất: + +### Option A. Full proxy, full rewrite + +BE cover: + +1. style JSON +2. source manifests +3. tiles + +Ưu điểm: + +- key không lộ ra browser +- FE không cần biết upstream Goong + +Nhược điểm: + +- BE chịu toàn bộ traffic tile + +### Option B. Hybrid + +BE cover: + +1. style JSON +2. source manifests + +Nhưng không rewrite `tiles[]` + +Ưu điểm: + +- BE nhẹ hơn + +Nhược điểm: + +- key vẫn lộ ở tile request + +Kết luận: + +- nếu ưu tiên bảo mật key thật sự: dùng **Option A** +- nếu ưu tiên hiệu suất hơn và chấp nhận domain restrictions của Goong: dùng **Option B** + +## 10. Recommendation cho codebase hiện tại + +Với frontend hiện tại, hướng hợp lý nhất là: + +1. giữ nguyên FE logic parse style/source như hiện nay +2. chuyển các URL Goong ở `config.ts` sang endpoint nội bộ BE +3. để BE rewrite: + - `sources.*.url` + - `tiles[]` +4. để BE stream tile response +5. cache rewritten JSON ở BE + +Nói ngắn: + +- rewrite JSON: nên làm +- rewrite tile URLs: bắt buộc nếu muốn giấu key +- proxy tile: phần tốn hiệu suất nhất +- muốn bù hiệu suất: phải dùng cache/stream/CDN tốt + +## 11. Checklist cho team BE + +1. Tạo route proxy cho 2 style JSON +2. Tạo route proxy cho 3 source manifests +3. Rewrite `sources.*.url` trong style JSON +4. Rewrite `tiles[]` trong source manifests +5. Tạo route proxy tile generic +6. Stream tile response +7. Preserve cache headers +8. Cache rewritten JSON +9. Kiểm tra browser không còn request trực tiếp `tiles.goong.io` diff --git a/src/uhm/doc/goong_satellite_structure.md b/src/uhm/doc/goong_satellite_structure.md new file mode 100644 index 0000000..ba042f6 --- /dev/null +++ b/src/uhm/doc/goong_satellite_structure.md @@ -0,0 +1,99 @@ +# Goong Satellite Structure + +Nguồn JSON gốc được tải về tại: + +- `FrontEndUser/tmp/goong-styles/goong_satellite.json` + +File này là style satellite. Nó vẫn có boundary và labels, nhưng ít lớp nước hơn `goong_map_web.json`. + +## Mermaid overview + +```mermaid +graph TD + ROOT[goong_satellite.json] + + ROOT --> S0[source: satellite] + ROOT --> S1[source: base] + ROOT --> S2[source: composite] + + S1 --> B1[source-layer: boundary] + S1 --> B2[source-layer: worldcountriespoints] + S1 --> B3[source-layer: worldnationalcapitals] + + S2 --> C1[source-layer: vietnam_administrator] + S2 --> C2[source-layer: streets_label] + + B1 --> BL0[boundary-land-type-0 / type-0-bg] + B1 --> BL1[boundary-land-type-1 / type-1-bg] + B1 --> BL2[boundary-land-type-2 / type-2-bg] + + B2 --> PC1[place-country-1] + B2 --> PC2[place-country-2] + + B3 --> CAP0[place-city-capital] + + C1 --> VA0[place-city-capital-vietnam] + C1 --> VA1[place-city1 / place-city2] + C1 --> VA2[place-town1 / place-town2] + C1 --> VA3[place-suburb / borough / neighbourhood] + C1 --> VA4[place-village] + + C2 --> RD0[highway-name-minor] + C2 --> RD1[highway-name-medium] + C2 --> RD2[highway-name-major] +``` + +## Boundary layers + +Các layer boundary nổi bật: + +- `boundary-land-type-0-bg` +- `boundary-land-type-0` +- `boundary-land-type-1-bg` +- `boundary-land-type-1` +- `boundary-land-type-2-bg` +- `boundary-land-type-2` + +Minzoom quan sát được: + +- `type-0`: từ zoom `1` +- `type-1`: từ zoom `5` +- `type-2-bg`: từ zoom `7` +- `type-2`: từ zoom `7` + +## Place labels + +Labels hữu ích: + +- `place-country-1` +- `place-country-2` +- `place-city-capital` +- `place-city-capital-vietnam` +- `place-city1` +- `place-city2` +- `place-town1` +- `place-town2` + +Labels dễ gây rối: + +- `highway-name-*` +- `place-suburb*` +- `place-neighbourhood*` +- `place-village` + +## Khác biệt thực dụng so với goong_map_web + +- Có `source: satellite` +- Boundary vẫn hiện diện rõ +- Labels hành chính vẫn có +- Không lộ ra nhóm water chi tiết rõ như `goong_map_web` +- Phù hợp làm raster/satellite nền hơn là style để dò water layers + +## Gợi ý dùng thực tế + +- Dùng `goong_satellite.json` cho nền satellite +- Dùng `goong_map_web.json` để dò: + - water + - water labels + - boundary theo cấp + - labels hành chính diff --git a/src/uhm/lib/editor/background/backgroundVisibilityStorage.ts b/src/uhm/lib/editor/background/backgroundVisibilityStorage.ts index d949ecb..b2d5bed 100644 --- a/src/uhm/lib/editor/background/backgroundVisibilityStorage.ts +++ b/src/uhm/lib/editor/background/backgroundVisibilityStorage.ts @@ -4,7 +4,7 @@ import { DEFAULT_BACKGROUND_LAYER_VISIBILITY, } from "@/uhm/lib/map/styles/backgroundLayers"; -const BACKGROUND_LAYER_VISIBILITY_STORAGE_KEY = "uhm.backgroundLayerVisibility.v1"; +const BACKGROUND_LAYER_VISIBILITY_STORAGE_KEY = "uhm.backgroundLayerVisibility.v2"; export function loadBackgroundLayerVisibilityFromStorage(): BackgroundLayerVisibility { if (typeof window === "undefined") { @@ -57,4 +57,3 @@ function normalizeBackgroundLayerVisibility(raw: unknown): BackgroundLayerVisibi return next; } - diff --git a/src/uhm/lib/map/constants.ts b/src/uhm/lib/map/constants.ts index 60691a2..b36aac8 100644 --- a/src/uhm/lib/map/constants.ts +++ b/src/uhm/lib/map/constants.ts @@ -5,7 +5,6 @@ export const MAP_MAX_ZOOM = 10; export const RASTER_BASE_SOURCE_ID = "rasterBase"; export const RASTER_BASE_LAYER_ID = "raster-base-layer"; -export const RASTER_BASE_INSERT_BEFORE_LAYER_ID = "graticules-line"; export const PATH_ARROW_SOURCE_ID = "path-arrow-shapes"; export const POLYGON_LABEL_SOURCE_ID = "polygon-labels"; diff --git a/src/uhm/lib/map/styles/backgroundLayers.ts b/src/uhm/lib/map/styles/backgroundLayers.ts index 5391a92..ee1abf0 100644 --- a/src/uhm/lib/map/styles/backgroundLayers.ts +++ b/src/uhm/lib/map/styles/backgroundLayers.ts @@ -1,29 +1,29 @@ export const BACKGROUND_LAYER_OPTIONS = [ { id: "raster-base-layer", label: "Raster" }, - { id: "graticules-line", label: "Graticules" }, - { id: "land", label: "Land" }, - { id: "bg-countries-fill", label: "Countries" }, { id: "bg-country-borders-line", label: "Country Borders" }, + { id: "bg-province-borders-line", label: "Province Borders" }, + { id: "bg-district-borders-line", label: "District Borders" }, { id: "country-labels", label: "Country Labels" }, - { id: "regions-line", label: "Regions" }, - { id: "lakes-fill", label: "Lakes" }, { id: "rivers-line", label: "Rivers" }, - { id: "geolines-line", label: "Geolines" }, ] as const; export type BackgroundLayerId = (typeof BACKGROUND_LAYER_OPTIONS)[number]["id"]; export type BackgroundLayerVisibility = Record; -// Tạo map visibility mặc định cho toàn bộ background layers. -function buildBackgroundLayerVisibility(value: boolean): BackgroundLayerVisibility { - return BACKGROUND_LAYER_OPTIONS.reduce((acc, option) => { - acc[option.id] = value; - return acc; - }, {} as BackgroundLayerVisibility); -} +export const DEFAULT_BACKGROUND_LAYER_VISIBILITY: BackgroundLayerVisibility = { + "raster-base-layer": true, + "bg-country-borders-line": true, + "bg-province-borders-line": false, + "bg-district-borders-line": false, + "country-labels": true, + "rivers-line": true, +}; -export const DEFAULT_BACKGROUND_LAYER_VISIBILITY = - buildBackgroundLayerVisibility(true); - -export const HIDDEN_BACKGROUND_LAYER_VISIBILITY = - buildBackgroundLayerVisibility(false); +export const HIDDEN_BACKGROUND_LAYER_VISIBILITY: BackgroundLayerVisibility = { + "raster-base-layer": false, + "bg-country-borders-line": false, + "bg-province-borders-line": false, + "bg-district-borders-line": false, + "country-labels": false, + "rivers-line": false, +}; diff --git a/src/uhm/lib/map/styles/shared/lineLabels.ts b/src/uhm/lib/map/styles/shared/lineLabels.ts index 87f5129..66a1ad4 100644 --- a/src/uhm/lib/map/styles/shared/lineLabels.ts +++ b/src/uhm/lib/map/styles/shared/lineLabels.ts @@ -1,4 +1,5 @@ import maplibregl, { LayerSpecification } from "maplibre-gl"; +import { MAP_TEXT_FONT_STACK } from "./textFonts"; const LINE_GEOMETRY_FILTER: maplibregl.ExpressionSpecification = [ "any", @@ -14,6 +15,7 @@ export function getLineLabelLayers(sourceId: string): LayerSpecification[] { source: sourceId, filter: ["all", LINE_GEOMETRY_FILTER, ["!=", ["coalesce", ["get", "line_label"], ""], ""]], layout: { + "text-font": [...MAP_TEXT_FONT_STACK], "symbol-placement": "line", "symbol-spacing": 280, "text-field": ["coalesce", ["get", "line_label"], ""], diff --git a/src/uhm/lib/map/styles/shared/pointStyle.ts b/src/uhm/lib/map/styles/shared/pointStyle.ts index c3ff7ff..be29449 100644 --- a/src/uhm/lib/map/styles/shared/pointStyle.ts +++ b/src/uhm/lib/map/styles/shared/pointStyle.ts @@ -1,4 +1,5 @@ import maplibregl, { LayerSpecification } from "maplibre-gl"; +import { MAP_EMPHASIS_TEXT_FONT_STACK } from "./textFonts"; export const POINT_GEOTYPE_IDS = [ "person_birthplace", @@ -168,6 +169,7 @@ export function buildPointGeotypeLayers( "icon-allow-overlap": true, "icon-ignore-placement": true, "symbol-placement": "point", + "text-font": [...MAP_EMPHASIS_TEXT_FONT_STACK], "text-field": ["coalesce", ["get", "point_label"], ""], "text-size": [ "interpolate", diff --git a/src/uhm/lib/map/styles/shared/polygonLabels.ts b/src/uhm/lib/map/styles/shared/polygonLabels.ts index cc36375..51a46ed 100644 --- a/src/uhm/lib/map/styles/shared/polygonLabels.ts +++ b/src/uhm/lib/map/styles/shared/polygonLabels.ts @@ -1,4 +1,5 @@ import { LayerSpecification } from "maplibre-gl"; +import { MAP_TEXT_FONT_STACK } from "./textFonts"; export function getPolygonLabelLayers(sourceId: string): LayerSpecification[] { return [ @@ -7,6 +8,7 @@ export function getPolygonLabelLayers(sourceId: string): LayerSpecification[] { type: "symbol", source: sourceId, layout: { + "text-font": [...MAP_TEXT_FONT_STACK], "text-field": ["coalesce", ["get", "polygon_label"], ""], "text-size": [ "interpolate", diff --git a/src/uhm/lib/map/styles/shared/textFonts.ts b/src/uhm/lib/map/styles/shared/textFonts.ts new file mode 100644 index 0000000..c6827bc --- /dev/null +++ b/src/uhm/lib/map/styles/shared/textFonts.ts @@ -0,0 +1,3 @@ +export const MAP_TEXT_FONT_STACK = ["Roboto Regular"] as const; +export const MAP_EMPHASIS_TEXT_FONT_STACK = ["Roboto Medium"] as const; +export const GOONG_LABEL_FALLBACK_FONT_STACK = ["Roboto Regular"] as const; diff --git a/tmp/goong-styles/goong_map_web.json b/tmp/goong-styles/goong_map_web.json new file mode 100644 index 0000000..d6943af --- /dev/null +++ b/tmp/goong-styles/goong_map_web.json @@ -0,0 +1,4288 @@ +{ + "version": 8, + "name": "GOONG-MAP-WEB", + "metadata": {"maputnik:renderer": "mlgljs"}, + "zoom": 16.667414484254696, + "bearing": 0, + "pitch": 0, + "sources": { + "base": { + "type": "vector", + "url": "https://tiles.goong.io/sources/base.json?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7" + }, + "composite": { + "type": "vector", + "url": "https://tiles.goong.io/sources/goong.json?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7" + } + }, + "sprite": "https://tiles.goong.io/sprite", + "glyphs": "https://tiles.goong.io/fonts/{fontstack}/{range}.pbf?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7", + "layers": [ + { + "id": "background", + "type": "background", + "filter": ["all"], + "layout": {"visibility": "visible"}, + "paint": {"background-color": "#EBF0F0"} + }, + { + "id": "landcover-natural", + "type": "fill", + "source": "base", + "source-layer": "landcover_natural", + "minzoom": 0, + "maxzoom": 24, + "filter": ["all", ["==", "class", "natural"]], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "rgba(210, 248, 226, 1)", + "fill-opacity": {"base": 1, "stops": [[5, 1], [6, 1]]} + } + }, + { + "id": "landcover-human-made", + "type": "fill", + "source": "base", + "source-layer": "landcover_human_made", + "minzoom": 9, + "maxzoom": 24, + "filter": ["all", ["==", "class", "human made"]], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "rgba(246, 245, 245, 1)", + "fill-opacity": {"base": 1, "stops": [[5, 1], [6, 1]]} + } + }, + { + "id": "park-outline", + "type": "line", + "source": "composite", + "source-layer": "landuser", + "minzoom": 15, + "maxzoom": 24, + "filter": ["all", ["==", "class", "park"]], + "layout": {"visibility": "visible"}, + "paint": {"line-color": "#E6EAE9", "line-dasharray": [3, 3]} + }, + { + "id": "park", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["==", "class", "park"]], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "#E6EAE9", + "fill-opacity": {"base": 1.8, "stops": [[9, 0.5], [12, 0.2]]} + } + }, + { + "id": "landuse-forest", + "type": "fill", + "source": "base", + "source-layer": "forest", + "filter": ["all"], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "rgba(183, 239, 206, 1)", + "fill-opacity": {"base": 1, "stops": [[5, 1], [6, 1]]} + } + }, + { + "id": "landuse-airport", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 9, + "filter": ["all", ["==", "class", "airport"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(224, 218, 224, 1)"} + }, + { + "id": "landuse-industrial", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 11, + "filter": ["all", ["==", "class", "industrial"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(224, 226, 235, 1)"} + }, + { + "id": "landuse-cemetery", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "filter": ["==", "class", "cemetery"], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(226, 238, 220, 1)"} + }, + { + "id": "landuse-hospital", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 14, + "filter": ["==", "class", "hospital"], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(245, 236, 245, 1)"} + }, + { + "id": "landuse-school", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "filter": ["all", ["==", "class", "school"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(242, 240, 227, 1)"} + }, + { + "id": "landuse-stadium", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "filter": ["all", ["==", "class", "stadium"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(244, 221, 217, 1)"} + }, + { + "id": "landuse-stadium-area", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 11, + "filter": ["all", ["==", "class", "stadium_area"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(216, 237, 191, 1)"} + }, + { + "id": "landuse-pitch", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 15, + "filter": ["all", ["==", "class", "pitch"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(217, 237, 193, 1)"} + }, + { + "id": "landuse-sand", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "filter": ["all", ["==", "class", "sand"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(237, 237, 207, 1)"} + }, + { + "id": "ocean", + "type": "fill", + "source": "base", + "source-layer": "ocean", + "minzoom": 1, + "maxzoom": 24, + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(130, 205, 247, 1)"} + }, + { + "id": "landuser-park", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "filter": ["all", ["==", "class", "park"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "#E6EAE9", "fill-opacity": 1} + }, + { + "id": "landuser-grass", + "type": "fill", + "source": "composite", + "source-layer": "landuser", + "minzoom": 12, + "maxzoom": 24, + "filter": ["==", "class", "grass"], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(217, 237, 193, 1)", "fill-opacity": 1} + }, + { + "id": "water-shadow", + "type": "fill", + "source": "composite", + "source-layer": "riversandlakes", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all"], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "rgba(49, 174, 243, 1)", + "fill-translate": {"stops": [[14, [0, 0]], [16, [-1.2, -1.2]]]} + } + }, + { + "id": "water", + "type": "fill", + "source": "composite", + "source-layer": "riversandlakes", + "minzoom": 6, + "maxzoom": 24, + "filter": ["all"], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "rgba(130, 205, 247, 1)"} + }, + { + "id": "ferry", + "type": "line", + "source": "composite", + "source-layer": "streets", + "filter": ["all", ["==", "structure", "ferry"]], + "layout": {"line-join": "round", "visibility": "visible"}, + "paint": { + "line-color": "rgba(92, 172, 230, 1)", + "line-width": 1.1, + "line-dasharray": [2, 2] + } + }, + { + "id": "aeroway-taxiway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": ["all", ["==", "class", "aeroway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-width": {"base": 1.5, "stops": [[11, 2], [17, 12]]}, + "line-opacity": 1 + } + }, + { + "id": "aeroway-runway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": ["all", ["==", "class", "aeroway-runway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-width": {"base": 1.5, "stops": [[11, 5], [17, 55]]}, + "line-opacity": 1, + "line-translate-anchor": "map" + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 9, + "filter": ["all", ["in", "class", "aeroway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(219, 206, 219, 1)", + "line-width": {"base": 1.5, "stops": [[11, 1], [17, 10]]}, + "line-opacity": {"base": 1, "stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "aeroway-runway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 9, + "filter": ["all", ["==", "class", "aeroway-runway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(219, 206, 219, 1)", + "line-width": {"base": 1.5, "stops": [[11, 4], [17, 50]]}, + "line-opacity": {"base": 1, "stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "tunnel-major", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "major"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": [1], + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "tunnel-path-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "tunnel"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": {"stops": [[0, 0], [14, 0.75]]}, + "line-width": {"stops": [[13, 1], [14, 2.5], [15, 2], [18, 7]]} + } + }, + { + "id": "tunnel-pedestrian-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [18, 6]]} + } + }, + { + "id": "tunnel-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-trunk-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["==", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["==", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-service-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-street-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.5], + [10, 0.55], + [12, 0.75], + [14, 0.81], + [16, 0.96], + [18, 1.28], + [20, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]]}, + "line-dasharray": [3, 3] + }, + "line-dasharray": [3, 3] + }, + { + "id": "tunnel-secondary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.75], + [12, 0.81], + [14, 0.96], + [16, 1.28], + [18, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [10, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + } + }, + "line-dasharray": [3, 3] + }, + { + "id": "tunnel-primary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": 1, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-width": { + "base": 1.2, + "stops": [[10, 1], [12, 1.05], [14, 1.16], [16, 1.42], [18, 2]] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-path", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "tunnel"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [15, 1], [18, 4]]} + } + }, + { + "id": "tunnel-pedestrian", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [16, 2], [18, 5]]} + } + }, + { + "id": "tunnel-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": { + "base": 1.2, + "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] + }, + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-trunk-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "tunnel-motorway-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "tunnel-service", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": {"base": 1.2, "stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "tunnel-street", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": { + "base": 1.2, + "stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "tunnel-secondary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "tunnel-primary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "tunnel-trunk", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "tunnel-motorway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-major", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "major"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-dasharray": [1], + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "road-runway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 15, + "maxzoom": 24, + "filter": ["all", ["==", "class", "runway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "road-path-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": {"stops": [[0, 0], [14, 0.75]]}, + "line-width": {"stops": [[13, 1], [14, 2.5], [15, 2], [18, 7]]} + } + }, + { + "id": "road-pedestrian-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [18, 6]]} + } + }, + { + "id": "road-major-tracks-copy", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "major"], ["==", "structure", "road"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-dasharray": [0.1, 15], + "line-opacity": {"stops": [[13.75, 0], [14, 1]]}, + "line-width": {"stops": [[14, 4], [20, 8]]} + } + }, + { + "id": "road-major-tracks", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "major"], ["==", "structure", "road"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-dasharray": [0.1, 15], + "line-opacity": {"stops": [[13.75, 0], [14, 1]]}, + "line-width": {"stops": [[14, 4], [20, 8]]} + } + }, + { + "id": "road-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "road"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] + } + } + }, + { + "id": "road-trunk-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["==", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-motorway-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["==", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-path", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "road"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [15, 1], [18, 4]]} + } + }, + { + "id": "road-pedestrian", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [16, 2], [18, 5]]} + } + }, + { + "id": "road-service-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.1], [14, 0.51], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-opacity": {"stops": [[0, 0], [13, 1]]}, + "line-gap-width": {"stops": [[14, 0.5], [16, 4.04], [18, 12]]} + } + }, + { + "id": "road-street-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["in", "class", "street", "street_link"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.2], + [10, 0.3], + [12, 0.5], + [14, 0.81], + [16, 0.96], + [18, 1.28], + [20, 2] + ] + }, + "line-opacity": 1, + "line-gap-width": { + "stops": [[12, 0.1], [14, 0.8], [16, 6.92], [18, 18]] + } + } + }, + { + "id": "road-secondary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 7, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.5], + [10, 0.6], + [12, 0.75], + [14, 0.96], + [16, 1.28], + [18, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [10, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + } + } + }, + { + "id": "road-primary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 7, + "filter": [ + "all", + ["==", "structure", "road"], + ["==", "class", "primary"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": {"base": 1.5, "stops": [[5, 0.75], [16, 2]]}, + "line-gap-width": {"stops": [[5, 0.75], [18, 32]], "base": 1.5} + } + }, + { + "id": "road-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": ["all", ["==", "class", "trunk"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.5], + [10, 0.6], + [12, 0.8], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "road-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-width": { + "base": 1.2, + "stops": [[10, 1], [12, 1.05], [14, 1.16], [16, 1.42], [18, 2]] + }, + "line-opacity": {"stops": [[9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "road-service", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": [ + "interpolate", + ["exponential", 1.2], + ["zoom"], + 12, + 0.1, + 14, + 0.3, + 16, + 4.04, + 18, + 12 + ], + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "road-street", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["in", "class", "street", "street_link"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.2], [14, 0.5], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[10, 0.2], [12, 0.5], [14, 1]]} + } + }, + { + "id": "road-trunk-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["in", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-motorway-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["in", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-secondary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 7, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-primary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 7, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-trunk", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": ["all", ["==", "class", "trunk"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-motorway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-primary-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 7, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "road"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-major", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "major"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": [1], + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "bridge-path-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "bridge"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": {"stops": [[0, 0], [14, 0.75]]}, + "line-width": {"stops": [[13, 1], [14, 2.5], [15, 2], [18, 7]]} + } + }, + { + "id": "bridge-pedestrian-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [18, 6]]} + } + }, + { + "id": "bridge-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] + } + } + }, + { + "id": "bridge-trunk-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["==", "class", "trunk_link"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-motorway-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["==", "class", "motorway_link"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-service-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[14, 0.5], [16, 4.04], [18, 12]]} + } + }, + { + "id": "bridge-street-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["in", "class", "street", "street_link"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.5], + [10, 0.55], + [12, 0.75], + [14, 0.81], + [16, 0.96], + [18, 1.28], + [20, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]]} + } + }, + { + "id": "bridge-secondary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.75], + [12, 0.81], + [14, 0.96], + [16, 1.28], + [18, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [10, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + } + } + }, + { + "id": "bridge-primary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(187, 195, 206, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": 1, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "bridge-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "bridge-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(118, 148, 181, 1)", + "line-width": { + "base": 1.2, + "stops": [[10, 1], [12, 1.05], [14, 1.16], [16, 1.42], [18, 2]] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "bridge-major-tracks", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "major"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": [0.1, 15], + "line-opacity": {"stops": [[13.75, 0], [14, 1]]}, + "line-width": {"stops": [[14, 4], [20, 8]]} + } + }, + { + "id": "bridge-path", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "bridge"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [15, 1], [18, 4]]} + } + }, + { + "id": "bridge-pedestrian", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [16, 2], [18, 5]]} + } + }, + { + "id": "bridge-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": { + "base": 1.2, + "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] + } + } + }, + { + "id": "bridge-trunk-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-motorway-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-service", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": {"base": 1.2, "stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "bridge-street", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["in", "class", "street", "street_link"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "#D2DAE3", + "line-width": { + "base": 1.2, + "stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "bridge-secondary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-primary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-motorway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-service-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "bridge"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": {"base": 1.2, "stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "bridge-street-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["in", "class", "street", "street_link"], + ["==", "structure", "bridge"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "bridge-secondary-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "bridge"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-primary-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 218, 227, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-motorway-200", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"], + ["==", "done", 200] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(139, 165, 193, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "boundary-land-type-2-bg", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 7, + "filter": ["all", ["==", "type", 2]], + "layout": { + "line-join": "round", + "visibility": "none", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(237, 233, 217, 1)", + "line-dasharray": [1, 0], + "line-width": {"base": 1.4, "stops": [[3, 2], [10, 6]]}, + "line-opacity": {"stops": [[7, 0], [8, 0.5]]}, + "line-blur": {"stops": [[3, 0], [8, 3]]} + } + }, + { + "id": "boundary-land-type-1-bg", + "type": "line", + "source": "base", + "source-layer": "boundary", + "filter": ["all", ["==", "type", 1]], + "layout": { + "line-join": "round", + "visibility": "none", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(237, 233, 217, 1)", + "line-dasharray": [1, 0], + "line-width": {"base": 1.4, "stops": [[3, 3.5], [10, 8]]}, + "line-opacity": {"stops": [[7, 0], [8, 0.75]]}, + "line-blur": {"stops": [[3, 0], [8, 3]]} + } + }, + { + "id": "boundary-land-type-0-bg", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 1, + "maxzoom": 24, + "filter": ["all", ["==", "type", 0]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(237, 233, 217, 1)", + "line-width": { + "base": 1, + "stops": [[3, 3.5], [5, 4.79], [7, 6.07], [9, 7.36], [10, 8]] + }, + "line-opacity": {"stops": [[3, 0], [4, 0.5]]}, + "line-blur": { + "stops": [[3, 0.5], [5, 0.93], [7, 1.36], [9, 1.79], [10, 2]] + } + } + }, + { + "id": "boundary-land-type-2", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 13, + "filter": ["all", ["==", "type", 2]], + "layout": { + "line-join": "round", + "visibility": "visible", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(176, 174, 191, 1)", + "line-dasharray": {"stops": [[6, [5, 0]], [7, [5, 5, 5, 5]]]}, + "line-width": {"base": 1.4, "stops": [[7, 0.5], [12, 1]]}, + "line-opacity": {"stops": [[2, 0], [3, 0.75]]} + } + }, + { + "id": "boundary-land-type-1", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 5, + "filter": ["all", ["==", "type", 1]], + "layout": { + "line-join": "round", + "visibility": "visible", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(177, 181, 203, 1)", + "line-dasharray": {"stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]]}, + "line-width": {"base": 1.4, "stops": [[7, 0.75], [12, 1.5]]}, + "line-opacity": {"stops": [[2, 0], [3, 1]]} + } + }, + { + "id": "boundary-land-type-0", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 1, + "maxzoom": 24, + "filter": ["all", ["==", "type", 0]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(159, 164, 193, 1)", + "line-width": { + "base": 1, + "stops": [[3, 0.5], [5, 0.93], [7, 1.36], [9, 1.79], [10, 2]] + }, + "line-opacity": 1 + } + }, + { + "id": "building_flat", + "type": "fill", + "source": "composite", + "source-layer": "VN_Building", + "filter": ["all", ["<", "max_height", 10]], + "paint": {"fill-color": "#CECED1", "fill-opacity": 0.6} + }, + { + "id": "building", + "type": "fill-extrusion", + "source": "composite", + "source-layer": "VN_Building", + "minzoom": 16, + "filter": ["all", [">=", "max_height", 10]], + "layout": {"visibility": "visible"}, + "paint": { + "fill-extrusion-color": "rgba(143, 143, 151, 1)", + "fill-extrusion-height": [ + "interpolate", + ["linear"], + ["zoom"], + 15, + 0, + 15.05, + ["get", "max_height"] + ], + "fill-extrusion-base": [ + "interpolate", + ["linear"], + ["zoom"], + 15, + 0, + 15.05, + ["get", "min_height"] + ], + "fill-extrusion-opacity": 0.4 + } + }, + { + "id": "poi-park-scalerank-4", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 14, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 4] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-4", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 14, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 4] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-park-scalerank-3", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 3] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 0, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-3", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 3] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-park-scalerank-2", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 2] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[14, 11], [20, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-2", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 2] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[14, 11], [20, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-park-scalerank-1", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["<=", "scalerank", 1] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[10, 11], [18, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[13, "{maki}"], [14, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-1", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 1] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[10, 11], [18, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[13, "{maki}"], [14, "{maki}"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1.2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-railway", + "type": "symbol", + "source": "base", + "source-layer": "rail_station", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["in", "maki", "rail-metro", "rail"]], + "layout": { + "text-optional": true, + "text-size": 12, + "text-allow-overlap": false, + "icon-image": "{maki}", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-max-width": 9, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-airport", + "type": "symbol", + "source": "base", + "source-layer": "airport", + "minzoom": 9, + "maxzoom": 24, + "filter": ["all"], + "layout": { + "text-optional": true, + "text-size": {"stops": [[10, 12], [18, 18]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[12, "{maki}"], [13, "{maki}"]]}, + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 9, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-mountain", + "type": "symbol", + "source": "base", + "source-layer": "mountain", + "minzoom": 9, + "filter": ["all"], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[10, 12], [18, 18]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[13, "mountain-11"], [14, "mountain-15"]]}, + "icon-rotation-alignment": "auto", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "icon-size": 2, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(25, 118, 210, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "road-oneway-spaced-large", + "type": "symbol", + "source": "composite", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["==", "oneway", "true"], + [ + "in", + "class", + "motorway", + "trunk", + "primary", + "secondary", + "motorway_link" + ] + ], + "layout": { + "text-size": 16, + "icon-rotation-alignment": "map", + "icon-text-fit-padding": [0, 0, 0, 0], + "symbol-spacing": 75, + "icon-rotate": 0, + "symbol-placement": "line", + "text-padding": 2, + "visibility": "visible", + "icon-size": {"stops": [[15, 0.75], [19, 1.2]]}, + "icon-padding": 2, + "text-max-width": 10, + "icon-image": "oneway-large" + }, + "paint": {"icon-opacity": 1, "text-color": "#ffffff"} + }, + { + "id": "road-oneway-spaced-small", + "type": "symbol", + "source": "composite", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["==", "oneway", "true"], + ["in", "class", "street", "service"] + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 75, + "icon-padding": 2, + "icon-rotation-alignment": "map", + "icon-rotate": 0, + "icon-size": {"stops": [[15, 0.5], [19, 1.5]]}, + "visibility": "visible", + "icon-image": "oneway-white-small" + }, + "paint": {"icon-opacity": 1, "text-color": "#ffffff"} + }, + { + "id": "highway-name-minor", + "type": "symbol", + "source": "composite", + "source-layer": "streets_label", + "minzoom": 12, + "maxzoom": 22, + "filter": [ + "all", + [ + "in", + "class", + "service", + "motorway_link", + "trunk_link", + "primary_link", + "secondary_link" + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [[11, 9], [14, 10.33], [16, 11.22], [18, 12.11], [20, 13]] + }, + "text-font": ["Roboto Medium"], + "text-field": "{st_name}", + "symbol-placement": "line", + "text-rotation-alignment": "map", + "visibility": "visible", + "text-letter-spacing": 0.01, + "text-pitch-alignment": "viewport" + }, + "paint": { + "text-halo-blur": 1, + "text-color": "rgba(107, 107, 107, 1)", + "text-halo-width": 1.25, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "highway-name-medium", + "type": "symbol", + "source": "composite", + "source-layer": "streets_label", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "text-size": { + "base": 1, + "stops": [[11, 11], [14, 11.33], [16, 12.22], [18, 13.11], [20, 14]] + }, + "text-font": ["Roboto Medium"], + "text-field": "{st_name}", + "symbol-placement": "line", + "text-rotation-alignment": "map", + "visibility": "visible", + "text-letter-spacing": 0.01, + "text-pitch-alignment": "viewport" + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(107, 107, 107, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "highway-name-major", + "type": "symbol", + "source": "composite", + "source-layer": "streets_label", + "minzoom": 12, + "filter": [ + "all", + ["in", "class", "motorway", "trunk", "primary", "secondary"] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [9, 13], + [12, 11.64], + [14, 12.73], + [16, 13.82], + [18, 14.91], + [20, 16] + ] + }, + "text-font": ["Roboto Medium"], + "text-field": "{st_name}", + "symbol-placement": "line", + "text-rotation-alignment": "map", + "visibility": "visible", + "text-letter-spacing": 0.01, + "text-pitch-alignment": "viewport" + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(107, 107, 107, 1)", + "text-halo-width": 2, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "highway-shield-2", + "type": "symbol", + "source": "composite", + "source-layer": "roadshields", + "minzoom": 7, + "maxzoom": 24, + "filter": ["all", ["==", "func_class", 2]], + "layout": { + "text-line-height": 2, + "text-size": 12, + "icon-image": "rectangle-green-4", + "icon-rotation-alignment": "viewport", + "symbol-spacing": 200, + "text-font": ["OpenSans Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "point"]] + }, + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "auto", + "text-field": "{ref}", + "icon-pitch-alignment": "auto", + "icon-keep-upright": false, + "icon-size": 1.5, + "icon-allow-overlap": false, + "icon-ignore-placement": false, + "icon-optional": false + }, + "paint": { + "text-opacity": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-color": "rgba(255, 255, 255, 1)", + "icon-color": "rgba(0, 0, 0, 1)", + "icon-opacity": 0.75, + "text-translate-anchor": "map" + } + }, + { + "id": "highway-shield-1-copy", + "type": "symbol", + "source": "composite", + "source-layer": "roadshields", + "minzoom": 7, + "filter": ["all"], + "layout": { + "text-line-height": 2, + "text-size": 12, + "icon-image": "rectangle-green-4", + "icon-rotation-alignment": "viewport", + "symbol-spacing": 200, + "text-font": ["OpenSans Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [12, "point"]] + }, + "text-padding": 2, + "visibility": "none", + "text-rotation-alignment": "viewport", + "icon-size": 1.5, + "text-field": "{ref}", + "text-max-width": 7 + }, + "paint": { + "text-opacity": 1, + "text-halo-color": "rgba(50, 168, 82, 1)", + "text-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 0, + "icon-opacity": 0.75 + } + }, + { + "id": "river-name-1", + "type": "symbol", + "source": "composite", + "source-layer": "rivernames", + "minzoom": 14, + "filter": ["all", ["==", "priority", 1]], + "layout": { + "text-size": 12, + "symbol-spacing": 200, + "text-font": ["Roboto Regular"], + "symbol-placement": "line", + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name1}", + "text-letter-spacing": 0, + "text-max-width": 10, + "text-pitch-alignment": "viewport" + }, + "paint": { + "text-color": "rgba(74, 126, 171, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-translate-anchor": "map", + "text-halo-blur": 1.5 + } + }, + { + "id": "highway-shield-1", + "type": "symbol", + "source": "composite", + "source-layer": "roadshields", + "minzoom": 7, + "filter": ["all", ["==", "func_class", 1]], + "layout": { + "text-line-height": 2, + "text-size": 12, + "icon-rotation-alignment": "viewport", + "symbol-spacing": 200, + "text-font": ["OpenSans Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [12, "point"]] + }, + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "icon-size": 1.5, + "text-field": "{ref}", + "text-max-width": 7, + "icon-image": "rectangle-green-4" + }, + "paint": { + "text-opacity": 1, + "text-halo-color": "rgba(50, 168, 82, 1)", + "text-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 0, + "icon-opacity": 0.75 + } + }, + { + "id": "river-name-2", + "type": "symbol", + "source": "composite", + "source-layer": "rivernames", + "minzoom": 15, + "filter": ["all", ["==", "priority", 2]], + "layout": { + "text-size": 10, + "symbol-spacing": 200, + "text-font": ["Roboto Regular"], + "symbol-placement": "line", + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name1}", + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-pitch-alignment": "viewport" + }, + "paint": { + "text-color": "rgba(74, 126, 171, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1.5 + } + }, + { + "id": "river-name-0", + "type": "symbol", + "source": "composite", + "source-layer": "rivernames", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["==", "priority", 0]], + "layout": { + "text-size": 12, + "symbol-spacing": 250, + "text-font": ["Roboto Regular"], + "symbol-placement": "line", + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name1}", + "text-letter-spacing": 0.3, + "text-max-width": 10, + "text-pitch-alignment": "viewport" + }, + "paint": { + "text-color": "rgba(74, 126, 171, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1.5 + } + }, + { + "id": "lake-name_priority_2", + "type": "symbol", + "source": "composite", + "source-layer": "lakenames", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["==", "priority", 2]], + "layout": { + "text-size": {"stops": [[13, 9], [18, 11]]}, + "symbol-spacing": {"stops": [[9, 100], [22, 150]]}, + "text-font": ["Roboto Regular"], + "symbol-placement": "point", + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{name1}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": { + "text-color": "rgba(74, 126, 171, 1)", + "text-halo-width": 0, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "lake-name_priority_1", + "type": "symbol", + "source": "composite", + "source-layer": "lakenames", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "priority", 1]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[9, 16], [22, 14]]}, + "symbol-spacing": {"stops": [[9, 100], [22, 150]]}, + "text-font": ["Roboto Regular"], + "symbol-placement": "point", + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{name1}", + "text-letter-spacing": 0, + "text-max-width": 5 + }, + "paint": { + "text-color": "rgba(74, 126, 171, 1)", + "text-halo-width": 0, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "lake-name_priority_0", + "type": "symbol", + "source": "composite", + "source-layer": "lakenames", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["==", "priority", 0]], + "layout": { + "text-size": {"stops": [[9, 13], [22, 17]]}, + "symbol-z-order": "viewport-y", + "symbol-avoid-edges": false, + "symbol-spacing": {"stops": [[9, 100], [22, 150]]}, + "text-font": ["Roboto Regular"], + "symbol-placement": "point", + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{name1}", + "text-letter-spacing": 0.2, + "text-max-width": 5 + }, + "paint": { + "text-color": "rgba(74, 126, 171, 1)", + "text-halo-width": 1.5, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 10, + "maxzoom": 17, + "filter": ["all", ["==", "type", "village"], ["==", "scalerank", 2]], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": { + "base": 1.2, + "stops": [[10, 10.5], [12, 13.67], [14, 14.83], [16, 17]] + }, + "text-field": "{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "text-padding": 20, + "text-line-height": 2 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-neighbourhood2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 9, + "maxzoom": 17, + "filter": [ + "all", + ["==", "type", "neighbourhood"], + ["==", "scalerank", 2] + ], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": {"base": 1.2, "stops": [[11, 11.5], [13, 15]]}, + "text-field": "P.{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "text-line-height": 2, + "text-padding": 20 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-neighbourhood1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 9, + "maxzoom": 15, + "filter": [ + "all", + ["==", "type", "neighbourhood"], + ["==", "scalerank", 1] + ], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": {"base": 1.2, "stops": [[11, 10.5], [16, 15]]}, + "text-field": "{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "text-padding": 15 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-town1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 11, + "maxzoom": 18, + "filter": ["all", ["==", "type", "town"], ["==", "scalerank", 1]], + "layout": { + "text-size": {"base": 1.2, "stops": [[11, 11.5], [13, 16]]}, + "text-font": ["Roboto Medium"], + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "auto", + "text-pitch-alignment": "auto", + "text-field": "xã {name_vn}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-town2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 8, + "maxzoom": 18, + "filter": ["all", ["==", "type", "town"], ["==", "scalerank", 2]], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": {"base": 1.2, "stops": [[11, 11.5], [13, 16]]}, + "text-field": "Đặc khu {name_vn}", + "text-max-width": 8, + "visibility": "visible", + "icon-rotation-alignment": "auto", + "text-line-height": 10 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-suburb3", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 7, + "maxzoom": 16, + "filter": ["all", ["==", "type", "suburb"], ["==", "scalerank", 3]], + "layout": { + "text-size": {"base": 1.2, "stops": [[11, 11.5], [13, 16]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-anchor": "center", + "text-transform": "none", + "symbol-spacing": 200, + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 0.5, + "text-field": "P.{name_vn}", + "text-letter-spacing": 0.1, + "text-max-width": 7 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1.75, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-suburb2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 9, + "maxzoom": 13, + "filter": ["all", ["==", "type", "suburb"], ["==", "scalerank", 2]], + "layout": { + "text-size": {"base": 1.2, "stops": [[11, 11.5], [13, 16]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-anchor": "center", + "text-transform": "none", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 0.5, + "text-field": "P. {name_vn}", + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-suburb1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 6, + "maxzoom": 13, + "filter": ["all", ["==", "type", "suburb"], ["==", "scalerank", 1]], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1.2, "stops": [[11, 13.5], [13, 16]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-text-fit-padding": [0, 0, 0, 0], + "icon-anchor": "center", + "text-transform": "none", + "text-font": ["Roboto Medium"], + "text-padding": 2, + "visibility": "visible", + "icon-size": 0.5, + "text-field": "xã {name_vn}", + "text-letter-spacing": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1.75, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-borough", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 7, + "maxzoom": 13, + "filter": ["all", ["==", "type", "city"], ["==", "scalerank", 4]], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1.2, "stops": [[11, 13.5], [13, 16]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-anchor": "center", + "text-transform": "none", + "text-font": ["Roboto Medium"], + "text-padding": 2, + "visibility": "visible", + "icon-size": 0.5, + "text-field": "P. {name_vn}", + "text-letter-spacing": 0, + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 6, + "maxzoom": 13, + "filter": ["all", ["==", "type", "city"], ["==", "scalerank", 5]], + "layout": { + "text-size": {"base": 1.2, "stops": [[7, 15], [12, 22]]}, + "icon-pitch-alignment": "auto", + "icon-offset": [1, 10], + "icon-image": "dot-9", + "icon-anchor": "center", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 1, + "text-field": "{name_vn}", + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "icon-color": "rgba(0, 0, 0, 1)", + "icon-opacity": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 5, + "maxzoom": 13, + "filter": ["all", ["==", "type", "city"], ["==", "scalerank", 2]], + "layout": { + "text-size": {"base": 1.2, "stops": [[5, 13], [7, 16], [12, 23]]}, + "icon-offset": [1, 10], + "icon-image": "dot-11", + "icon-anchor": "center", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 1, + "text-field": "Tp.{name_vn}", + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city-capital", + "type": "symbol", + "source": "base", + "source-layer": "worldnationalcapitals", + "minzoom": 5, + "maxzoom": 11, + "filter": ["all"], + "layout": { + "text-size": {"base": 1.2, "stops": [[7, 13], [11, 23]]}, + "icon-image": "dot-11", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "text-offset": [0.4, 0], + "icon-size": 0.8, + "text-anchor": "left", + "text-field": "{city_name}", + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city-capital-vietnam", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 1, + "maxzoom": 17, + "filter": ["all", ["==", "type", "capital"]], + "layout": { + "text-size": {"base": 1.2, "stops": [[4, 14], [10, 23]]}, + "icon-image": "star", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "text-offset": [0.4, 0], + "icon-size": 0.8, + "text-anchor": "left", + "text-field": "{name_vn}", + "text-max-width": 8 + }, + "paint": { + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1.5, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1.5 + } + }, + { + "id": "place-island", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 6, + "filter": ["all", ["==", "code", 4]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[10, 10], [18, 15]]}, + "text-transform": "none", + "text-font": ["Roboto Regular"], + "text-padding": 12, + "visibility": "visible", + "text-rotation-alignment": "auto", + "text-pitch-alignment": "auto", + "text-field": "{name}", + "text-max-width": 6.25 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-archipelago", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 4, + "maxzoom": 22, + "filter": ["all", ["==", "code", 3]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[4, 10], [18, 15]]}, + "text-transform": "none", + "text-font": ["Roboto Regular"], + "text-padding": 12, + "visibility": "visible", + "text-rotation-alignment": "auto", + "text-pitch-alignment": "auto", + "text-field": "{name}", + "text-max-width": 6.25 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-bay", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 4, + "maxzoom": 22, + "filter": ["all", ["==", "code", 1]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[4, 13], [18, 15]]}, + "text-transform": "none", + "text-font": ["Roboto Regular"], + "text-padding": 12, + "visibility": "visible", + "text-rotation-alignment": "auto", + "text-pitch-alignment": "auto", + "text-field": "{name}", + "text-max-width": 6.25 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-ocean", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 4, + "maxzoom": 22, + "filter": ["any", ["==", "name", "Biển Đông"]], + "layout": { + "text-line-height": 1.2, + "text-size": {"stops": [[4, 10], [18, 23]]}, + "text-transform": "none", + "symbol-spacing": 250, + "text-font": ["Roboto Regular"], + "text-padding": 1, + "visibility": "visible", + "text-offset": [5, 0], + "text-rotation-alignment": "auto", + "text-pitch-alignment": "auto", + "text-field": "{name}", + "text-rotate": -40, + "text-letter-spacing": {"stops": [[6, 0.5], [7, 1]]}, + "text-max-width": 50 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-translate-anchor": "map" + } + }, + { + "id": "place-country-2", + "type": "symbol", + "source": "base", + "source-layer": "worldcountriespoints", + "filter": ["all", ["==", "code", 2]], + "layout": { + "text-font": ["Roboto Regular"], + "text-field": "{cntry_name}", + "text-size": {"stops": [[2, 10], [5, 16]]}, + "text-transform": "uppercase", + "text-max-width": 6.25, + "visibility": "visible" + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-country-1", + "type": "symbol", + "source": "base", + "source-layer": "worldcountriespoints", + "minzoom": 1, + "maxzoom": 15, + "filter": ["all", ["==", "code", 1]], + "layout": { + "text-font": ["Roboto Regular"], + "text-field": "{cntry_name}", + "text-size": {"stops": [[1, 10], [4, 16]]}, + "text-transform": "uppercase", + "text-max-width": 6.25, + "visibility": "visible" + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "rgba(68, 68, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + } + ], + "attribution": "© Goong.io", + "id": "7d086d5a-fb70-4a1e-93de-47ed55974a80", + "owner": "ledat" +} \ No newline at end of file diff --git a/tmp/goong-styles/goong_satellite.json b/tmp/goong-styles/goong_satellite.json new file mode 100644 index 0000000..34f16a5 --- /dev/null +++ b/tmp/goong-styles/goong_satellite.json @@ -0,0 +1,3294 @@ +{ + "version": 8, + "name": "GOONG-MAP-WEB_SATELLITE", + "metadata": {"maputnik:renderer": "mbgljs"}, + "zoom": 16.667414484254696, + "bearing": 0, + "pitch": 0, + "sources": { + "satellite": { + "type": "raster", + "url": "https://tiles.goong.io/sources/satellite.json?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7", + "tileSize": 256 + }, + "base": { + "type": "vector", + "url": "https://tiles.goong.io/sources/base.json?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7" + }, + "composite": { + "type": "vector", + "url": "https://tiles.goong.io/sources/goong.json?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7" + } + }, + "sprite": "https://tiles.goong.io/sprite", + "glyphs": "https://tiles.goong.io/fonts/{fontstack}/{range}.pbf?api_key=m9fAvOdFOmpI6RIdxIBX6gEACOyo545gXRp7saw7", + "layers": [ + { + "id": "background-satellite", + "type": "raster", + "source": "satellite", + "layout": {"visibility": "visible"} + }, + { + "id": "aeroway-taxiway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": ["all", ["==", "class", "aeroway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-width": {"base": 1.5, "stops": [[11, 2], [17, 12]]}, + "line-opacity": 1 + } + }, + { + "id": "aeroway-runway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": ["all", ["==", "class", "aeroway-runway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-width": {"base": 1.5, "stops": [[11, 5], [17, 55]]}, + "line-opacity": 1, + "line-translate-anchor": "map" + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 9, + "filter": ["all", ["in", "class", "aeroway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(219, 206, 219, 1)", + "line-width": {"base": 1.5, "stops": [[11, 1], [17, 10]]}, + "line-opacity": {"base": 1, "stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "aeroway-runway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 9, + "filter": ["all", ["==", "class", "aeroway-runway"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(219, 206, 219, 1)", + "line-width": {"base": 1.5, "stops": [[11, 4], [17, 50]]}, + "line-opacity": {"base": 1, "stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "tunnel-major", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "major"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": [1], + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "tunnel-path-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "tunnel"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(43, 43, 43, 1)", + "line-opacity": {"stops": [[0, 0], [14, 0.75]]}, + "line-width": {"stops": [[13, 1], [14, 2.5], [15, 2], [18, 7]]} + } + }, + { + "id": "tunnel-pedestrian-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(43, 43, 43, 1)", + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [18, 6]]} + } + }, + { + "id": "tunnel-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(43, 43, 43, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-trunk-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["==", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["==", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-service-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-street-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.5], + [10, 0.55], + [12, 0.75], + [14, 0.81], + [16, 0.96], + [18, 1.28], + [20, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]]}, + "line-dasharray": [3, 3] + }, + "line-dasharray": [3, 3] + }, + { + "id": "tunnel-secondary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.75], + [12, 0.81], + [14, 0.96], + [16, 1.28], + [18, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [10, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + } + }, + "line-dasharray": [3, 3] + }, + { + "id": "tunnel-primary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": 1, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [[10, 1], [12, 1.05], [14, 1.16], [16, 1.42], [18, 2]] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-path", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "tunnel"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [15, 1], [18, 4]]} + } + }, + { + "id": "tunnel-pedestrian", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [16, 2], [18, 5]]} + } + }, + { + "id": "tunnel-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-width": { + "base": 1.2, + "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] + }, + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-trunk-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(242, 207, 96, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "tunnel-motorway-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 161, 89, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "tunnel-service", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": {"base": 1.2, "stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "tunnel-street", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "tunnel-secondary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "tunnel-primary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "tunnel-trunk", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(242, 207, 96, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "tunnel-motorway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 161, 89, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-major", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "major"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 0.5)", + "line-dasharray": [1], + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "road-major-tracks", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "major"], ["==", "structure", "road"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(185, 185, 185, 0.5)", + "line-dasharray": [0.1, 15], + "line-opacity": {"stops": [[13.75, 0], [14, 1]]}, + "line-width": {"stops": [[14, 4], [20, 8]]} + } + }, + { + "id": "road-trunk-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["==", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 0.5)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-motorway-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["==", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 0.5)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-path", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "road"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 0.5)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [15, 1], [18, 4]]} + } + }, + { + "id": "road-pedestrian", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 0.5)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [16, 2], [18, 5]]} + } + }, + { + "id": "road-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "road"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 0.3)", + "line-width": { + "base": 1.2, + "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] + } + } + }, + { + "id": "road-trunk-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["in", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(242, 207, 96, 0.5)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-motorway-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "road"], + ["in", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 161, 89, 0.5)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "road-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 0.5)", + "line-width": { + "base": 1.2, + "stops": [[10, 1], [12, 1.05], [14, 1.16], [16, 1.42], [18, 2]] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "road-street", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": ["all", ["==", "class", "street"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 0.1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "road-secondary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 0.1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-primary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 0.1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-trunk", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": ["all", ["==", "class", "trunk"], ["==", "structure", "road"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(242, 207, 96, 0.5)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "road-motorway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "road"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 161, 89, 0.5)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-major", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "major"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": [1], + "line-opacity": 1, + "line-width": 1 + } + }, + { + "id": "bridge-path-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "bridge"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-opacity": {"stops": [[0, 0], [14, 0.75]]}, + "line-width": {"stops": [[13, 1], [14, 2.5], [15, 2], [18, 7]]} + } + }, + { + "id": "bridge-pedestrian-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [18, 6]]} + } + }, + { + "id": "bridge-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] + } + } + }, + { + "id": "bridge-trunk-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["==", "class", "trunk_link"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-motorway-link-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["==", "class", "motorway_link"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-service-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.75], [14, 0.81], [16, 0.96], [18, 1.28], [20, 2]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[14, 0.5], [16, 4.04], [18, 12]]} + } + }, + { + "id": "bridge-street-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.5], + [10, 0.55], + [12, 0.75], + [14, 0.81], + [16, 0.96], + [18, 1.28], + [20, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]}, + "line-gap-width": {"stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]]} + } + }, + { + "id": "bridge-secondary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.75], + [12, 0.81], + [14, 0.96], + [16, 1.28], + [18, 2] + ] + }, + "line-opacity": {"stops": [[0, 0], [10, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + } + } + }, + { + "id": "bridge-primary-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible", + "line-miter-limit": 0, + "line-round-limit": 0 + }, + "paint": { + "line-color": "rgba(217, 211, 201, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": 1, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "bridge-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [10, 0.85], + [12, 0.99], + [14, 1.3], + [16, 1.9], + [18, 2.2] + ] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "bridge-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "streets", + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [[10, 1], [12, 1.05], [14, 1.16], [16, 1.42], [18, 2]] + }, + "line-opacity": {"stops": [[0, 0], [9, 0], [11, 1]]}, + "line-gap-width": { + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + } + } + }, + { + "id": "bridge-major-tracks", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "major"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": [0.1, 15], + "line-opacity": {"stops": [[13.75, 0], [14, 1]]}, + "line-width": {"stops": [[14, 4], [20, 8]]} + } + }, + { + "id": "bridge-path", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["==", "class", "path"], ["==", "structure", "bridge"]], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [15, 1], [18, 4]]} + } + }, + { + "id": "bridge-pedestrian", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-dasharray": { + "stops": [ + [0, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": 1, + "line-width": {"stops": [[13, 0.5], [14, 1], [16, 2], [18, 5]]} + } + }, + { + "id": "bridge-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "primary_link", "secondary_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(210, 212, 220, 1)", + "line-width": { + "base": 1.2, + "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] + } + } + }, + { + "id": "bridge-trunk-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "trunk_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(242, 207, 96, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-motorway-link", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "motorway_link"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 161, 89, 1)", + "line-width": {"stops": [[12, 0.5], [14, 2], [16, 9.92], [18, 18]]} + } + }, + { + "id": "bridge-service", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "service"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": {"base": 1.2, "stops": [[14, 0.5], [16, 4.04], [18, 12]]}, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "bridge-street", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [[12, 0.5], [14, 2], [16, 6.92], [18, 18]] + }, + "line-opacity": {"stops": [[0, 0], [14, 1]]} + } + }, + { + "id": "bridge-secondary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "secondary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.1], + [7, 0.27], + [9, 0.64], + [11, 1.49], + [13, 3.39], + [15, 7.68], + [17, 17.32], + [18, 26] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-primary", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(242, 207, 96, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-motorway", + "type": "line", + "source": "composite", + "source-layer": "streets", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 161, 89, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [5, 0.75], + [7, 0.95], + [9, 1.41], + [11, 2.43], + [13, 4.73], + [15, 9.9], + [17, 21.53], + [18, 32] + ] + }, + "line-opacity": 1 + } + }, + { + "id": "boundary-land-type-2-bg", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 7, + "filter": ["all", ["==", "type", 2]], + "layout": { + "line-join": "round", + "visibility": "none", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(237, 233, 217, 1)", + "line-dasharray": [1, 0], + "line-width": {"base": 1.4, "stops": [[3, 2], [10, 6]]}, + "line-opacity": {"stops": [[7, 0], [8, 0.5]]}, + "line-blur": {"stops": [[3, 0], [8, 3]]} + } + }, + { + "id": "boundary-land-type-1-bg", + "type": "line", + "source": "base", + "source-layer": "boundary", + "filter": ["all", ["==", "type", 1]], + "layout": { + "line-join": "round", + "visibility": "none", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(237, 233, 217, 1)", + "line-dasharray": [1, 0], + "line-width": {"base": 1.4, "stops": [[3, 3.5], [10, 8]]}, + "line-opacity": {"stops": [[7, 0], [8, 0.75]]}, + "line-blur": {"stops": [[3, 0], [8, 3]]} + } + }, + { + "id": "boundary-land-type-0-bg", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 1, + "maxzoom": 24, + "filter": ["all", ["==", "type", 0]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "none" + }, + "paint": { + "line-color": "rgba(237, 233, 217, 1)", + "line-width": { + "base": 1, + "stops": [[3, 3.5], [5, 4.79], [7, 6.07], [9, 7.36], [10, 8]] + }, + "line-opacity": {"stops": [[3, 0], [4, 0.5]]}, + "line-blur": { + "stops": [[3, 0.5], [5, 0.93], [7, 1.36], [9, 1.79], [10, 2]] + } + } + }, + { + "id": "boundary-land-type-2", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 7, + "filter": ["all", ["==", "type", 2]], + "layout": { + "line-join": "round", + "visibility": "none", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(120, 118, 128, 1)", + "line-dasharray": {"stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]]}, + "line-width": {"base": 1.4, "stops": [[7, 0.5], [12, 1]]}, + "line-opacity": {"stops": [[2, 0], [3, 0.75]]} + } + }, + { + "id": "boundary-land-type-1", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 5, + "filter": ["all", ["==", "type", 1]], + "layout": { + "line-join": "round", + "visibility": "visible", + "line-cap": "round" + }, + "paint": { + "line-color": "rgba(177, 181, 203, 1)", + "line-dasharray": {"stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]]}, + "line-width": {"base": 1.4, "stops": [[7, 0.75], [12, 1.5]]}, + "line-opacity": {"stops": [[2, 0], [3, 1]]} + } + }, + { + "id": "boundary-land-type-0", + "type": "line", + "source": "base", + "source-layer": "boundary", + "minzoom": 1, + "maxzoom": 24, + "filter": ["all", ["==", "type", 0]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(159, 164, 193, 1)", + "line-width": { + "base": 1, + "stops": [[3, 0.5], [5, 0.93], [7, 1.36], [9, 1.79], [10, 2]] + }, + "line-opacity": 1 + } + }, + { + "id": "poi-park-scalerank-4", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 14, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 4] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(76, 102, 31, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-4", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 14, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 4] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(101, 81, 61, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-park-scalerank-3", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 13, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 3] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 0, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(76, 102, 31, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-3", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 3] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[16, 11], [20, 13]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(96, 59, 39, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-park-scalerank-2", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 11, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 2] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[14, 11], [20, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(76, 102, 31, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-2", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 2] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[14, 11], [20, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[14, "{maki}"], [15, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(101, 81, 61, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-park-scalerank-1", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 9, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["<=", "scalerank", 1] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[10, 11], [18, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[13, "{maki}"], [14, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(76, 102, 31, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-scalerank-1", + "type": "symbol", + "source": "composite", + "source-layer": "point_map", + "minzoom": 9, + "maxzoom": 24, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "park", + "golf", + "swimming", + "zoo" + ], + ["==", "scalerank", 1] + ], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[10, 11], [18, 14]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[13, "{maki}"], [14, "{maki}"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(101, 81, 61, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-railway", + "type": "symbol", + "source": "base", + "source-layer": "rail_station", + "minzoom": 12, + "maxzoom": 24, + "filter": ["all", ["in", "maki", "rail-metro", "rail"]], + "layout": { + "text-optional": true, + "text-size": 12, + "text-allow-overlap": false, + "icon-image": "{maki}-15", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-max-width": 9, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "rgba(57, 98, 162, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-airport", + "type": "symbol", + "source": "base", + "source-layer": "airport", + "minzoom": 9, + "maxzoom": 24, + "filter": ["all"], + "layout": { + "text-optional": true, + "text-size": {"stops": [[10, 12], [18, 18]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[12, "{maki}-11"], [13, "{maki}-15"]]}, + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 9, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "rgba(66, 67, 68, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "poi-mountain", + "type": "symbol", + "source": "base", + "source-layer": "mountain", + "minzoom": 9, + "filter": ["all"], + "layout": { + "text-optional": true, + "text-line-height": 1.2, + "text-size": {"stops": [[10, 12], [18, 18]]}, + "text-allow-overlap": false, + "icon-image": {"stops": [[13, "mountain-11"], [14, "mountain-15"]]}, + "icon-rotation-alignment": "map", + "text-ignore-placement": false, + "text-font": ["Roboto Regular"], + "icon-allow-overlap": false, + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 0.6], + "icon-optional": false, + "text-anchor": "top", + "text-field": "{name}", + "text-letter-spacing": 0.02, + "text-max-width": 8, + "icon-ignore-placement": false + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(76, 102, 31, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "road-oneway-spaced-small", + "type": "symbol", + "source": "composite", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["==", "oneway", "true"], + ["in", "class", "street", "service"] + ], + "layout": { + "symbol-placement": "line", + "icon-image": "oneway-spaced-small", + "symbol-spacing": 75, + "icon-padding": 2, + "icon-rotation-alignment": "map", + "icon-rotate": 0, + "icon-size": {"stops": [[15, 0.5], [19, 1.5]]}, + "visibility": "visible" + }, + "paint": {"icon-opacity": 1} + }, + { + "id": "road-oneway-spaced-large", + "type": "symbol", + "source": "composite", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["==", "oneway", "true"], + ["in", "class", "motorway", "trunk", "primary", "secondary"] + ], + "layout": { + "text-size": 16, + "icon-image": "oneway-spaced-large", + "icon-rotation-alignment": "map", + "icon-text-fit-padding": [0, 0, 0, 0], + "symbol-spacing": 75, + "icon-rotate": 0, + "symbol-placement": "line", + "text-padding": 2, + "visibility": "visible", + "icon-size": {"stops": [[15, 0.75], [19, 1.2]]}, + "icon-padding": 2, + "text-max-width": 10 + }, + "paint": {"icon-opacity": 1} + }, + { + "id": "highway-name-minor", + "type": "symbol", + "source": "composite", + "source-layer": "streets_label", + "minzoom": 12, + "maxzoom": 22, + "filter": [ + "all", + [ + "in", + "class", + "service", + "mortorway_link", + "trunk_link", + "primary_link", + "secondary_link" + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [[11, 9], [14, 10.33], [16, 11.22], [18, 12.11], [20, 13]] + }, + "text-font": ["Roboto Medium"], + "text-field": "{st_name}", + "symbol-placement": "line", + "text-rotation-alignment": "map", + "visibility": "visible", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-halo-blur": 1, + "text-color": "rgba(107, 107, 107, 1)", + "text-halo-width": 1.25, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "highway-name-medium", + "type": "symbol", + "source": "composite", + "source-layer": "streets_label", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "text-size": { + "base": 1, + "stops": [[11, 11], [14, 11.33], [16, 12.22], [18, 13.11], [20, 14]] + }, + "text-font": ["Roboto Medium"], + "text-field": "{st_name}", + "symbol-placement": "line", + "text-rotation-alignment": "map", + "visibility": "visible", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(107, 107, 107, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "highway-name-major", + "type": "symbol", + "source": "composite", + "source-layer": "streets_label", + "minzoom": 12, + "filter": [ + "all", + ["in", "class", "mortorway", "trunk", "primary", "secondary"] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [9, 13], + [12, 11.64], + [14, 12.73], + [16, 13.82], + [18, 14.91], + [20, 16] + ] + }, + "text-font": ["Roboto Medium"], + "text-field": "{st_name}", + "symbol-placement": "line", + "text-rotation-alignment": "map", + "visibility": "visible", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "rgba(107, 107, 107, 1)", + "text-halo-width": 2, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "highway-shield-2", + "type": "symbol", + "source": "composite", + "source-layer": "roadshields", + "minzoom": 7, + "maxzoom": 24, + "filter": ["all", ["==", "func_class", 2]], + "layout": { + "text-line-height": 2, + "text-size": 10, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "symbol-spacing": 200, + "text-font": ["Roboto Regular"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "point"]] + }, + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "icon-size": 1, + "text-field": "{ref}" + }, + "paint": { + "text-opacity": 1, + "text-halo-width": 0, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-color": "rgba(18, 18, 18, 1)" + } + }, + { + "id": "highway-shield-1", + "type": "symbol", + "source": "composite", + "source-layer": "roadshields", + "minzoom": 7, + "filter": ["all", ["==", "func_class", 1]], + "layout": { + "text-line-height": 2, + "text-size": 10, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "symbol-spacing": 200, + "text-font": ["Roboto Medium"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [12, "point"]] + }, + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "icon-size": 1, + "text-field": "{ref}", + "text-max-width": 7 + }, + "paint": { + "text-opacity": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-color": "rgba(18, 18, 18, 1)", + "text-halo-width": 0 + } + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 10, + "maxzoom": 17, + "filter": ["all", ["==", "type", "village"], ["==", "scalerank", 2]], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": { + "base": 1.2, + "stops": [[10, 11.5], [12, 13.67], [14, 15.83], [16, 18]] + }, + "text-field": "{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "text-padding": 20, + "text-line-height": 2 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-neighbourhood2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 9, + "maxzoom": 13, + "filter": [ + "all", + ["==", "type", "neighbourhood"], + ["==", "scalerank", 2] + ], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": {"base": 1.2, "stops": [[9, 10], [11, 11.5], [16, 16]]}, + "text-field": "P.{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "text-line-height": 2, + "text-padding": 20 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-neighbourhood1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 9, + "maxzoom": 15, + "filter": [ + "all", + ["==", "type", "neighbourhood"], + ["==", "scalerank", 1] + ], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": {"base": 1.2, "stops": [[11, 11.5], [16, 16]]}, + "text-field": "{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "text-padding": 15 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-town1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 11, + "maxzoom": 18, + "filter": ["all", ["==", "type", "town"], ["==", "scalerank", 1]], + "layout": { + "text-size": {"base": 1.2, "stops": [[11, 12.5], [13, 17], [16, 17]]}, + "text-font": ["Roboto Medium"], + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-pitch-alignment": "map", + "text-field": "{name_vn}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-town2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 8, + "maxzoom": 18, + "filter": ["all", ["==", "type", "town"], ["==", "scalerank", 2]], + "layout": { + "text-font": ["Roboto Medium"], + "text-size": {"base": 1.2, "stops": [[11, 14], [15, 17]]}, + "text-field": "{name_vn}", + "text-max-width": 8, + "visibility": "visible", + "icon-rotation-alignment": "auto", + "text-line-height": 10 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-suburb3", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 7, + "maxzoom": 16, + "filter": ["all", ["==", "type", "suburb"], ["==", "scalerank", 3]], + "layout": { + "text-size": { + "base": 1.2, + "stops": [[11, 11], [12, 13.25], [13, 15.5], [14, 17.75], [15, 20]] + }, + "icon-offset": [1, 10], + "icon-image": "", + "icon-anchor": "center", + "text-transform": "uppercase", + "symbol-spacing": 200, + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 0.5, + "text-field": "{name_vn}", + "text-letter-spacing": 0.1, + "text-max-width": 7 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1.75, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-suburb2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 9, + "maxzoom": 13, + "filter": ["all", ["==", "type", "suburb"], ["==", "scalerank", 2]], + "layout": { + "text-size": {"base": 1.2, "stops": [[11, 11], [15, 20]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-anchor": "center", + "text-transform": "uppercase", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 0.5, + "text-field": "{name_vn}", + "text-letter-spacing": 0.15, + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-suburb1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 7, + "maxzoom": 13, + "filter": ["all", ["==", "type", "suburb"], ["==", "scalerank", 1]], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1.2, "stops": [[7, 12], [15, 20]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-text-fit-padding": [0, 0, 0, 0], + "icon-anchor": "center", + "text-transform": "uppercase", + "text-font": ["Roboto Regular"], + "text-padding": 2, + "visibility": "visible", + "icon-size": 0.5, + "text-field": { + "stops": [[8, "{name_vn}"], [10, "{name_vn}"], [11, "{name_vn}"]] + }, + "text-letter-spacing": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1.75, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1 + } + }, + { + "id": "place-borough", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 7, + "maxzoom": 13, + "filter": ["all", ["==", "type", "city"], ["==", "scalerank", 4]], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1.2, "stops": [[7, 13], [11, 20]]}, + "icon-offset": [1, 10], + "icon-image": "", + "icon-anchor": "center", + "text-transform": "none", + "text-font": ["Roboto Medium"], + "text-padding": 2, + "visibility": "visible", + "icon-size": 0.5, + "text-field": "Tx.{name_vn}", + "text-letter-spacing": 0, + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city2", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 6, + "maxzoom": 13, + "filter": ["all", ["==", "type", "city"], ["==", "scalerank", 5]], + "layout": { + "text-size": {"base": 1.2, "stops": [[7, 14], [11, 24]]}, + "icon-pitch-alignment": "auto", + "icon-offset": [1, 10], + "icon-image": "dot-9", + "icon-anchor": "center", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 1, + "text-field": { + "stops": [[6, "{name_vn}"], [8, "Tp.{name_vn}"], [10, "{name_vn}"]] + }, + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "icon-color": "rgba(0, 0, 0, 1)", + "icon-opacity": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city1", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 5, + "maxzoom": 13, + "filter": ["all", ["==", "type", "city"], ["==", "scalerank", 2]], + "layout": { + "text-size": {"base": 1.2, "stops": [[5, 14], [7, 17], [12, 24]]}, + "icon-offset": [1, 10], + "icon-image": "dot-11", + "icon-anchor": "center", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "icon-size": 1, + "text-field": "Tp.{name_vn}", + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city-capital", + "type": "symbol", + "source": "base", + "source-layer": "worldnationalcapitals", + "minzoom": 5, + "maxzoom": 11, + "filter": ["all"], + "layout": { + "text-size": {"base": 1.2, "stops": [[7, 14], [11, 24]]}, + "icon-image": "dot-11", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "text-offset": [0.4, 0], + "icon-size": 0.8, + "text-anchor": "left", + "text-field": "{city_name}", + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-city-capital-vietnam", + "type": "symbol", + "source": "composite", + "source-layer": "vietnam_administrator", + "minzoom": 1, + "maxzoom": 10, + "filter": ["all", ["==", "type", "capital"]], + "layout": { + "text-size": {"base": 1.2, "stops": [[4, 15], [10, 24]]}, + "icon-image": "star", + "text-font": ["Roboto Medium"], + "visibility": "visible", + "text-offset": [0.4, 0], + "icon-size": 0.8, + "text-anchor": "left", + "text-field": "{name_vn}", + "text-max-width": 8 + }, + "paint": { + "text-color": "#78888a", + "text-halo-width": 1.5, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-blur": 1.5 + } + }, + { + "id": "place-island", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 6, + "filter": ["all", ["==", "code", 4]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[10, 11], [18, 16]]}, + "text-transform": "none", + "text-font": ["Roboto Regular"], + "text-padding": 12, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-pitch-alignment": "map", + "text-field": "{name}", + "text-max-width": 6.25 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-archipelago", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 4, + "maxzoom": 22, + "filter": ["all", ["==", "code", 3]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[4, 11], [18, 16]]}, + "text-transform": "none", + "text-font": ["Roboto Regular"], + "text-padding": 12, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-pitch-alignment": "map", + "text-field": "{name}", + "text-max-width": 6.25 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-bay", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 4, + "maxzoom": 22, + "filter": ["all", ["==", "code", 1]], + "layout": { + "text-line-height": 1, + "text-size": {"stops": [[4, 14], [18, 16]]}, + "text-transform": "none", + "text-font": ["Roboto Regular"], + "text-padding": 12, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-pitch-alignment": "map", + "text-field": "{name}", + "text-max-width": 6.25 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-ocean", + "type": "symbol", + "source": "base", + "source-layer": "island", + "minzoom": 4, + "maxzoom": 22, + "filter": ["any", ["==", "name", "Biển Đông"]], + "layout": { + "text-line-height": 1.2, + "text-size": {"stops": [[4, 11], [18, 24]]}, + "text-transform": "none", + "symbol-spacing": 250, + "text-font": ["Roboto Regular"], + "text-padding": 1, + "visibility": "visible", + "text-offset": [5, 0], + "text-rotation-alignment": "map", + "text-pitch-alignment": "map", + "text-field": "{name}", + "text-rotate": -40, + "text-letter-spacing": {"stops": [[6, 0.5], [7, 1]]}, + "text-max-width": 50 + }, + "paint": { + "text-halo-blur": 0, + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-translate-anchor": "map" + } + }, + { + "id": "place-country-2", + "type": "symbol", + "source": "base", + "source-layer": "worldcountriespoints", + "filter": ["all", ["==", "code", 2]], + "layout": { + "text-font": ["Roboto Regular"], + "text-field": "{cntry_name}", + "text-size": {"stops": [[2, 11], [5, 17]]}, + "text-transform": "uppercase", + "text-max-width": 6.25, + "visibility": "visible" + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "place-country-1", + "type": "symbol", + "source": "base", + "source-layer": "worldcountriespoints", + "minzoom": 1, + "maxzoom": 15, + "filter": ["all", ["==", "code", 1]], + "layout": { + "text-font": ["Roboto Regular"], + "text-field": "{cntry_name}", + "text-size": {"stops": [[1, 11], [4, 17]]}, + "text-transform": "uppercase", + "text-max-width": 6.25, + "visibility": "visible" + }, + "paint": { + "text-halo-blur": 0.5, + "text-color": "#78888a", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + } + ], + "id": "7d086d5a-fb70-4a1e-93de-47ed55974a80", + "attribution": "© Goong.io" +} \ No newline at end of file