Offline-capable geomap, meant for storing location bookmarks
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: cleanup layers

+96 -395
+1 -1
data/cli/shared/tilemaker/config.json
··· 32 32 }, 33 33 "transportation_name": { "minzoom": 8, "maxzoom": 14 }, 34 34 35 - "building": { "minzoom": 13, "maxzoom": 14 }, 35 + "building": { "minzoom": 12, "maxzoom": 14 }, 36 36 37 37 "water": { 38 38 "minzoom": 6,
+10 -1
data/cli/shared/tilemaker/process.lua
··· 628 628 if building~="" then 629 629 Layer("building", true) 630 630 SetBuildingHeightAttributes() 631 - SetMinZoomByArea() 631 + SetBuildingMinZoomByArea() 632 632 end 633 633 634 634 -- Set 'housenumber' ··· 787 787 -- Set minimum zoom level by area 788 788 function SetMinZoomByArea() 789 789 SetMinZoomByAreaWithLimit(0) 790 + end 791 + 792 + -- Buildings: pop in together around z12–z13 instead of dribbling 793 + -- in tier-by-tier through z14. Big footprints get z12, everything 794 + -- else gets z13 so the style's z12→z13 fade covers both. 795 + function SetBuildingMinZoomByArea() 796 + local area=Area() 797 + if area>ZRES12^2 then MinZoom(12) 798 + else MinZoom(13) end 790 799 end 791 800 792 801 -- Set minimum zoom level by area but not below given minzoom
+5 -7
www/components/m-map.ts
··· 625 625 626 626 async #loadWorldTiles(): Promise<void> { 627 627 if (!this.#map) return 628 - let worldFilename = 'world_z3.pmtiles' 628 + let worldFilename = 'world_z5.pmtiles' 629 629 if (!registeredSources.has('world')) { 630 - const [z7, z6, z5] = await Promise.all([ 630 + const [z7, z6] = await Promise.all([ 631 631 getCachedPMTiles('world/world_z7.pmtiles'), 632 632 getCachedPMTiles('world/world_z6.pmtiles'), 633 - getCachedPMTiles('world/world_z5.pmtiles'), 634 633 ]) 635 634 636 635 if (z7) worldFilename = 'world/world_z7.pmtiles' 637 636 else if (z6) worldFilename = 'world/world_z6.pmtiles' 638 - else if (z5) worldFilename = 'world/world_z5.pmtiles' 639 - const pmtiles = z7 ?? z6 ?? z5 ?? await downloadAndSavePMTiles( 640 - '/static/tiles/world/world_z3.pmtiles', 641 - 'world_z3.pmtiles', 637 + const pmtiles = z7 ?? z6 ?? await downloadAndSavePMTiles( 638 + '/static/tiles/world/world_z5.pmtiles', 639 + 'world_z5.pmtiles', 642 640 ) 643 641 protocol.add(pmtiles) 644 642 registeredSources.add('world')
+4 -4
www/models/app.ts
··· 24 24 lastView: null, 25 25 } 26 26 27 - const backend = new IDBStorage({ dbName: 'maps-store' }) 28 - const blobBackend = new IDBBlobStorage({ dbName: 'maps-store' }) 27 + const backend = new IDBStorage({ dbName: 'bpev-maps' }) 28 + const blobBackend = new IDBBlobStorage({ dbName: 'bpev-maps' }) 29 29 const blobStore = new BlobStore(blobBackend) 30 30 const store = new Store(backend, { 31 31 documents: ['preferences', 'searchHistory'], ··· 337 337 req.onblocked = () => resolve() 338 338 }) 339 339 340 - await deleteDB('maps-store') 341 - await deleteDB('maps-blobs') 340 + await deleteDB('bpev-maps') 341 + await deleteDB('bpev-maps-blobs') 342 342 return { success: true } 343 343 } catch (error) { 344 344 return {
+53 -53
www/utils/LAYERS.md
··· 7 7 8 8 ## Layer counts 9 9 10 - | Source | Before | After | Saved | 11 - |--------|--------|-------|-------| 12 - | Regional (per tile) | 47 | 34 | 13 | 13 - | World | 17 | 10 | 7 | 14 - | Bookmarks | 5 | 5 | — | 10 + | Source | Before | After | Saved | 11 + | ------------------- | ------ | ----- | ----- | 12 + | Regional (per tile) | 47 | 34 | 13 | 13 + | World | 17 | 10 | 7 | 14 + | Bookmarks | 5 | 5 | — | 15 15 16 16 With 3 regional tiles loaded: **156 → 117 layers** (25% reduction). 17 17 ··· 19 19 20 20 34 layers, rendered bottom to top: 21 21 22 - | # | Layer ID | Type | Source-layer | Notes | 23 - |---|----------|------|-------------|-------| 24 - | 1 | `landuse-residential` | fill | landuse | z11+, residential/suburb/neighbourhood | 25 - | 2 | `landcover` | fill | landcover | **Merged** grass + wood + sand via `match` on class | 26 - | 3 | `water` | fill | water | **Merged** normal + intermittent via opacity expression | 27 - | 4 | `landcover-ice-shelf` | fill | landcover | Separate — renders above water | 28 - | 5 | `landcover-glacier` | fill | landcover | Separate — opacity ramp z0→z8 | 29 - | 6 | `landuse` | fill | landuse | Agriculture | 30 - | 7 | `landuse_overlay_national_park` | fill | landcover | Opacity ramp z5→z9 | 31 - | 8 | `waterway-tunnel` | line | waterway | Dashed + gap-width (unique paint) | 32 - | 9 | `waterway` | line | waterway | Normal waterways | 33 - | 10 | `waterway_intermittent` | line | waterway | Dashed (can't merge — `line-dasharray` not data-driven) | 34 - | 11 | `tunnel_railway_transit` | line | transportation | Kept separate — opacity ramp differs from road tunnels | 35 - | 12 | `building` | fill | building | z13+ fade-in | 36 - | 13 | `housenumber` | symbol | housenumber | z17+ | 37 - | 14 | `road_area_pier` | fill | transportation | Polygon piers | 38 - | 15 | `road_pier` | line | transportation | Line piers | 39 - | 16 | `road_bridge_area` | fill | transportation | Bridge polygons | 40 - | 17 | `road_path` | line | transportation | Kept separate — dashed, square cap | 41 - | 18 | `tunnel_road` | line | transportation | **Merged** minor + major tunnels | 42 - | 19 | `aeroway-area` | fill | aeroway | Runway/taxiway polygons | 43 - | 20 | `aeroway-taxiway` | line | aeroway | Kept separate — different minzoom/width from runway | 44 - | 21 | `aeroway-runway` | line | aeroway | z4+ | 45 - | 22 | `road` | line | transportation | **Merged** minor, service, secondary, tertiary, trunk, primary, motorway — class-based `line-width` | 46 - | 23 | `railway` | line | transportation | **Merged** rail + transit | 47 - | 24 | `waterway-bridge-case` | line | waterway | Different source-layer from road bridges | 48 - | 25 | `waterway-bridge` | line | waterway | | 49 - | 26 | `bridge_case` | line | transportation | **Merged** minor + major bridge casing | 50 - | 27 | `bridge` | line | transportation | **Merged** minor + major bridge fill | 51 - | 28 | `admin_sub` | line | boundary | State/province boundaries | 52 - | 29 | `admin_country` | line | boundary | z5+ only — world tiles cover z0–5 | 53 - | 30 | `poi_label` | symbol | poi | z15+, rank 1 only | 54 - | 31 | `airport-label` | symbol | aerodrome_label | z11+, IATA airports | 55 - | 32 | `road_major_label` | symbol | transportation_name | z14+, line placement | 56 - | 33 | `place_label` | symbol | place | **Merged** city + town + suburb/neighbourhood/quarter — single collision pass, class-based text-size/font/color | 57 - | 34 | `country_label` | symbol | place | Country names z0–12 | 22 + | # | Layer ID | Type | Source-layer | Notes | 23 + | -- | ------------------------------- | ------ | ------------------- | --------------------------------------------------------------------------------------------------------------- | 24 + | 1 | `landuse-residential` | fill | landuse | z11+, residential/suburb/neighbourhood | 25 + | 2 | `landcover` | fill | landcover | **Merged** grass + wood + sand via `match` on class | 26 + | 3 | `water` | fill | water | **Merged** normal + intermittent via opacity expression | 27 + | 4 | `landcover-ice-shelf` | fill | landcover | Separate — renders above water | 28 + | 5 | `landcover-glacier` | fill | landcover | Separate — opacity ramp z0→z8 | 29 + | 6 | `landuse` | fill | landuse | Agriculture | 30 + | 7 | `landuse_overlay_national_park` | fill | landcover | Opacity ramp z5→z9 | 31 + | 8 | `waterway-tunnel` | line | waterway | Dashed + gap-width (unique paint) | 32 + | 9 | `waterway` | line | waterway | Normal waterways | 33 + | 10 | `waterway_intermittent` | line | waterway | Dashed (can't merge — `line-dasharray` not data-driven) | 34 + | 11 | `tunnel_railway_transit` | line | transportation | Kept separate — opacity ramp differs from road tunnels | 35 + | 12 | `building` | fill | building | z13+ fade-in | 36 + | 13 | `housenumber` | symbol | housenumber | z17+ | 37 + | 14 | `road_area_pier` | fill | transportation | Polygon piers | 38 + | 15 | `road_pier` | line | transportation | Line piers | 39 + | 16 | `road_bridge_area` | fill | transportation | Bridge polygons | 40 + | 17 | `road_path` | line | transportation | Kept separate — dashed, square cap | 41 + | 18 | `tunnel_road` | line | transportation | **Merged** minor + major tunnels | 42 + | 19 | `aeroway-area` | fill | aeroway | Runway/taxiway polygons | 43 + | 20 | `aeroway-taxiway` | line | aeroway | Kept separate — different minzoom/width from runway | 44 + | 21 | `aeroway-runway` | line | aeroway | z4+ | 45 + | 22 | `road` | line | transportation | **Merged** minor, service, secondary, tertiary, trunk, primary, motorway — class-based `line-width` | 46 + | 23 | `railway` | line | transportation | **Merged** rail + transit | 47 + | 24 | `waterway-bridge-case` | line | waterway | Different source-layer from road bridges | 48 + | 25 | `waterway-bridge` | line | waterway | | 49 + | 26 | `bridge_case` | line | transportation | **Merged** minor + major bridge casing | 50 + | 27 | `bridge` | line | transportation | **Merged** minor + major bridge fill | 51 + | 28 | `admin_sub` | line | boundary | State/province boundaries | 52 + | 29 | `admin_country` | line | boundary | z5+ only — world tiles cover z0–5 | 53 + | 30 | `poi_label` | symbol | poi | z15+, rank 1 only | 54 + | 31 | `airport-label` | symbol | aerodrome_label | z11+, IATA airports | 55 + | 32 | `road_major_label` | symbol | transportation_name | z14+, line placement | 56 + | 33 | `place_label` | symbol | place | **Merged** city + town + suburb/neighbourhood/quarter — single collision pass, class-based text-size/font/color | 57 + | 34 | `country_label` | symbol | place | Country names z0–12 | 58 58 59 59 ## World layers (`world_layers.ts`) 60 60 61 61 10 layers: 62 62 63 - | # | Layer ID | Type | Source-layer | Notes | 64 - |---|----------|------|-------------|-------| 65 - | 1 | `water` | fill | water | Oceans + inland water | 66 - | 2 | `landcover` | fill | landcover | **Merged** grass, wood, wetland, sand, rock, ice — class-based color + opacity | 67 - | 3 | `park` | fill | park | National parks, nature reserves | 68 - | 4 | `waterway` | line | waterway | z6+, named rivers | 69 - | 5 | `boundary-state` | line | boundary | z3+, admin levels 3–6 | 70 - | 6 | `boundary-country` | line | boundary | Admin level 2 | 71 - | 7 | `place-continent` | symbol | place | z0–3, uppercase | 72 - | 8 | `place-country` | symbol | place | z0–7, Medium font for sovereign states | 73 - | 9 | `place-state` | symbol | place | z4–8, uppercase | 74 - | 10 | `place-settlement` | symbol | place | **Merged** city + town + village — class-based text-size | 63 + | # | Layer ID | Type | Source-layer | Notes | 64 + | -- | ------------------ | ------ | ------------ | ------------------------------------------------------------------------------ | 65 + | 1 | `water` | fill | water | Oceans + inland water | 66 + | 2 | `landcover` | fill | landcover | **Merged** grass, wood, wetland, sand, rock, ice — class-based color + opacity | 67 + | 3 | `park` | fill | park | National parks, nature reserves | 68 + | 4 | `waterway` | line | waterway | z6+, named rivers | 69 + | 5 | `boundary-state` | line | boundary | z3+, admin levels 3–6 | 70 + | 6 | `boundary-country` | line | boundary | Admin level 2 | 71 + | 7 | `place-continent` | symbol | place | z0–3, uppercase | 72 + | 8 | `place-country` | symbol | place | z0–7, Medium font for sovereign states | 73 + | 9 | `place-state` | symbol | place | z4–8, uppercase | 74 + | 10 | `place-settlement` | symbol | place | **Merged** city + town + village — class-based text-size | 75 75 76 76 ## Why some layers are NOT merged 77 77
+2 -4
www/utils/fs.ts
··· 1 1 import { PMTiles } from 'pmtiles' 2 2 import { IndexedDBSource } from 'pmtiles-offline' 3 3 4 - const DB_NAME = 'maps-data' 4 + const DB_NAME = 'bpev-maps-tiles' 5 5 const STORE_NAME = 'tiles' 6 6 7 7 let _db: IDBDatabase | null = null 8 8 9 9 async function getDb(): Promise<IDBDatabase> { 10 - if (!_db) { 11 - _db = await IndexedDBSource.openDb(DB_NAME, STORE_NAME) 12 - } 10 + if (!_db) _db = await IndexedDBSource.openDb(DB_NAME, STORE_NAME) 13 11 return _db 14 12 } 15 13
+21 -52
www/utils/layers.ts
··· 185 185 'paint': { 186 186 'fill-antialias': true, 187 187 'fill-color': 'rgba(222, 211, 190, 1)', 188 - 'fill-opacity': ELEVEN_SIXTEEN, 188 + 'fill-opacity': { 'base': 1, 'stops': [[11, 0], [13, 1]] }, 189 189 'fill-outline-color': { 190 190 'stops': [ 191 - [13, 'rgba(212, 177, 146, 0)'], 192 - [16, 'rgba(212, 177, 146, 0.5)'], 191 + [11, 'rgba(212, 177, 146, 0)'], 192 + [13, 'rgba(212, 177, 146, 0.5)'], 193 193 ], 194 194 }, 195 195 }, ··· 269 269 ALL, 270 270 LINE, 271 271 ['==', 'brunnel', 'tunnel'], 272 - ['in', ['get', 'class'], ['literal', MINOR_ROAD]], 272 + ['in', 'class', ...MINOR_ROAD], 273 273 ], 274 274 'layout': { 'line-cap': 'butt', 'line-join': 'miter' }, 275 275 'paint': { ··· 309 309 'source': sourceName, 310 310 'source-layer': 'aeroway', 311 311 'minzoom': 12, 312 - 'filter': [ 313 - ALL, 314 - ['in', 'class', 'taxiway'], 315 - LINE, 316 - ], 312 + 'filter': [ALL, ['in', 'class', 'taxiway'], LINE], 317 313 'layout': { 318 314 'line-cap': 'round', 319 315 'line-join': 'round', ··· 361 357 LINE, 362 358 [ 363 359 'in', 364 - ['get', 'class'], 365 - [ 366 - 'literal', 367 - [ 368 - 'motorway', 369 - 'trunk', 370 - 'primary', 371 - 'secondary', 372 - 'tertiary', 373 - 'minor', 374 - 'service', 375 - ], 376 - ], 360 + 'class', 361 + 'motorway', 362 + 'trunk', 363 + 'primary', 364 + 'secondary', 365 + 'tertiary', 366 + 'minor', 367 + 'service', 377 368 ], 378 369 ['!has', 'brunnel'], 379 370 ], ··· 416 407 1.5, 417 408 'tertiary', 418 409 1.5, 419 - 0.15, 410 + 0.5, 420 411 ], 421 412 13, 422 413 [ ··· 432 423 3, 433 424 'tertiary', 434 425 3, 435 - 1.5, 426 + 2.5, 436 427 ], 437 428 16, 438 429 [ ··· 481 472 'type': 'line', 482 473 'source': sourceName, 483 474 'source-layer': 'waterway', 484 - 'filter': [ 485 - ALL, 486 - LINE, 487 - ['==', 'brunnel', 'bridge'], 488 - ], 475 + 'filter': [ALL, LINE, ['==', 'brunnel', 'bridge']], 489 476 'layout': { 'line-cap': 'butt', 'line-join': 'miter' }, 490 477 'paint': { 491 478 'line-color': '#bbbbbb', ··· 498 485 'type': 'line', 499 486 'source': sourceName, 500 487 'source-layer': 'waterway', 501 - 'filter': [ 502 - ALL, 503 - LINE, 504 - ['==', 'brunnel', 'bridge'], 505 - ], 488 + 'filter': [ALL, LINE, ['==', 'brunnel', 'bridge']], 506 489 'layout': { 'line-cap': 'round', 'line-join': 'round' }, 507 490 'paint': { 508 491 'line-color': BLUE, ··· 518 501 ALL, 519 502 LINE, 520 503 ['==', 'brunnel', 'bridge'], 521 - ['in', ['get', 'class'], ['literal', MINOR_ROAD]], 504 + ['in', 'class', ...MINOR_ROAD], 522 505 ], 523 506 'layout': { 'line-cap': 'butt', 'line-join': 'miter' }, 524 507 'paint': { ··· 536 519 ALL, 537 520 LINE, 538 521 ['==', 'brunnel', 'bridge'], 539 - [ 540 - 'in', 541 - ['get', 'class'], 542 - [ 543 - 'literal', 544 - MINOR_ROAD, 545 - ], 546 - ], 522 + ['in', 'class', ...MINOR_ROAD], 547 523 ], 548 524 'layout': { 'line-cap': 'round', 'line-join': 'round' }, 549 525 'paint': { ··· 578 554 'source-layer': 'boundary', 579 555 'minzoom': 5, 580 556 'filter': [ALL, ['<=', 'admin_level', 2], LINE], 581 - 'layout': { 582 - 'line-cap': 'round', 583 - 'line-join': 'round', 584 - }, 557 + 'layout': { 'line-cap': 'round', 'line-join': 'round' }, 585 558 'paint': { 586 559 'line-color': 'hsl(0, 0%, 60%)', 587 560 'line-width': { 'base': 1.3, 'stops': [[3, 0.5], [22, 15]] }, ··· 667 640 'filter': [ 668 641 ALL, 669 642 ['==', '$type', 'Point'], 670 - [ 671 - 'in', 672 - ['get', 'class'], 673 - ['literal', ['city', 'town', 'suburb', 'neighbourhood', 'quarter']], 674 - ], 643 + ['in', 'class', 'city', 'town', 'suburb', 'neighbourhood', 'quarter'], 675 644 ], 676 645 'layout': { 677 646 'text-field': '{name:latin}',
-273
www/utils/world_layers.ts
··· 1 - /** 2 - * MapLibre layer definitions for the OSM-based world basemap tiles. 3 - * 4 - * Source-layers emitted by tilemaker + process.world.lua / config.world.json: 5 - * water — ocean polygons (from coastline shapefile) + inland water 6 - * landcover — wood, wetland, sand, farmland, ice, rock, grass 7 - * landuse — school, hospital, military, residential, commercial, etc. 8 - * park — national_park, nature_reserve 9 - * boundary — administrative boundaries (admin_level 2–6) 10 - * waterway — named rivers 11 - * place — continent, country, state, city, town, village labels 12 - * mountain_peak — peaks and volcanoes 13 - * 14 - * Transportation is intentionally omitted — roads are distracting at world 15 - * zoom and are available in regional tiles once downloaded. 16 - * 17 - * Colors are harmonised with layers.ts so the visual transition when a 18 - * regional tile loads is as seamless as possible. 19 - */ 20 - export default [ 21 - // ── Ocean / Water (fill) ────────────────────────────────────────────────── 22 - // fill-antialias matches regional water layer (no false here) 23 - { 24 - 'id': 'water', 25 - 'type': 'fill', 26 - 'source': 'world', 27 - 'source-layer': 'water', 28 - 'paint': { 29 - 'fill-color': 'hsl(205, 56%, 73%)', 30 - }, 31 - }, 32 - 33 - // ── Landcover — colours match layers.ts exactly ─────────────────────────── 34 - { 35 - 'id': 'landcover', 36 - 'type': 'fill', 37 - 'source': 'world', 38 - 'source-layer': 'landcover', 39 - 'filter': [ 40 - 'in', 41 - ['get', 'class'], 42 - ['literal', ['grass', 'wood', 'wetland', 'sand', 'rock', 'ice']], 43 - ], 44 - 'paint': { 45 - 'fill-color': [ 46 - 'match', 47 - ['get', 'class'], 48 - 'grass', 49 - 'hsl(82, 46%, 72%)', 50 - 'wood', 51 - 'hsl(82, 46%, 72%)', 52 - 'wetland', 53 - 'hsl(180, 25%, 78%)', 54 - 'sand', 55 - 'rgba(232, 214, 38, 1)', 56 - 'rock', 57 - 'hsl(30, 8%, 72%)', 58 - 'ice', 59 - 'hsl(47, 22%, 94%)', 60 - 'hsl(82, 46%, 72%)', 61 - ], 62 - 'fill-opacity': [ 63 - 'interpolate', 64 - ['linear'], 65 - ['zoom'], 66 - 0, 67 - [ 68 - 'match', 69 - ['get', 'class'], 70 - 'ice', 71 - 1, 72 - 'wood', 73 - 0.6, 74 - 'sand', 75 - 0.3, 76 - 'grass', 77 - 0.45, 78 - 0.5, 79 - ], 80 - 6, 81 - [ 82 - 'match', 83 - ['get', 'class'], 84 - 'ice', 85 - 0.75, 86 - 'wood', 87 - 0.6, 88 - 'sand', 89 - 0.3, 90 - 'grass', 91 - 0.45, 92 - 0.5, 93 - ], 94 - 9, 95 - [ 96 - 'match', 97 - ['get', 'class'], 98 - 'ice', 99 - 0.5, 100 - 'wood', 101 - 0.8, 102 - 'sand', 103 - 0.3, 104 - 'grass', 105 - 0.45, 106 - 0.5, 107 - ], 108 - ], 109 - }, 110 - }, 111 - 112 - // ── Parks / nature reserves ─────────────────────────────────────────────── 113 - { 114 - 'id': 'park', 115 - 'type': 'fill', 116 - 'source': 'world', 117 - 'source-layer': 'park', 118 - 'paint': { 119 - 'fill-color': '#E1EBB0', 120 - 'fill-opacity': { 'base': 1, 'stops': [[3, 0], [7, 0.75]] }, 121 - }, 122 - }, 123 - 124 - // ── Waterways ───────────────────────────────────────────────────────────── 125 - { 126 - 'id': 'waterway', 127 - 'type': 'line', 128 - 'source': 'world', 129 - 'source-layer': 'waterway', 130 - 'minzoom': 6, 131 - 'paint': { 132 - 'line-color': 'hsl(205, 56%, 73%)', 133 - 'line-opacity': 1, 134 - 'line-width': { 'base': 1.4, 'stops': [[6, 0.5], [9, 3]] }, 135 - }, 136 - }, 137 - 138 - // ── Boundaries ──────────────────────────────────────────────────────────── 139 - { 140 - 'id': 'boundary-state', 141 - 'type': 'line', 142 - 'source': 'world', 143 - 'source-layer': 'boundary', 144 - 'filter': ['all', ['>=', 'admin_level', 3], ['<=', 'admin_level', 6]], 145 - 'minzoom': 3, 146 - 'paint': { 147 - 'line-color': 'hsla(0, 0%, 60%, 0.5)', 148 - 'line-width': 0.5, 149 - 'line-dasharray': [2, 1], 150 - }, 151 - }, 152 - { 153 - 'id': 'boundary-country', 154 - 'type': 'line', 155 - 'source': 'world', 156 - 'source-layer': 'boundary', 157 - 'filter': ['==', 'admin_level', 2], 158 - 'paint': { 159 - 'line-color': 'hsl(0, 0%, 60%)', 160 - 'line-width': { 'base': 1.3, 'stops': [[0, 0.5], [4, 1], [7, 1.5]] }, 161 - }, 162 - }, 163 - 164 - // ── Place labels ────────────────────────────────────────────────────────── 165 - { 166 - 'id': 'place-continent', 167 - 'type': 'symbol', 168 - 'source': 'world', 169 - 'source-layer': 'place', 170 - 'filter': ['==', 'class', 'continent'], 171 - 'maxzoom': 3, 172 - 'layout': { 173 - 'text-field': ['coalesce', ['get', 'name:latin'], ['get', 'name']], 174 - 'text-font': ['Noto Sans Medium'], 175 - 'text-size': 13, 176 - 'text-transform': 'uppercase', 177 - 'text-letter-spacing': 0.1, 178 - }, 179 - 'paint': { 180 - 'text-color': 'hsl(0, 0%, 30%)', 181 - 'text-halo-color': 'rgba(255, 255, 255, 0.7)', 182 - 'text-halo-width': 1, 183 - }, 184 - }, 185 - { 186 - 'id': 'place-country', 187 - 'type': 'symbol', 188 - 'source': 'world', 189 - 'source-layer': 'place', 190 - 'filter': ['==', 'class', 'country'], 191 - 'maxzoom': 7, 192 - 'layout': { 193 - 'text-field': ['coalesce', ['get', 'name:latin'], ['get', 'name']], 194 - 'text-font': [ 195 - 'case', 196 - ['has', 'iso_a2'], 197 - ['literal', ['Noto Sans Medium']], 198 - ['literal', ['Noto Sans Regular']], 199 - ], 200 - 'text-max-width': 10, 201 - 'text-size': { 'stops': [[3, 12], [8, 22]] }, 202 - }, 203 - 'paint': { 204 - 'text-color': 'hsl(0, 0%, 13%)', 205 - 'text-halo-blur': 0, 206 - 'text-halo-color': 'rgba(255, 255, 255, 0.75)', 207 - 'text-halo-width': 2, 208 - }, 209 - }, 210 - { 211 - 'id': 'place-state', 212 - 'type': 'symbol', 213 - 'source': 'world', 214 - 'source-layer': 'place', 215 - 'filter': ['in', 'class', 'state', 'province'], 216 - 'minzoom': 4, 217 - 'maxzoom': 8, 218 - 'layout': { 219 - 'text-field': ['coalesce', ['get', 'name:latin'], ['get', 'name']], 220 - 'text-font': ['Noto Sans Regular'], 221 - 'text-size': 10, 222 - 'text-transform': 'uppercase', 223 - 'text-letter-spacing': 0.05, 224 - 'text-max-width': 6, 225 - }, 226 - 'paint': { 227 - 'text-color': 'hsl(0, 0%, 35%)', 228 - 'text-halo-color': 'rgba(255, 255, 255, 0.6)', 229 - 'text-halo-width': 1, 230 - 'text-opacity': 0.8, 231 - }, 232 - }, 233 - { 234 - 'id': 'place-settlement', 235 - 'type': 'symbol', 236 - 'source': 'world', 237 - 'source-layer': 'place', 238 - 'filter': [ 239 - 'in', 240 - ['get', 'class'], 241 - ['literal', ['city', 'town', 'village']], 242 - ], 243 - 'minzoom': 6, 244 - 'layout': { 245 - 'text-field': ['coalesce', ['get', 'name:latin'], ['get', 'name']], 246 - 'text-font': ['Noto Sans Regular'], 247 - 'text-max-width': ['match', ['get', 'class'], 'city', 10, 6], 248 - 'text-size': [ 249 - 'interpolate', 250 - ['linear'], 251 - ['zoom'], 252 - 6, 253 - ['match', ['get', 'class'], 'city', 11, 'town', 10, 0], 254 - 8, 255 - ['match', ['get', 'class'], 'city', 12, 'town', 11, 10], 256 - 9, 257 - ['match', ['get', 'class'], 'city', 15, 'town', 14, 14], 258 - ], 259 - }, 260 - 'paint': { 261 - 'text-color': [ 262 - 'match', 263 - ['get', 'class'], 264 - 'city', 265 - 'hsl(0, 0%, 0%)', 266 - 'hsl(0, 0%, 25%)', 267 - ], 268 - 'text-halo-blur': 0, 269 - 'text-halo-color': 'rgba(255, 255, 255, 0.75)', 270 - 'text-halo-width': 2, 271 - }, 272 - }, 273 - ]