aviation-chart 2.0.29 → 2.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1332,15 +1332,15 @@ const AMM_COLOR_LIGHT = {
1332
1332
  /** 机场边界(淡暖灰垫底,在纯白底上显现轮廓) */
1333
1333
  airport: '#e2e8f0',
1334
1334
  /** 跑道面(中深灰,作为白底上的绝对重心) */
1335
- runway: '#94a3b8',
1335
+ runway: 'hsl(0, 0%, 33%)',
1336
1336
  /** 机坪面(中浅灰,与白底拉开清晰明度差) */
1337
- apron: '#cbd5e1',
1337
+ apron: 'hsl(0, 0%, 60%)',
1338
1338
  /** 滑行道面(带微弱色调差的浅灰,与机坪剥离) */
1339
- taxiway: '#e2e8f0',
1339
+ taxiway: 'hsl(240, 5%, 60%)',
1340
1340
  /** 滑行道中心线(深琥珀金,白底上极清晰) */
1341
- taxiwayLine: '#f59e0b',
1341
+ taxiwayLine: '#ffff00',
1342
1342
  /** 等待位(深砖红/铁锈红,高辨识度) */
1343
- holding: '#b91c1c',
1343
+ holding: 'hsl(0, 100%, 50%)',
1344
1344
  /** 机位点(深翡翠绿) */
1345
1345
  stand: '#1e293b',
1346
1346
  /** 跑道标记(涂装面) */
@@ -1348,7 +1348,7 @@ const AMM_COLOR_LIGHT = {
1348
1348
  /** 跑道中心线 */
1349
1349
  runwayCenterline: '#ffffff',
1350
1350
  /** 停机位引导线(深绿色) */
1351
- standLine: '#64748b',
1351
+ standLine: '#010101',
1352
1352
  /** 跑道入口点(深琥珀色) */
1353
1353
  threshold: '#c2410c',
1354
1354
  /** 限制区域(深红) */
@@ -1357,9 +1357,9 @@ const AMM_COLOR_LIGHT = {
1357
1357
  hotspot: '#ea580c',
1358
1358
  };
1359
1359
 
1360
- function buildAMMLayersLight(sourceId = 'amm') {
1361
- const C = AMM_COLOR_LIGHT;
1362
- return [
1360
+ function buildAMMLayersLight(sourceId = 'amm', colors = AMM_COLOR_LIGHT) {
1361
+ const C = colors;
1362
+ const layers = [
1363
1363
  // ── 机场边界轮廓(z11+)
1364
1364
  {
1365
1365
  id: 'amm-airport-fill',
@@ -1392,8 +1392,9 @@ function buildAMMLayersLight(sourceId = 'amm') {
1392
1392
  'source-layer': 'amm-runway',
1393
1393
  minzoom: 11,
1394
1394
  paint: {
1395
+ "fill-antialias": true,
1395
1396
  'fill-color': C.runway,
1396
- 'fill-opacity': 0.9,
1397
+ 'fill-opacity': 1,
1397
1398
  },
1398
1399
  },
1399
1400
  {
@@ -1417,20 +1418,39 @@ function buildAMMLayersLight(sourceId = 'amm') {
1417
1418
  'source-layer': 'amm-apron',
1418
1419
  minzoom: 11,
1419
1420
  paint: {
1421
+ "fill-antialias": true,
1420
1422
  'fill-color': C.apron,
1421
- 'fill-opacity': 0.6, // 提高透明度浓度
1423
+ 'fill-opacity': 1, // 提高透明度浓度
1422
1424
  },
1423
1425
  },
1424
1426
  {
1425
- id: 'amm-apron-stroke',
1426
- type: 'line',
1427
+ id: 'amm-apron-label',
1428
+ type: 'symbol',
1427
1429
  source: sourceId,
1428
1430
  'source-layer': 'amm-apron',
1429
- minzoom: 11,
1430
- paint: {
1431
- 'line-color': '#94a3b8', // 勾边加深,确保纯白背景下清晰可见
1432
- 'line-width': 0.5,
1431
+ minzoom: 13,
1432
+ "layout": {
1433
+ "text-ignore-placement": false,
1434
+ "text-allow-overlap": false,
1435
+ "text-size": 10,
1436
+ "text-font": ["Fira Code SemiBold"],
1437
+ "text-field": [
1438
+ "case",
1439
+ [
1440
+ "any",
1441
+ ["!", ["has", "idapron"]],
1442
+ ["==", ["get", "idapron"], null],
1443
+ ["==", ["get", "idapron"], "null"]
1444
+ ],
1445
+ "",
1446
+ ["to-string", ["get", "idapron"]]
1447
+ ]
1433
1448
  },
1449
+ "paint": {
1450
+ "text-color": "#fefefe",
1451
+ "text-halo-color": "#010101",
1452
+ "text-halo-width": 0.5
1453
+ }
1434
1454
  },
1435
1455
 
1436
1456
  // ── 滑行道面(z11+)───
@@ -1441,8 +1461,21 @@ function buildAMMLayersLight(sourceId = 'amm') {
1441
1461
  'source-layer': 'amm-taxiway',
1442
1462
  minzoom: 11,
1443
1463
  paint: {
1464
+ "fill-antialias": true,
1444
1465
  'fill-color': C.taxiway,
1445
- 'fill-opacity': 0.7,
1466
+ "fill-opacity": {
1467
+ "base": 1,
1468
+ "stops": [
1469
+ [
1470
+ 11,
1471
+ 0
1472
+ ],
1473
+ [
1474
+ 12,
1475
+ 1
1476
+ ]
1477
+ ]
1478
+ }
1446
1479
  },
1447
1480
  },
1448
1481
 
@@ -1452,12 +1485,40 @@ function buildAMMLayersLight(sourceId = 'amm') {
1452
1485
  type: 'line',
1453
1486
  source: sourceId,
1454
1487
  'source-layer': 'amm-taxiway-line',
1455
- minzoom: 11,
1488
+ minzoom: 13.5,
1489
+ paint: {
1490
+ 'line-color': C.taxiwayLine,
1491
+ 'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2]
1492
+ },
1493
+ },
1494
+ // 滑行道引导线
1495
+ {
1496
+ id: 'amm-taxiway-guidanceline',
1497
+ type: 'line',
1498
+ source: sourceId,
1499
+ 'source-layer': 'amm-taxiway-guidance-line',
1500
+ minzoom: 13.5,
1456
1501
  paint: {
1457
1502
  'line-color': C.taxiwayLine,
1458
1503
  'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2]
1459
1504
  },
1460
1505
  },
1506
+ // 滑行道交叉线
1507
+ {
1508
+ id: 'amm-taxiway-intersectionline',
1509
+ type: 'line',
1510
+ source: sourceId,
1511
+ 'source-layer': 'amm-taxiway-intersection-marking',
1512
+ minzoom: 13.5,
1513
+ paint: {
1514
+ 'line-color': "#fff",
1515
+ 'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2],
1516
+ "line-dasharray": [
1517
+ 3,
1518
+ 3
1519
+ ]
1520
+ },
1521
+ },
1461
1522
 
1462
1523
 
1463
1524
  // ── 等待位(z11+)─────
@@ -1466,12 +1527,58 @@ function buildAMMLayersLight(sourceId = 'amm') {
1466
1527
  type: 'line',
1467
1528
  source: sourceId,
1468
1529
  'source-layer': 'amm-holding',
1469
- minzoom: 11,
1530
+ minzoom: 13,
1470
1531
  paint: {
1471
1532
  'line-color': C.holding,
1472
1533
  'line-width': 1.5,
1473
1534
  },
1474
1535
  },
1536
+ {
1537
+ id: 'amm-holding-label',
1538
+ type: 'symbol',
1539
+ source: sourceId,
1540
+ 'source-layer': 'amm-holding',
1541
+ minzoom: 15,
1542
+ "layout": {
1543
+ "text-offset": [
1544
+ 0,
1545
+ 0
1546
+ ],
1547
+ "symbol-placement": "point",
1548
+ "text-ignore-placement": true,
1549
+ "text-allow-overlap": true,
1550
+ "text-size": 13,
1551
+ "text-font": [
1552
+ "Font17"
1553
+ ],
1554
+ "text-field": [
1555
+ "case",
1556
+ [
1557
+ "!=",
1558
+ [
1559
+ "get",
1560
+ "idlin"
1561
+ ],
1562
+ ""
1563
+ ],
1564
+ [
1565
+ "concat",
1566
+ ".",
1567
+ [
1568
+ "get",
1569
+ "idlin"
1570
+ ],
1571
+ "."
1572
+ ],
1573
+ ""
1574
+ ]
1575
+ },
1576
+ "paint": {
1577
+ "text-halo-color": C.holding,
1578
+ "text-color": "#010101",
1579
+ "text-halo-width": 2
1580
+ }
1581
+ },
1475
1582
 
1476
1583
  // ── 跑道标记(斑马线、编号等涂装面,z13+)─────────────────────────
1477
1584
  {
@@ -1481,6 +1588,7 @@ function buildAMMLayersLight(sourceId = 'amm') {
1481
1588
  'source-layer': 'amm-runway-marking',
1482
1589
  minzoom: 13,
1483
1590
  paint: {
1591
+ "fill-antialias": true,
1484
1592
  'fill-color': C.runwayMarking,
1485
1593
  'fill-opacity': 0.9,
1486
1594
  },
@@ -1494,20 +1602,9 @@ function buildAMMLayersLight(sourceId = 'amm') {
1494
1602
  'source-layer': 'amm-restricted',
1495
1603
  minzoom: 11,
1496
1604
  paint: {
1605
+ "fill-antialias": true,
1497
1606
  'fill-color': C.restricted,
1498
- 'fill-opacity': 0.08, // 针对白底降低面纯度
1499
- },
1500
- },
1501
- {
1502
- id: 'amm-restricted-stroke',
1503
- type: 'line',
1504
- source: sourceId,
1505
- 'source-layer': 'amm-restricted',
1506
- minzoom: 11,
1507
- paint: {
1508
- 'line-color': C.restricted,
1509
- 'line-width': 1.5,
1510
- 'line-dasharray': [4, 2],
1607
+ 'fill-opacity': 0.3, // 针对白底降低面纯度
1511
1608
  },
1512
1609
  },
1513
1610
 
@@ -1517,22 +1614,55 @@ function buildAMMLayersLight(sourceId = 'amm') {
1517
1614
  type: 'fill',
1518
1615
  source: sourceId,
1519
1616
  'source-layer': 'amm-hotspot',
1520
- minzoom: 11,
1521
- paint: {
1522
- 'fill-color': C.hotspot,
1523
- 'fill-opacity': 0.1, // 针对白底轻微淡化面
1524
- },
1617
+ minzoom: 12,
1618
+ "paint": {
1619
+ "fill-antialias": true,
1620
+ "fill-outline-color": "#ff00ff",
1621
+ "fill-color": "#89259D",
1622
+ "fill-opacity": 0.3
1623
+ }
1525
1624
  },
1526
1625
  {
1527
- id: 'amm-hotspot-stroke',
1528
- type: 'line',
1529
- source: sourceId,
1530
- 'source-layer': 'amm-hotspot',
1531
- minzoom: 11,
1532
- paint: {
1533
- 'line-color': C.hotspot,
1534
- 'line-width': 1.5,
1626
+ id: "amm-hotpost-label",
1627
+ "type": "symbol",
1628
+ "source": sourceId,
1629
+ "source-layer": "amm-hotspot",
1630
+ "minzoom": 12,
1631
+ "layout": {
1632
+ "symbol-placement": "point",
1633
+ "text-ignore-placement": false,
1634
+ "text-allow-overlap": false,
1635
+ "text-size": 14,
1636
+ "text-font": [
1637
+ "Font17"
1638
+ ],
1639
+ "text-field": [
1640
+ "case",
1641
+ [
1642
+ "!=",
1643
+ [
1644
+ "get",
1645
+ "idhot"
1646
+ ],
1647
+ ""
1648
+ ],
1649
+ [
1650
+ "concat",
1651
+ ".",
1652
+ [
1653
+ "get",
1654
+ "idhot"
1655
+ ],
1656
+ "."
1657
+ ],
1658
+ ""
1659
+ ]
1535
1660
  },
1661
+ "paint": {
1662
+ "text-color": "#444",
1663
+ "text-halo-color": "#ff00ff",
1664
+ "text-halo-width": 2
1665
+ }
1536
1666
  },
1537
1667
 
1538
1668
  // ── 跑道中心线(z11+)─────────────────────────────────────────────
@@ -1592,8 +1722,14 @@ function buildAMMLayersLight(sourceId = 'amm') {
1592
1722
  'source-layer': 'amm-stand-line',
1593
1723
  minzoom: 13,
1594
1724
  paint: {
1595
- 'line-color': C.standLine,
1596
- 'line-width': 1,
1725
+ 'line-color': '#ffff00',
1726
+ "line-width": [
1727
+ "interpolate",
1728
+ ["exponential", 1.8],
1729
+ ["zoom"],
1730
+ 13, 0.2,
1731
+ 15, 0.4
1732
+ ]
1597
1733
  },
1598
1734
  },
1599
1735
  // 滑行道名称(中心线 symbol)
@@ -1602,25 +1738,43 @@ function buildAMMLayersLight(sourceId = 'amm') {
1602
1738
  type: 'symbol',
1603
1739
  source: sourceId,
1604
1740
  'source-layer': 'amm-taxiway-line',
1605
- minzoom: 14,
1741
+ minzoom: 12,
1606
1742
  layout: {
1607
- 'text-field': ['get', 'idlin'],
1608
- 'text-size': 10,
1609
- "icon-image": "stretch:text_bg",
1610
- "icon-text-fit": "both",
1611
- "icon-text-fit-padding": [
1612
- 1,
1613
- 2,
1614
- 1,
1615
- 2
1743
+ "symbol-placement": "line",
1744
+ "text-ignore-placement": false,
1745
+ "text-allow-overlap": false,
1746
+ "text-size": 15,
1747
+ "text-max-angle": 10,
1748
+ "text-font": [
1749
+ "Font17"
1616
1750
  ],
1617
- 'symbol-placement': 'line',
1618
- 'text-keep-upright': true,
1619
- 'text-allow-overlap': false,
1751
+ "text-field": [
1752
+ "case",
1753
+ [
1754
+ "!=",
1755
+ [
1756
+ "get",
1757
+ "idlin"
1758
+ ],
1759
+ ""
1760
+ ],
1761
+ [
1762
+ "concat",
1763
+ ".",
1764
+ [
1765
+ "get",
1766
+ "idlin"
1767
+ ],
1768
+ "."
1769
+ ],
1770
+ ""
1771
+ ],
1772
+ "text-rotation-alignment": "viewport"
1620
1773
  },
1621
1774
  paint: {
1622
- 'text-color': "#FFF",
1623
- "icon-color": C.taxiwayLine
1775
+ "text-halo-color": "yellow",
1776
+ "text-color": "#010101",
1777
+ "text-halo-width": 2
1624
1778
  },
1625
1779
  },
1626
1780
 
@@ -1631,98 +1785,96 @@ function buildAMMLayersLight(sourceId = 'amm') {
1631
1785
  source: sourceId,
1632
1786
  'source-layer': 'amm-runway-threshold',
1633
1787
  minzoom: 12,
1634
- layout: {
1635
- "icon-image": "stretch:text_bg",
1636
- "icon-text-fit": "both",
1637
- "icon-text-fit-padding": [
1638
- 1,
1639
- 2,
1640
- 1,
1641
- 2
1788
+ "layout": {
1789
+ "symbol-placement": "point",
1790
+ "text-ignore-placement": false,
1791
+ "text-allow-overlap": false,
1792
+ "text-size": 14,
1793
+ "text-font": [
1794
+ "Font17"
1642
1795
  ],
1643
- 'text-field': ['get', 'idthr'],
1644
- 'text-size': 14,
1645
- 'text-allow-overlap': true,
1796
+ "text-field": "{idthr}",
1646
1797
  'text-rotation-alignment': 'map',
1647
- 'icon-rotation-alignment': 'map',
1648
- },
1649
- paint: {
1650
- 'text-color': '#fff',
1651
- "icon-color": "#b91c1c"
1652
1798
  },
1799
+ "paint": {
1800
+ "text-halo-color": "white",
1801
+ "text-color": "red",
1802
+ "text-halo-width": 2
1803
+ }
1653
1804
  },
1654
1805
 
1655
- // ── 机位点(z11+)─────
1656
- {
1657
- id: 'amm-stand',
1658
- type: 'circle',
1659
- source: sourceId,
1660
- 'source-layer': 'amm-stand',
1661
- minzoom: 12,
1662
- paint: {
1663
- 'circle-color': C.stand,
1664
- 'circle-radius': 1.5,
1665
- },
1666
- },
1667
1806
  // 机位编号标签
1668
1807
  {
1669
1808
  id: 'amm-stand-label',
1670
1809
  type: 'symbol',
1671
1810
  source: sourceId,
1672
1811
  'source-layer': 'amm-stand',
1673
- minzoom: 14,
1674
- layout: {
1675
- 'text-field': ['get', 'idstd'],
1676
- 'text-size': 9,
1677
- 'text-anchor': 'bottom',
1678
- 'text-offset': [0, -0.5],
1679
- 'text-allow-overlap': false,
1680
- },
1681
- paint: {
1682
- 'text-color': C.standLine, // 改为深墨绿字,白底/浅灰底上高可读
1812
+ minzoom: 13.5,
1813
+ "layout": {
1814
+ "symbol-placement": "point",
1815
+ "text-ignore-placement": false,
1816
+ "text-allow-overlap": false,
1817
+ "text-size": 14,
1818
+ "text-font": [
1819
+ "Font17"
1820
+ ],
1821
+ "text-field": [
1822
+ "case",
1823
+ [
1824
+ "!=",
1825
+ [
1826
+ "get",
1827
+ "idstd"
1828
+ ],
1829
+ ""
1830
+ ],
1831
+ [
1832
+ "concat",
1833
+ ".",
1834
+ [
1835
+ "get",
1836
+ "idstd"
1837
+ ],
1838
+ "."
1839
+ ],
1840
+ ""
1841
+ ],
1683
1842
  },
1843
+ "paint": {
1844
+ "text-halo-color": "#fefefe",
1845
+ "text-color": C.standLine,
1846
+ "text-halo-width": 2
1847
+ }
1684
1848
  },
1685
1849
 
1686
1850
 
1687
1851
  // ── 垂直面状障碍物(z11+)──────────────────────────────────────
1688
1852
  {
1689
1853
  id: 'amm-obstacle-region-fill',
1690
- type: 'fill',
1691
- source: sourceId,
1692
- 'source-layer': 'amm-obstacle-region',
1693
- minzoom: 11,
1694
- paint: {
1695
- 'fill-color': '#fef08a',
1696
- 'fill-opacity': 0.35,
1697
- },
1698
- },
1699
- {
1700
- id: 'amm-obstacle-region-stroke',
1701
- type: 'line',
1854
+ type: 'fill-extrusion',
1702
1855
  source: sourceId,
1703
1856
  'source-layer': 'amm-obstacle-region',
1704
1857
  minzoom: 11,
1705
1858
  paint: {
1706
- 'line-color': '#ca8a04',
1707
- 'line-width': 1.5,
1708
- 'line-dasharray': [1.5, 1]
1709
- },
1859
+ "fill-extrusion-height": 10,
1860
+ "fill-extrusion-color": 'hsl(240, 25%, 30%)',
1861
+ "fill-extrusion-opacity": {
1862
+ "base": 1,
1863
+ "stops": [
1864
+ [
1865
+ 11,
1866
+ 0
1867
+ ],
1868
+ [
1869
+ 12,
1870
+ 1
1871
+ ]
1872
+ ]
1873
+ }
1874
+ }
1710
1875
  },
1711
1876
 
1712
- // ── 垂直点状障碍物(z11+)──────────────────────────────────────
1713
- {
1714
- id: 'amm-obstacle-point',
1715
- type: 'circle',
1716
- source: sourceId,
1717
- 'source-layer': 'amm-obstacle-point',
1718
- minzoom: 11,
1719
- paint: {
1720
- 'circle-color': '#b45309',
1721
- 'circle-radius': 4,
1722
- 'circle-stroke-color': '#ffffff',
1723
- 'circle-stroke-width': 1,
1724
- },
1725
- },
1877
+
1726
1878
  // 点状障碍物名称标签
1727
1879
  {
1728
1880
  id: 'amm-obstacle-point-label',
@@ -1734,13 +1886,31 @@ function buildAMMLayersLight(sourceId = 'amm') {
1734
1886
  'text-field': ['coalesce', ['get', 'ident'], ['get', 'LABEL']],
1735
1887
  'text-size': 9,
1736
1888
  'text-anchor': 'bottom',
1737
- 'text-offset': [0, -0.5],
1738
- 'text-allow-overlap': false,
1889
+ 'text-offset': [0, -1],
1890
+ "icon-allow-overlap": true,
1891
+ "icon-image": 'navig:radio_tower',
1892
+ "icon-size": {
1893
+ "base": 2,
1894
+ "stops": [
1895
+ [
1896
+ 13,
1897
+ 0.5
1898
+ ],
1899
+ [
1900
+ 16,
1901
+ 1
1902
+ ]
1903
+ ]
1904
+ }
1739
1905
  },
1740
1906
  paint: {
1741
1907
  'text-color': '#92400e',
1742
1908
  'text-halo-color': '#ffffff',
1743
1909
  'text-halo-width': 1,
1910
+ "icon-color": "#010101",
1911
+ "icon-halo-color": "#fefefe",
1912
+ "icon-halo-width": 0.5,
1913
+ "icon-halo-blur": 0.5
1744
1914
  },
1745
1915
  },
1746
1916
 
@@ -1787,6 +1957,15 @@ function buildAMMLayersLight(sourceId = 'amm') {
1787
1957
  'text-halo-width': 1,
1788
1958
  },
1789
1959
  },
1960
+ ];
1961
+
1962
+ // 文字标注置于所有面、线和图标之后,避免被后续图层遮挡。
1963
+ const textLayers = layers.filter((layer) =>
1964
+ layer.type === 'symbol' && layer.layout?.['text-field'] !== undefined
1965
+ );
1966
+ return [
1967
+ ...layers.filter((layer) => !textLayers.includes(layer)),
1968
+ ...textLayers,
1790
1969
  ]
1791
1970
  }
1792
1971
 
@@ -1808,62 +1987,7 @@ const AMM_COLOR_DARK = {
1808
1987
  };
1809
1988
 
1810
1989
  function buildAMMLayersDark(sourceId = 'amm') {
1811
- const C = AMM_COLOR_DARK;
1812
- return [
1813
- { id: 'amm-airport-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-airport', minzoom: 11, paint: { 'fill-color': C.airport, 'fill-opacity': 0.3 } },
1814
- { id: 'amm-airport-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-airport', minzoom: 11, paint: { 'line-color': '#475569', 'line-width': 1 } },
1815
- { id: 'amm-runway-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-runway', minzoom: 11, paint: { 'fill-color': C.runway, 'fill-opacity': 1 } },
1816
- { id: 'amm-runway-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-runway', minzoom: 11, paint: { 'line-color': '#64748b', 'line-width': 0.5 } },
1817
- { id: 'amm-apron-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-apron', minzoom: 11, paint: { 'fill-color': C.apron, 'fill-opacity': 1 } },
1818
- { id: 'amm-apron-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-apron', minzoom: 11, paint: { 'line-color': '#334155', 'line-width': 0.5 } },
1819
- { id: 'amm-taxiway-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-taxiway', minzoom: 11, paint: { 'fill-color': C.taxiway, 'fill-opacity': 0.8 } },
1820
- { id: 'amm-taxiway-line', type: 'line', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 11, paint: { 'line-color': C.taxiwayLine, 'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2] } },
1821
-
1822
- { id: 'amm-holding', type: 'line', source: sourceId, 'source-layer': 'amm-holding', minzoom: 11, paint: { 'line-color': C.holding, 'line-width': 1.5 } },
1823
- { id: 'amm-runway-marking', type: 'fill', source: sourceId, 'source-layer': 'amm-runway-marking', minzoom: 13, paint: { 'fill-color': C.runwayMarking, 'fill-opacity': 0.8 } },
1824
- { id: 'amm-restricted-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-restricted', minzoom: 11, paint: { 'fill-color': C.restricted, 'fill-opacity': 0.12 } },
1825
- { id: 'amm-restricted-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-restricted', minzoom: 11, paint: { 'line-color': C.restricted, 'line-width': 1.2, 'line-dasharray': [4, 2] } },
1826
- { id: 'amm-hotspot-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-hotspot', minzoom: 11, paint: { 'fill-color': C.hotspot, 'fill-opacity': 0.15 } },
1827
- { id: 'amm-hotspot-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-hotspot', minzoom: 11, paint: { 'line-color': C.hotspot, 'line-width': 1.2 } },
1828
- { id: 'amm-runway-centerline', type: 'line', source: sourceId, 'source-layer': 'amm-runway-centerline', minzoom: 11, paint: { 'line-color': C.runwayCenterline, 'line-width': 1, 'line-dasharray': [6, 3] } },
1829
- {
1830
- id: 'amm-runway-info', type: 'symbol', source: sourceId, 'source-layer': 'amm-runway-label', minzoom: 13,
1831
- layout: { 'text-field': ['concat', ['coalesce', ['get', 'length'], ''], '×', ['coalesce', ['get', 'width'], ''], 'm'], 'text-size': ['interpolate', ['exponential', 1.5], ['zoom'], 13, 10, 16, 13], 'symbol-placement': 'point', 'text-rotate': ['coalesce', ['get', 'bearing'], 0], 'text-rotation-alignment': 'map', 'text-allow-overlap': true, 'text-ignore-placement': true },
1832
- paint: { 'text-color': '#e2e8f0', 'text-halo-color': '#0f172a', 'text-halo-width': 2 },
1833
- },
1834
- { id: 'amm-stand-line', type: 'line', source: sourceId, 'source-layer': 'amm-stand-line', minzoom: 13, paint: { 'line-color': C.standLine, 'line-width': 1 } },
1835
- {
1836
- id: 'amm-taxiway-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 14,
1837
- layout: { 'text-field': ['get', 'idlin'], 'text-size': 10, "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'symbol-placement': 'line', 'text-keep-upright': true, 'text-allow-overlap': false },
1838
- paint: { 'text-color': "#0f172a", "icon-color": C.taxiwayLine },
1839
- },
1840
- {
1841
- id: 'amm-runway-threshold-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-runway-threshold', minzoom: 12,
1842
- layout: { "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'text-field': ['get', 'idthr'], 'text-size': 14, 'text-allow-overlap': true, 'text-rotation-alignment': 'map', 'icon-rotation-alignment': 'map' },
1843
- paint: { 'text-color': '#ffffff', "icon-color": "#ef4444" },
1844
- },
1845
- { id: 'amm-stand', type: 'circle', source: sourceId, 'source-layer': 'amm-stand', minzoom: 12, paint: { 'circle-color': C.stand, 'circle-radius': 1.5 } },
1846
- {
1847
- id: 'amm-stand-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-stand', minzoom: 14,
1848
- layout: { 'text-field': ['get', 'idstd'], 'text-size': 9, 'text-anchor': 'bottom', 'text-offset': [0, -0.5], 'text-allow-overlap': false },
1849
- paint: { 'text-color': C.stand, 'text-halo-color': '#0f172a', 'text-halo-width': 1 },
1850
- },
1851
- { id: 'amm-obstacle-region-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-obstacle-region', minzoom: 11, paint: { 'fill-color': '#fef08a', 'fill-opacity': 0.15 } },
1852
- { id: 'amm-obstacle-region-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-obstacle-region', minzoom: 11, paint: { 'line-color': '#eab308', 'line-width': 1.2, 'line-dasharray': [1.5, 1] } },
1853
- { id: 'amm-obstacle-point', type: 'circle', source: sourceId, 'source-layer': 'amm-obstacle-point', minzoom: 11, paint: { 'circle-color': '#f97316', 'circle-radius': 4, 'circle-stroke-color': '#0f172a', 'circle-stroke-width': 1 } },
1854
- {
1855
- id: 'amm-obstacle-point-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-obstacle-point', minzoom: 14,
1856
- layout: { 'text-field': ['coalesce', ['get', 'ident'], ['get', 'LABEL']], 'text-size': 9, 'text-anchor': 'bottom', 'text-offset': [0, -0.5], 'text-allow-overlap': false },
1857
- paint: { 'text-color': '#fdba74', 'text-halo-color': '#0f172a', 'text-halo-width': 1.2 },
1858
- },
1859
- { id: 'amm-construction-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-construction', minzoom: 11, paint: { 'fill-pattern': 'normal:passline', 'fill-opacity': 0.6 } },
1860
- { id: 'amm-construction-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-construction', minzoom: 11, paint: { 'line-color': '#ea580c', 'line-width': 1.2, 'line-dasharray': [4, 2] } },
1861
- {
1862
- id: 'amm-construction-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-construction', minzoom: 13,
1863
- layout: { 'text-field': ['get', 'text'], 'text-size': 9, 'text-anchor': 'center', 'symbol-placement': 'point', 'text-allow-overlap': false },
1864
- paint: { 'text-color': '#f97316', 'text-halo-color': '#0f172a', 'text-halo-width': 1 },
1865
- },
1866
- ]
1990
+ return buildAMMLayersLight(sourceId, AMM_COLOR_DARK)
1867
1991
  }
1868
1992
 
1869
1993
  // ── Neutral (Charcoal) theme ──────────────────────────────────────────────────
@@ -1884,62 +2008,7 @@ const AMM_COLOR_NEUTRAL = {
1884
2008
  };
1885
2009
 
1886
2010
  function buildAMMLayersNeutral(sourceId = 'amm') {
1887
- const C = AMM_COLOR_NEUTRAL;
1888
- const H = '#1f1f23';
1889
- return [
1890
- { id: 'amm-airport-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-airport', minzoom: 11, paint: { 'fill-color': C.airport, 'fill-opacity': 0.3 } },
1891
- { id: 'amm-airport-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-airport', minzoom: 11, paint: { 'line-color': '#52525b', 'line-width': 1 } },
1892
- { id: 'amm-runway-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-runway', minzoom: 11, paint: { 'fill-color': C.runway, 'fill-opacity': 1 } },
1893
- { id: 'amm-runway-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-runway', minzoom: 11, paint: { 'line-color': '#52525b', 'line-width': 0.5 } },
1894
- { id: 'amm-apron-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-apron', minzoom: 11, paint: { 'fill-color': C.apron, 'fill-opacity': 1 } },
1895
- { id: 'amm-apron-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-apron', minzoom: 11, paint: { 'line-color': '#3f3f46', 'line-width': 0.5 } },
1896
- { id: 'amm-taxiway-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-taxiway', minzoom: 11, paint: { 'fill-color': C.taxiway, 'fill-opacity': 0.9 } },
1897
- { id: 'amm-taxiway-line', type: 'line', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 11, paint: { 'line-color': C.taxiwayLine, 'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2] } },
1898
- {
1899
- id: 'amm-taxiway-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 14,
1900
- layout: { 'text-field': ['get', 'idlin'], 'text-size': 10, "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'symbol-placement': 'line', 'text-keep-upright': true, 'text-allow-overlap': false },
1901
- paint: { 'text-color': H, "icon-color": C.taxiwayLine },
1902
- },
1903
- { id: 'amm-holding', type: 'line', source: sourceId, 'source-layer': 'amm-holding', minzoom: 11, paint: { 'line-color': C.holding, 'line-width': 1.5 } },
1904
- { id: 'amm-runway-marking', type: 'fill', source: sourceId, 'source-layer': 'amm-runway-marking', minzoom: 13, paint: { 'fill-color': C.runwayMarking, 'fill-opacity': 0.85 } },
1905
- { id: 'amm-restricted-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-restricted', minzoom: 11, paint: { 'fill-color': C.restricted, 'fill-opacity': 0.1 } },
1906
- { id: 'amm-restricted-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-restricted', minzoom: 11, paint: { 'line-color': C.restricted, 'line-width': 1.2, 'line-dasharray': [4, 2] } },
1907
- { id: 'amm-hotspot-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-hotspot', minzoom: 11, paint: { 'fill-color': C.hotspot, 'fill-opacity': 0.12 } },
1908
- { id: 'amm-hotspot-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-hotspot', minzoom: 11, paint: { 'line-color': C.hotspot, 'line-width': 1.2 } },
1909
- { id: 'amm-runway-centerline', type: 'line', source: sourceId, 'source-layer': 'amm-runway-centerline', minzoom: 11, paint: { 'line-color': C.runwayCenterline, 'line-width': 1, 'line-dasharray': [6, 3] } },
1910
- {
1911
- id: 'amm-runway-info', type: 'symbol', source: sourceId, 'source-layer': 'amm-runway-label', minzoom: 13,
1912
- layout: { 'text-field': ['concat', ['coalesce', ['get', 'length'], ''], '×', ['coalesce', ['get', 'width'], ''], 'm'], 'text-size': ['interpolate', ['exponential', 1.5], ['zoom'], 13, 10, 16, 13], 'symbol-placement': 'point', 'text-rotate': ['coalesce', ['get', 'bearing'], 0], 'text-rotation-alignment': 'map', 'text-allow-overlap': true, 'text-ignore-placement': true },
1913
- paint: { 'text-color': '#e4e4e7', 'text-halo-color': H, 'text-halo-width': 2 },
1914
- },
1915
- { id: 'amm-stand-line', type: 'line', source: sourceId, 'source-layer': 'amm-stand-line', minzoom: 13, paint: { 'line-color': C.standLine, 'line-width': 1 } },
1916
- {
1917
- id: 'amm-runway-threshold-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-runway-threshold', minzoom: 12,
1918
- layout: { "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'text-field': ['get', 'idthr'], 'text-size': 14, 'text-allow-overlap': true, 'text-rotation-alignment': 'map', 'icon-rotation-alignment': 'map' },
1919
- paint: { 'text-color': '#ffffff', "icon-color": C.threshold },
1920
- },
1921
- { id: 'amm-stand', type: 'circle', source: sourceId, 'source-layer': 'amm-stand', minzoom: 12, paint: { 'circle-color': C.stand, 'circle-radius': 1.5 } },
1922
- {
1923
- id: 'amm-stand-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-stand', minzoom: 14,
1924
- layout: { 'text-field': ['get', 'idstd'], 'text-size': 9, 'text-anchor': 'bottom', 'text-offset': [0, -0.5], 'text-allow-overlap': false },
1925
- paint: { 'text-color': C.stand, 'text-halo-color': H, 'text-halo-width': 1 },
1926
- },
1927
- { id: 'amm-obstacle-region-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-obstacle-region', minzoom: 11, paint: { 'fill-color': '#fef08a', 'fill-opacity': 0.1 } },
1928
- { id: 'amm-obstacle-region-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-obstacle-region', minzoom: 11, paint: { 'line-color': '#eab308', 'line-width': 1.2, 'line-dasharray': [1.5, 1] } },
1929
- { id: 'amm-obstacle-point', type: 'circle', source: sourceId, 'source-layer': 'amm-obstacle-point', minzoom: 11, paint: { 'circle-color': '#f97316', 'circle-radius': 4, 'circle-stroke-color': H, 'circle-stroke-width': 1 } },
1930
- {
1931
- id: 'amm-obstacle-point-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-obstacle-point', minzoom: 14,
1932
- layout: { 'text-field': ['coalesce', ['get', 'ident'], ['get', 'LABEL']], 'text-size': 9, 'text-anchor': 'bottom', 'text-offset': [0, -0.5], 'text-allow-overlap': false },
1933
- paint: { 'text-color': '#fdba74', 'text-halo-color': H, 'text-halo-width': 1.2 },
1934
- },
1935
- { id: 'amm-construction-fill', type: 'fill', source: sourceId, 'source-layer': 'amm-construction', minzoom: 11, paint: { 'fill-pattern': 'normal:passline', 'fill-opacity': 0.6 } },
1936
- { id: 'amm-construction-stroke', type: 'line', source: sourceId, 'source-layer': 'amm-construction', minzoom: 11, paint: { 'line-color': '#ea580c', 'line-width': 1.2, 'line-dasharray': [4, 2] } },
1937
- {
1938
- id: 'amm-construction-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-construction', minzoom: 13,
1939
- layout: { 'text-field': ['get', 'text'], 'text-size': 9, 'text-anchor': 'center', 'symbol-placement': 'point', 'text-allow-overlap': false },
1940
- paint: { 'text-color': '#f97316', 'text-halo-color': H, 'text-halo-width': 1 },
1941
- },
1942
- ]
2011
+ return buildAMMLayersLight(sourceId, AMM_COLOR_NEUTRAL)
1943
2012
  }
1944
2013
 
1945
2014
  // ── Dispatcher ────────────────────────────────────────────────────────────────
@@ -1955,15 +2024,14 @@ const AMM_LAYER_GROUPS = {
1955
2024
  ammRunway: ['amm-runway-fill', 'amm-runway-stroke', 'amm-runway-info',
1956
2025
  'amm-runway-marking', 'amm-runway-centerline',
1957
2026
  'amm-runway-threshold', 'amm-runway-threshold-label'],
1958
- ammApron: ['amm-apron-fill', 'amm-apron-stroke'],
1959
- ammTaxiway: ['amm-taxiway-fill', 'amm-taxiway-line', 'amm-taxiway-label'],
1960
- ammHolding: ['amm-holding'],
1961
- ammStand: ['amm-stand', 'amm-stand-label', 'amm-stand-line'],
1962
- ammRestricted: ['amm-restricted-fill', 'amm-restricted-stroke'],
1963
- ammHotspot: ['amm-hotspot-fill', 'amm-hotspot-stroke'],
2027
+ ammApron: ['amm-apron-fill', 'amm-apron-label'],
2028
+ ammTaxiway: ['amm-taxiway-fill', 'amm-taxiway-line', 'amm-taxiway-label', 'amm-taxiway-guidanceline', 'amm-taxiway-intersectionline'],
2029
+ ammHolding: ['amm-holding', 'amm-holding-label'],
2030
+ ammStand: ['amm-stand-label', 'amm-stand-line'],
2031
+ ammRestricted: ['amm-restricted-fill'],
2032
+ ammHotspot: ['amm-hotspot-fill'],
1964
2033
  /** 障碍物(点 + 面) */
1965
- ammObstacle: ['amm-obstacle-region-fill', 'amm-obstacle-region-stroke',
1966
- 'amm-obstacle-point', 'amm-obstacle-point-label'],
2034
+ ammObstacle: ['amm-obstacle-region-fill', 'amm-obstacle-point-label'],
1967
2035
  ammConstruction: ['amm-construction-fill', 'amm-construction-stroke', 'amm-construction-label'],
1968
2036
  };
1969
2037
 
@@ -1977,10 +2045,22 @@ const TYPEMAP = {
1977
2045
  ocean: ["ocean_label"],
1978
2046
  airspace: ["airspaceLayer", "airspace_label_side_layer", "airspaceLayer_line", "airspace_label_center_layer"],
1979
2047
  airline: ["airline", "airline_label", "airline_point", "airline_radial"],
1980
- controlled: ["controlledLayer", "controlledLayer_stroke", "controlled_line_label"],
1981
- restricted: ["restrictedLayer", "restrictedLayer_stroke", "restricted_line_label"],
1982
- vor: ["vor_icon", "vor_icon_dial", "vor_label"],
1983
- ndb: ["ndb_icon"],
2048
+ controlled: [
2049
+ "controlledLayer",
2050
+ "controlledLayer_stroke_left_bg",
2051
+ "controlledLayer_stroke_border",
2052
+ "controlledLayer_stroke",
2053
+ "controlled_line_label",
2054
+ ],
2055
+ restricted: [
2056
+ "restrictedLayer",
2057
+ "restrictedLayer_stroke_border",
2058
+ "restrictedLayer_stroke_bg",
2059
+ "restrictedLayer_stroke",
2060
+ "restricted_line_label",
2061
+ ],
2062
+ vor: ["vor_icon", "vor_icon_dial", "vor_label", "vor_label_detail"],
2063
+ ndb: ["ndb_icon", "ndb_label_detail"],
1984
2064
  airport: ["airport", "airport-runway", "airport-runway-cross"],
1985
2065
  adiz: ["adiz-line", "adiz-label"],
1986
2066
  waypointOffAirway: ["waypoint-off-airway-symbol"],
@@ -7448,9 +7528,9 @@ function getAviationBaseStyle(opts) {
7448
7528
  { id: "normal", url: `${spriteBase}/kyresources/sprite-color` },
7449
7529
  { id: "default", url: `${spriteBase}/kyresources/sprite` },
7450
7530
  { id: "v2", url: `${spriteBase}/kyresources/sprite-v2` },
7451
- { id: "vor", url: `${spriteBase}/kyresources/sprite-vor` },
7452
7531
  { id: "runway", url: `${spriteBase}/kyresources/sprite-runway` },
7453
7532
  { id: "stretch", url: `${spriteBase}/kyresources/sprite-stretch` },
7533
+ { id: "navig", url: `${spriteBase}/kyresources/sprite-navig` },
7454
7534
  ],
7455
7535
  sources: {
7456
7536
  land: { type: "geojson", data: LAND_FC },
@@ -9780,10 +9860,9 @@ const THEME_TOKENS = {
9780
9860
  airspaceStroke: '#6F7E68',
9781
9861
  restrictedFill: '#FAD7A0',
9782
9862
  restrictedFillPattern: "",
9783
- restrictedStrokeLine: '#f6bf65',
9784
- restrictedStroke: '#D35400', // 限制区标注文字色(ICAO 导出/图例用)
9785
- controlledStroke: '#10B981',
9786
- controlledFill: '#10B981',
9863
+ restrictedStrokeLine: '#ca84a0',
9864
+ restrictedStroke: '#ca84a0',
9865
+ controlled: '#5fa4d9',
9787
9866
  segment: '#1C2526',
9788
9867
  segmentWith: ['interpolate', ['linear'], ['zoom'], 6, 0.2, 8, 0.8],
9789
9868
  segmentRemark: '#E8A020', // HAS_REMARK 航段
@@ -9792,10 +9871,14 @@ const THEME_TOKENS = {
9792
9871
  airportText: '#006400', // 机场文字色(非 AMM)
9793
9872
  runway: '#006400',
9794
9873
  vorDial: '#0b417a',
9795
- vorNormal: '#3874cb',
9874
+ vorNormal: '#00008B',
9796
9875
  vor: '#00008B',
9876
+ vorCompass: '#2E4053',
9877
+ vorCompassPointer: '#000000',
9797
9878
  ndbIcon: 'v2:ndb-normal', // 图标按主题不同(正常)
9798
9879
  ndb: '#0066CC',
9880
+ navAidDetailText: '#000000',
9881
+ navAidDetailHalo: '#ffffff',
9799
9882
  waypoint: '#1C2526',
9800
9883
  airlinePointIcon: ['case', ['==', ['get', 'report_type'], 'C'], 'waypoint-compusory', 'waypoint'],
9801
9884
  // airline_label format 内嵌文字色
@@ -9820,7 +9903,7 @@ const THEME_TOKENS = {
9820
9903
  restrictedFill: ['case', ['==', ['get', 'CODE_TYPE'], 'P'], '#ef4444', ['==', ['get', 'CODE_TYPE'], 'D'], '#f97316', '#ef4444'],
9821
9904
  restrictedStrokeLine: '#CC7722',
9822
9905
  restrictedStroke: '#CC7722',
9823
- controlledStroke: '#22C55E',
9906
+ controlled: '#22C55E',
9824
9907
  controlledFill: '#22C55E',
9825
9908
  segment: '#40C4FF',
9826
9909
  segmentWith: ['interpolate', ['linear'], ['zoom'], 6, 0.2, 8, 0.8],
@@ -9832,8 +9915,12 @@ const THEME_TOKENS = {
9832
9915
  vorDial: '#38bdf8',
9833
9916
  vorNormal: '#38bdf8',
9834
9917
  vor: '#72aae5',
9918
+ vorCompass: '#38bdf8',
9919
+ vorCompassPointer: '#E0F7FA',
9835
9920
  ndbIcon: 'ndb-inway',
9836
9921
  ndb: '#62d6ef',
9922
+ navAidDetailText: '#E0F7FA',
9923
+ navAidDetailHalo: '#0f172a',
9837
9924
  waypoint: '#74cdde',
9838
9925
  airlinePointIcon: ['case', ['==', ['get', 'report_type'], 'C'], 'waypoint-compusory', 'waypoint'],
9839
9926
  alBase: '#0f172a', alDist: '#cbd5e1', alRnp: '#FFFFFF',
@@ -9860,7 +9947,7 @@ const THEME_TOKENS = {
9860
9947
  restrictedFillPattern: "",
9861
9948
  restrictedStrokeLine: '#e59866',
9862
9949
  restrictedStroke: '#e59866',
9863
- controlledStroke: '#52c9a3',
9950
+ controlled: '#52c9a3',
9864
9951
  controlledFill: '#52c9a3',
9865
9952
  segment: '#8fa8c7',
9866
9953
  segmentWith: ['interpolate', ['linear'], ['zoom'], 6, 0.2, 8, 0.8],
@@ -9872,8 +9959,12 @@ const THEME_TOKENS = {
9872
9959
  vorDial: '#5dade2',
9873
9960
  vorNormal: '#5dade2',
9874
9961
  vor: '#85a9e0',
9962
+ vorCompass: '#5dade2',
9963
+ vorCompassPointer: '#dce9f0',
9875
9964
  ndbIcon: 'ndb-inway',
9876
9965
  ndb: '#7ec8e3',
9966
+ navAidDetailText: '#dce9f0',
9967
+ navAidDetailHalo: '#16212c',
9877
9968
  waypoint: '#a9c6d8',
9878
9969
  airlinePointIcon: ['case', ['==', ['get', 'report_type'], 'C'], 'waypoint-compusory', 'waypoint'],
9879
9970
  alBase: '#1B2838', alDist: '#b8c9d9', alRnp: '#f4c542',
@@ -9901,7 +9992,7 @@ const THEME_TOKENS = {
9901
9992
  restrictedFillPattern: "",
9902
9993
  restrictedStrokeLine: '#C0392B',
9903
9994
  restrictedStroke: '#C0392B',
9904
- controlledStroke: '#2E5C8A',
9995
+ controlled: '#2E5C8A',
9905
9996
  controlledFill: '#2E5C8A',
9906
9997
  segment: '#34495E',
9907
9998
  segmentWith: ['interpolate', ['linear'], ['zoom'], 6, 0.2, 8, 0.8],
@@ -9913,8 +10004,12 @@ const THEME_TOKENS = {
9913
10004
  vorDial: '#2E5C8A',
9914
10005
  vorNormal: '#2E5C8A',
9915
10006
  vor: '#154360',
10007
+ vorCompass: '#2E5C8A',
10008
+ vorCompassPointer: '#1B2631',
9916
10009
  ndbIcon: 'v2:ndb-normal',
9917
10010
  ndb: '#8B5A2B',
10011
+ navAidDetailText: '#1B2631',
10012
+ navAidDetailHalo: '#F2EFE6',
9918
10013
  waypoint: '#2C3E50',
9919
10014
  airlinePointIcon: ['case', ['==', ['get', 'report_type'], 'C'], 'waypoint-compusory', 'waypoint'],
9920
10015
  alBase: '#F2EFE6', alDist: '#5D6D7E', alRnp: '#D68910',
@@ -9940,7 +10035,7 @@ const THEME_TOKENS = {
9940
10035
  restrictedStrokeLine: '#7E524D',
9941
10036
  restrictedStrokeLineWidth: 1.2,
9942
10037
  restrictedStroke: '#D35400', // 限制区标注文字色(ICAO 导出/图例用)
9943
- controlledStroke: "#88918088",
10038
+ controlled: "#88918088",
9944
10039
  controlledFill: '#C7CEC096',
9945
10040
  segment: '#1C2526',
9946
10041
  segmentWith: ['interpolate', ['linear'], ['zoom'], 6, 1.9, 10, 2.2],
@@ -9952,8 +10047,12 @@ const THEME_TOKENS = {
9952
10047
  vorDial: '#0b417a',
9953
10048
  vorNormal: '#3874cb',
9954
10049
  vor: '#00008B',
10050
+ vorCompass: '#2E4053',
10051
+ vorCompassPointer: '#000000',
9955
10052
  ndbIcon: 'v2:ndb-normal', // 图标按主题不同(正常)
9956
10053
  ndb: '#0066CC',
10054
+ navAidDetailText: '#000000',
10055
+ navAidDetailHalo: '#ffffff',
9957
10056
  waypoint: '#1C2526',
9958
10057
  airlinePointIcon: ['case', ['==', ['get', 'report_type'], 'C'], 'designate_point_inway', 'designate_point_notinway'],
9959
10058
  airlinePointIconSize: 0.65,
@@ -9980,6 +10079,8 @@ const THEME_TOKENS = {
9980
10079
  function buildLayers(themeId = 'light') {
9981
10080
  const T = THEME_TOKENS[themeId] ?? THEME_TOKENS.light;
9982
10081
  const sourceId = 'navdata';
10082
+ const isLightTheme = themeId === 'light';
10083
+ const frutigerBold = ['Frutiger Bold'];
9983
10084
  // `has` alone is insufficient for segment labels: the data can carry an
9984
10085
  // empty direction field. Keep all direction decisions on non-empty values.
9985
10086
  const hasText = (field) => [
@@ -10026,6 +10127,7 @@ function buildLayers(themeId = 'light') {
10026
10127
  ],
10027
10128
  layout: {
10028
10129
  'text-field': ['get', 'name_en'],
10130
+ 'text-font': frutigerBold,
10029
10131
  // zoom 插值必须为顶层表达式;每个档位再乘以按 scalerank 得到的大小倍率
10030
10132
  // (scalerank 0=大洋→最大, 8→最小)。
10031
10133
  'text-size': 11,
@@ -10052,16 +10154,67 @@ function buildLayers(themeId = 'light') {
10052
10154
  },
10053
10155
  {
10054
10156
  id: 'airspace_label_side_layer', type: 'symbol', source: sourceId, 'source-layer': 'fir', minzoom: 4,
10055
- layout: { 'text-field': ["concat", ["get", "TXT_NAME"], "/", ["get", "CODE_ID"], "/", ["get", "CODE_TYPE"]], 'text-size': 10, 'symbol-placement': 'line', 'text-max-width': 8, "text-offset": [0, 1], "text-letter-spacing": 0.05, "text-optional": true },
10157
+ layout: { 'text-field': ["concat", ["get", "TXT_NAME"], "/", ["get", "CODE_ID"], "/", ["get", "CODE_TYPE"]], 'text-font': frutigerBold, 'text-size': 10, 'symbol-placement': 'line', 'text-max-width': 8, "text-offset": [0, 1], "text-letter-spacing": 0.05, "text-optional": true },
10056
10158
  paint: { 'text-color': T.airspaceStroke, ...T.sideHalo },
10057
10159
  },
10058
10160
  {
10059
- id: 'airspace_label_center_layer', type: 'symbol', source: sourceId, 'source-layer': 'fir-centroid', minzoom: 3,
10161
+ id: 'airspace_label_center_layer', type: 'symbol', source: sourceId, 'source-layer': 'fir-centroid',
10162
+ minzoom: 3,
10163
+ "maxzoom": 6,
10060
10164
  layout: {
10061
- 'text-field': ['coalesce', ['get', 'CODE_ID'], ['get', 'TXT_NAME']],
10062
- 'text-size': ['interpolate', ['linear'], ['zoom'], 3, 12, 17, 16],
10165
+ 'text-field': '{CODE_ID}',
10166
+ 'text-font': frutigerBold,
10063
10167
  'symbol-placement': 'point',
10064
10168
  'text-max-width': 8,
10169
+ 'symbol-sort-key': ['*', -1, ['get', 'SIZE']],
10170
+ "text-letter-spacing": 0.02,
10171
+ "text-size": [
10172
+ "interpolate",
10173
+ ["linear"],
10174
+ ["zoom"],
10175
+
10176
+ // Z2:全球视角
10177
+ 2,
10178
+ [
10179
+ "interpolate",
10180
+ ["linear"],
10181
+ ["sqrt", ["get", "SIZE"]],
10182
+ 100, 9,
10183
+ 316, 11,
10184
+ 707, 13,
10185
+ 1000, 14,
10186
+ 1414, 16,
10187
+ 2236, 18
10188
+ ],
10189
+
10190
+ // Z4:区域视角
10191
+ 4,
10192
+ [
10193
+ "interpolate",
10194
+ ["linear"],
10195
+ ["sqrt", ["get", "SIZE"]],
10196
+ 100, 10,
10197
+ 316, 12,
10198
+ 707, 14,
10199
+ 1000, 16,
10200
+ 1414, 18,
10201
+ 2236, 20
10202
+ ],
10203
+
10204
+ // Z6:FIR 最后显示层级
10205
+ 6,
10206
+ [
10207
+ "interpolate",
10208
+ ["linear"],
10209
+ ["sqrt", ["get", "SIZE"]],
10210
+ 100, 11,
10211
+ 316, 13,
10212
+ 707, 15,
10213
+ 1000, 17,
10214
+ 1414, 19,
10215
+ 2236, 21
10216
+ ]
10217
+ ]
10065
10218
  },
10066
10219
  paint: {
10067
10220
  'text-color': T.airspaceStroke,
@@ -10077,14 +10230,57 @@ function buildLayers(themeId = 'light') {
10077
10230
  'fill-opacity': ["interpolate", ["linear"], ["zoom"], 10, 0.15, 11.5, 0],
10078
10231
  },
10079
10232
  },
10233
+ {
10234
+ id: 'restrictedLayer_stroke_bg', type: 'line', source: sourceId, 'source-layer': 'restricted',
10235
+ paint: {
10236
+ 'line-color': T.restrictedStrokeLine,
10237
+ 'line-opacity': isLightTheme ? ['step', ['zoom'], 0, 6, 0.2] : 0,
10238
+ 'line-offset': ['interpolate', ['exponential', 2], ['zoom'], 6, 1, 7, 1, 10, 5],
10239
+ 'line-width': ['interpolate', ['exponential', 2], ['zoom'], 6, 1, 7, 2, 10, 10],
10240
+ },
10241
+ },
10080
10242
  {
10081
10243
  id: 'restrictedLayer_stroke', type: 'line', source: sourceId, 'source-layer': 'restricted',
10082
- paint: { 'line-color': T.restrictedStrokeLine, 'line-width': T.restrictedStrokeLineWidth || 1, "line-dasharray": [2, 2], "line-opacity": ['interpolate', ['linear'], ['zoom'], 4, 0.5, 8, 1] },
10244
+ layout: isLightTheme
10245
+ ? { 'line-join': 'round', 'line-cap': 'round' }
10246
+ : {},
10247
+ paint: isLightTheme
10248
+ ? {
10249
+ 'line-color': T.restrictedStrokeLine,
10250
+ 'line-opacity': ['step', ['zoom'], 0, 6, 1],
10251
+ 'line-width': ['interpolate', ['exponential', 2], ['zoom'], 6, 0.5, 7, 1, 8, 2],
10252
+ }
10253
+ : {
10254
+ 'line-color': T.restrictedStrokeLine,
10255
+ 'line-width': T.restrictedStrokeLineWidth || 1,
10256
+ 'line-opacity': ['interpolate', ['linear'], ['zoom'], 4, 0.5, 8, 1],
10257
+ },
10083
10258
  },
10084
10259
  {
10085
10260
  id: 'restricted_line_label', type: 'symbol', source: sourceId, 'source-layer': 'restricted', minzoom: 6,
10086
- layout: { 'text-field': ["concat", ["get", "TXT_NAME"], "/", ["get", "CODE_ID"], "/", ["get", "CODE_TYPE"]], "text-letter-spacing": 0.1, 'text-size': 10, 'symbol-placement': 'line', 'text-max-width': 8, "text-offset": [0, 1] },
10087
- paint: { 'text-color': T.restrictedStroke, ...T.restrictedHalo },
10261
+ layout: {
10262
+ 'text-field': [
10263
+ 'concat',
10264
+ ['get', 'TXT_NAME'],
10265
+ ':',
10266
+ [
10267
+ 'case',
10268
+ ['==', ['get', 'alt_lower'], 0],
10269
+ 'GND',
10270
+ ['to-string', ['get', 'alt_lower']]
10271
+ ],
10272
+ '-',
10273
+ [
10274
+ 'case',
10275
+ ['==', ['get', 'alt_upper'], 99999],
10276
+ 'UNL',
10277
+ ['to-string', ['get', 'alt_upper']]
10278
+ ]
10279
+ ], 'text-font': frutigerBold, "text-letter-spacing": 0.1, 'text-size': 10, 'symbol-placement': 'line', 'text-max-width': 8, "text-offset": [0, 1.5]
10280
+ },
10281
+ paint: isLightTheme
10282
+ ? { 'text-color': T.restrictedStroke, 'text-halo-color': T.halo, 'text-halo-width': 0.5 }
10283
+ : { 'text-color': T.restrictedStroke, ...T.restrictedHalo },
10088
10284
  },
10089
10285
  {
10090
10286
  id: 'controlledLayer', type: 'fill', source: sourceId, 'source-layer': 'controlled-fill', minzoom: 4,
@@ -10093,14 +10289,60 @@ function buildLayers(themeId = 'light') {
10093
10289
  "fill-opacity": ["interpolate", ["linear"], ["zoom"], 10, 0.035, 11.5, 0],
10094
10290
  },
10095
10291
  },
10292
+ {
10293
+ // Based on Navigraph's controlled-airspace treatment. The current
10294
+ // navdata stack calls this source-layer `controlled`; no `lo` filter is
10295
+ // applied so all controlled-airspace features remain visible.
10296
+ id: 'controlledLayer_stroke_left_bg', type: 'line', source: sourceId, 'source-layer': 'controlled',
10297
+ paint: {
10298
+ 'line-color': T.controlled,
10299
+ 'line-opacity': isLightTheme ? ['step', ['zoom'], 0, 6, 0.2] : 0,
10300
+ 'line-offset': ['interpolate', ['exponential', 2], ['zoom'], 6, 0, 7, 1, 10, 5],
10301
+ 'line-width': ['interpolate', ['exponential', 2], ['zoom'], 6, 1, 7, 2, 10, 10],
10302
+ },
10303
+ },
10096
10304
  {
10097
10305
  id: 'controlledLayer_stroke', type: 'line', source: sourceId, 'source-layer': 'controlled',
10098
- paint: { 'line-color': T.controlledStroke, 'line-width': 1, 'line-opacity': ['interpolate', ['linear'], ['zoom'], 4, 0.5, 8, 1], "line-dasharray": [1, 1.4] },
10306
+ layout: isLightTheme
10307
+ ? { 'line-join': 'round', 'line-cap': 'square' }
10308
+ : {},
10309
+ paint: isLightTheme
10310
+ ? {
10311
+ 'line-color': T.controlled,
10312
+ 'line-dasharray': [2, 2, 4, 2],
10313
+ 'line-opacity': ['interpolate', ['linear'], ['zoom'], 6, 0, 6.5, 1],
10314
+ 'line-width': 1,
10315
+ }
10316
+ : {
10317
+ 'line-color': T.controlled,
10318
+ 'line-width': 1,
10319
+ 'line-opacity': ['interpolate', ['linear'], ['zoom'], 4, 0.5, 8, 1],
10320
+ 'line-dasharray': [1, 1.4],
10321
+ },
10099
10322
  },
10100
10323
  {
10101
10324
  id: 'controlled_line_label', type: 'symbol', source: sourceId, 'source-layer': 'controlled', minzoom: 6,
10102
- layout: { 'text-field': ["concat", ["get", "TXT_NAME"], "/", ["get", "CODE_ID"], "/", ["get", "CODE_TYPE"]], 'text-size': 10, 'symbol-placement': 'line', 'text-letter-spacing': 0.2, 'text-max-width': 8, "text-offset": [0, 1] },
10103
- paint: { 'text-color': T.controlledStroke, ...T.controlledHalo },
10325
+ layout: {
10326
+ 'text-field': [
10327
+ 'concat',
10328
+ ['get', 'TXT_NAME'],
10329
+ ':',
10330
+ [
10331
+ 'case',
10332
+ ['==', ['get', 'alt_lower'], 0],
10333
+ 'GND',
10334
+ ['to-string', ['get', 'alt_lower']]
10335
+ ],
10336
+ '-',
10337
+ [
10338
+ 'case',
10339
+ ['==', ['get', 'alt_upper'], 99999],
10340
+ 'UNL',
10341
+ ['to-string', ['get', 'alt_upper']]
10342
+ ]
10343
+ ], 'text-font': frutigerBold, 'text-size': 10, 'symbol-placement': 'line', 'text-letter-spacing': 0.2, 'text-max-width': 8, "text-offset": [0, 1.5]
10344
+ },
10345
+ paint: { 'text-color': T.controlled, ...T.controlledHalo },
10104
10346
  },
10105
10347
  {
10106
10348
  id: 'airline', type: 'line', source: sourceId, 'source-layer': 'segment', minzoom: 6,
@@ -10111,13 +10353,64 @@ function buildLayers(themeId = 'light') {
10111
10353
  "line-opacity": ["interpolate", ["linear"], ["zoom"], 6, 0.5, 7, 1, 8, 1, 12, 0.8, 15, 0.2],
10112
10354
  }
10113
10355
  },
10356
+ {
10357
+ "id": "airline-shadow",
10358
+ "type": "line",
10359
+ "source": sourceId,
10360
+ "source-layer": "segment-shdow",
10361
+ "minzoom": 6,
10362
+ "layout": {
10363
+ "line-cap": "round",
10364
+ "line-join": "round"
10365
+ },
10366
+ "paint": {
10367
+ "line-color": T.segment,
10368
+ "line-width": {
10369
+ "base": 2,
10370
+ "stops": [
10371
+ [
10372
+ 3,
10373
+ 0.1
10374
+ ],
10375
+ [
10376
+ 8,
10377
+ 1
10378
+ ]
10379
+ ]
10380
+ },
10381
+ "line-dasharray": [
10382
+ 2,
10383
+ 2
10384
+ ],
10385
+ "line-opacity": {
10386
+ "base": 2,
10387
+ "stops": [
10388
+ [
10389
+ 5,
10390
+ 0.125
10391
+ ],
10392
+ [
10393
+ 8,
10394
+ 0.2
10395
+ ]
10396
+ ]
10397
+ }
10398
+ },
10399
+ },
10114
10400
  {
10115
10401
  id: 'airline_label', type: 'symbol', source: sourceId, 'source-layer': 'segment', minzoom: 6,
10116
10402
  layout: {
10117
- "icon-image": ["case", hasBothDesignation, "stretch:segment-both", hasForwardDesignation, "stretch:segment-right", hasBackwardDesignation, "stretch:segment-left", "stretch:segment-both"],
10403
+ "icon-image": [
10404
+ 'match',
10405
+ ['get', 'DIRECTION'],
10406
+ 'FORWARD', 'stretch:segment-right',
10407
+ 'BACKWARD', 'stretch:segment-left',
10408
+ 'stretch:segment-both',
10409
+ ],
10118
10410
  "icon-anchor": "center", "symbol-placement": "line", "icon-text-fit": "width", "icon-size": 1,
10119
10411
  "text-allow-overlap": false, "icon-allow-overlap": false, "text-optional": false,
10120
10412
  "text-anchor": "center", "text-justify": "center", "text-line-height": 1.3, "text-letter-spacing": 0.1,
10413
+ "text-font": ['Frutiger Regular'],
10121
10414
  "text-field": ["step", ["zoom"],
10122
10415
  ["format", ["case", hasBothDesignation, ["get", "TXT_DESIG"], hasForwardDesignation, ["get", "TXT_DESIG_FORWARD"], hasBackwardDesignation, ["get", "TXT_DESIG_BACKWARD"], "-"], { "font-scale": 1, "text-color": T.alBase }],
10123
10416
  10,
@@ -10143,21 +10436,88 @@ function buildLayers(themeId = 'light') {
10143
10436
  },
10144
10437
  },
10145
10438
  {
10146
- id: 'airline_radial', type: 'symbol', source: sourceId, 'source-layer': 'segment-radial', minzoom: 13,
10147
- layout: {
10148
- 'text-field': ['concat', ['get', 'bearing'], '°'],
10149
- 'text-size': 9,
10150
- 'text-rotate': ['to-number', ['get', 'line_angle'], 0],
10151
- 'text-rotation-alignment': 'map',
10152
- 'text-allow-overlap': true,
10153
- 'text-ignore-placement': true,
10154
- 'text-offset': [0, -0.6],
10155
- 'text-justify': 'auto',
10439
+ id: 'airline_radial', type: 'symbol', source: sourceId, 'source-layer': 'segment-radial', minzoom: 11,
10440
+ "layout": {
10441
+ "text-rotation-alignment": "map",
10442
+ "text-line-height": 0.5,
10443
+ "text-font": [
10444
+ "Font11"
10445
+ ],
10446
+ "text-padding": 1,
10447
+ "text-size": {
10448
+ "base": 2,
10449
+ "stops": [
10450
+ [
10451
+ 8,
10452
+ 6
10453
+ ],
10454
+ [
10455
+ 10,
10456
+ 8
10457
+ ]
10458
+ ]
10459
+ },
10460
+ "symbol-placement": "line-center",
10461
+ "text-field": [
10462
+ "concat",
10463
+ [
10464
+ "case",
10465
+ [
10466
+ "<",
10467
+ [
10468
+ "to-number",
10469
+ [
10470
+ "get",
10471
+ "bearing"
10472
+ ]
10473
+ ],
10474
+ 10
10475
+ ],
10476
+ "00",
10477
+ [
10478
+ "case",
10479
+ [
10480
+ "<",
10481
+ [
10482
+ "to-number",
10483
+ [
10484
+ "get",
10485
+ "bearing"
10486
+ ]
10487
+ ],
10488
+ 100
10489
+ ],
10490
+ "0",
10491
+ ""
10492
+ ]
10493
+ ],
10494
+ [
10495
+ "get",
10496
+ "bearing"
10497
+ ],
10498
+ "^"
10499
+ ]
10500
+ },
10501
+ "paint": {
10502
+ "text-color": T.segment,
10503
+ "text-halo-color": T.halo,
10504
+ "text-halo-width": {
10505
+ "base": 2,
10506
+ "stops": [
10507
+ [
10508
+ 8,
10509
+ 0.8
10510
+ ],
10511
+ [
10512
+ 10,
10513
+ 1.2
10514
+ ]
10515
+ ]
10516
+ }
10156
10517
  },
10157
- paint: { 'text-color': T.segment, ...T.radialHalo },
10158
10518
  },
10159
10519
  {
10160
- id: 'airport', type: 'symbol', source: sourceId, minzoom: 2, 'source-layer': 'airport',
10520
+ id: 'airport', type: 'symbol', source: sourceId, minzoom: 2.5, 'source-layer': 'airport',
10161
10521
  // 4级前就显示大型机场+中型,5级后全部显示
10162
10522
  filter:
10163
10523
  ['case',
@@ -10187,7 +10547,7 @@ function buildLayers(themeId = 'light') {
10187
10547
  "text-optional": true,
10188
10548
  "visibility": "none",
10189
10549
  "icon-size": ["interpolate", ["linear"], ["zoom"], 2, 0.6, 5, 0.7, 9, 1, 12, 1.1],
10190
- 'text-font': ['Open Sans Semibold'],
10550
+ 'text-font': frutigerBold,
10191
10551
  },
10192
10552
  paint: {
10193
10553
  'icon-color': ['case', ['has', 'has_amm'], T.airportamm, T.airport],
@@ -10274,9 +10634,22 @@ function buildLayers(themeId = 'light') {
10274
10634
  },
10275
10635
  {
10276
10636
  id: 'vor_icon_dial', type: 'symbol', source: sourceId, 'source-layer': 'vor', minzoom: 8,
10637
+ 'maxzoom': 12,
10277
10638
  layout: {
10278
- "icon-image": "vor:vor_dial",
10279
- "icon-size": ["interpolate", ["linear"], ["zoom"], 8, 0.072, 10, 0.072, 11, 0.126, 12, 0.180, 13, 0.234, 14, 0.288, 15, 0.342, 16, 0.396, 17, 0.450, 22, 0.450],
10639
+ "icon-image": "navig:compass",
10640
+ "icon-size": {
10641
+ "base": 2,
10642
+ "stops": [
10643
+ [
10644
+ 8,
10645
+ 0.0625
10646
+ ],
10647
+ [
10648
+ 12,
10649
+ 1
10650
+ ]
10651
+ ]
10652
+ },
10280
10653
  "icon-rotate": ["to-number", ["get", "VAL_MAG_VAR"], 0],
10281
10654
  "icon-rotation-alignment": "map",
10282
10655
  "symbol-z-order": "viewport-y",
@@ -10288,10 +10661,140 @@ function buildLayers(themeId = 'light') {
10288
10661
  paint: { "icon-color": T.vorDial }
10289
10662
  },
10290
10663
  {
10291
- id: 'vor_icon', minzoom: 4, maxzoom: 9, type: 'symbol', source: sourceId, 'source-layer': 'vor',
10664
+ "id": "vor_icon_dial_arrow",
10665
+ "type": "symbol",
10666
+ "source": sourceId,
10667
+ "source-layer": 'vor',
10668
+ "minzoom": 8.5,
10669
+ 'maxzoom': 12,
10670
+ "layout": {
10671
+ "icon-rotation-alignment": "map",
10672
+ "icon-allow-overlap": true,
10673
+ "icon-image": "navig:compass-arrow",
10674
+ "icon-rotate": ["to-number", ["get", "VAL_MAG_VAR"], 0],
10675
+ "icon-size": {
10676
+ "base": 2,
10677
+ "stops": [
10678
+ [
10679
+ 8,
10680
+ 0.0625
10681
+ ],
10682
+ [
10683
+ 12,
10684
+ 1
10685
+ ]
10686
+ ]
10687
+ }
10688
+ },
10689
+ "paint": {
10690
+ "icon-color": T.vorDial
10691
+ }
10692
+ },
10693
+ {
10694
+ "id": "vor-compass-ring",
10695
+ "type": "line",
10696
+ "source": sourceId,
10697
+ "source-layer": "compass",
10698
+ "minzoom": 12.1,
10699
+ "filter": [
10700
+ "==",
10701
+ [
10702
+ "get",
10703
+ "kind"
10704
+ ],
10705
+ "ring"
10706
+ ],
10707
+ "layout": {
10708
+ "line-cap": "round",
10709
+ "line-join": "round",
10710
+ "visibility": "visible"
10711
+ },
10712
+ "paint": {
10713
+ "line-color": T.vorDial,
10714
+ "line-width": 1.15,
10715
+ "line-opacity": 0.9
10716
+ }
10717
+ },
10718
+ {
10719
+ "id": "vor-compass-ticks",
10720
+ "type": "line",
10721
+ "source": sourceId,
10722
+ "source-layer": "compass",
10723
+ "minzoom": 12.1,
10724
+ "filter": [
10725
+ "==",
10726
+ [
10727
+ "get",
10728
+ "kind"
10729
+ ],
10730
+ "ticks"
10731
+ ],
10732
+ "layout": {
10733
+ "line-cap": "round",
10734
+ "line-join": "round",
10735
+ "visibility": "visible"
10736
+ },
10737
+ "paint": {
10738
+ "line-color": T.vorDial,
10739
+ "line-width": [
10740
+ "match",
10741
+ [
10742
+ "get",
10743
+ "rank"
10744
+ ],
10745
+ "cardinal",
10746
+ 1.7,
10747
+ "major",
10748
+ 1.4,
10749
+ "medium",
10750
+ 1.2,
10751
+ 1
10752
+ ],
10753
+ "line-opacity": 0.9
10754
+ }
10755
+ },
10756
+ {
10757
+ "id": "vor-compass-pointer",
10758
+ "type": "line",
10759
+ "source": sourceId,
10760
+ "source-layer": "compass",
10761
+ "minzoom": 12.1,
10762
+ "filter": [
10763
+ "==",
10764
+ [
10765
+ "get",
10766
+ "kind"
10767
+ ],
10768
+ "pointer"
10769
+ ],
10770
+ "layout": {
10771
+ "line-cap": "round",
10772
+ "line-join": "round",
10773
+ "visibility": "visible"
10774
+ },
10775
+ "paint": {
10776
+ "line-color": T.vorDial,
10777
+ "line-width": 1.8,
10778
+ "line-opacity": 1
10779
+ }
10780
+ },
10781
+ {
10782
+ id: 'vor_icon', minzoom: 4, type: 'symbol', source: sourceId, 'source-layer': 'vor',
10292
10783
  layout: {
10293
- "icon-image": "v2:vor-normal",
10294
- "icon-size": ["interpolate", ["linear"], ["zoom"], 4, 0.7, 8, 1],
10784
+ "icon-image": "navig:vordme",
10785
+ "icon-size": {
10786
+ "base": 2,
10787
+ "stops": [
10788
+ [
10789
+ 5,
10790
+ 0.4
10791
+ ],
10792
+ [
10793
+ 7,
10794
+ 0.5
10795
+ ]
10796
+ ]
10797
+ },
10295
10798
  "icon-rotation-alignment": "map",
10296
10799
  "symbol-z-order": "viewport-y",
10297
10800
  "text-letter-spacing": 0.05,
@@ -10300,13 +10803,40 @@ function buildLayers(themeId = 'light') {
10300
10803
  },
10301
10804
  paint: {
10302
10805
  "icon-color": T.vorNormal,
10303
- "icon-opacity": ["interpolate", ["linear"], ["zoom"], 8, 1, 9, 0],
10806
+ "icon-halo-color": "#fff",
10807
+ 'icon-opacity': 1,
10808
+ "icon-halo-width": {
10809
+ "base": 2,
10810
+ "stops": [
10811
+ [
10812
+ 5,
10813
+ 0.5
10814
+ ],
10815
+ [
10816
+ 7,
10817
+ 1
10818
+ ]
10819
+ ]
10820
+ },
10821
+ "icon-halo-blur": {
10822
+ "base": 2,
10823
+ "stops": [
10824
+ [
10825
+ 5,
10826
+ 0.5
10827
+ ],
10828
+ [
10829
+ 7,
10830
+ 1
10831
+ ]
10832
+ ]
10833
+ }
10304
10834
  }
10305
10835
  },
10306
10836
  {
10307
- id: 'vor_label', type: 'symbol', source: sourceId, 'source-layer': 'vor', minzoom: 5,
10837
+ id: 'vor_label', type: 'symbol', source: sourceId, 'source-layer': 'vor', minzoom: 5, maxzoom: 8,
10308
10838
  layout: {
10309
- 'text-field': ['get', 'CODE_ID'], 'text-size': 10, 'text-anchor': 'top',
10839
+ 'text-field': ['get', 'CODE_ID'], 'text-font': ['Frutiger Regular'], 'text-size': 10, 'text-anchor': 'top',
10310
10840
  'text-offset': [0, 0.8]
10311
10841
  },
10312
10842
  paint: { 'text-color': T.vor, 'text-halo-color': T.halo, 'text-halo-width': 1 },
@@ -10316,12 +10846,8 @@ function buildLayers(themeId = 'light') {
10316
10846
  layout: {
10317
10847
  "icon-image": T.ndbIcon, "icon-size": ["interpolate", ["linear"], ["zoom"], 6, 0.5, 10, 1],
10318
10848
  "symbol-z-order": "viewport-y",
10319
- "text-field": [
10320
- "format",
10321
- ["get", "CODE_ID"], { "text-color": T.ndb, "font-scale": 1.1 },
10322
- "", {},
10323
- ["coalesce", ["get", "VAL_FREQ"], ""], { "text-color": T.ndb, "font-scale": 0.95 }
10324
- ],
10849
+ "text-font": frutigerBold,
10850
+ "text-field": ["get", "CODE_ID"],
10325
10851
  "text-size": 10,
10326
10852
  "text-offset": [0, 0.5],
10327
10853
  "text-letter-spacing": 0.05,
@@ -10333,10 +10859,67 @@ function buildLayers(themeId = 'light') {
10333
10859
  "text-color": T.ndb,
10334
10860
  ...T.ndbHalo,
10335
10861
  "icon-color": T.ndb,
10336
- "text-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0, 5.5, 0, 6, 0.6, 8, 1, 10, 0.3],
10862
+ "text-opacity": ["step", ["zoom"], 0, 5.5, 0, 6, 0.6, 7, 1, 8, 0],
10337
10863
  "icon-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0, 5, 0.3, 5.5, 0.8, 8, 1, 12, 1, 14, 0.6],
10338
10864
  }
10339
10865
  },
10866
+ {
10867
+ id: 'vor_label_detail', type: 'symbol', source: sourceId, 'source-layer': 'vor', minzoom: 8,
10868
+ layout: {
10869
+ 'text-max-width': 20,
10870
+ 'text-allow-overlap': false,
10871
+ 'text-size': ['interpolate', ['exponential', 2], ['zoom'], 5, 6, 7, 10.5],
10872
+ 'text-radial-offset': 1,
10873
+ 'text-justify': 'auto',
10874
+ 'text-variable-anchor': ['bottom', 'right', 'left', 'top', 'bottom-right', 'bottom-left', 'top-right', 'top-left'],
10875
+ 'text-font': ['Fira Code SemiBold'],
10876
+ 'text-padding': 8,
10877
+ 'text-line-height': 0.2,
10878
+ 'text-field': [
10879
+ 'case',
10880
+ ['==', ['get', 'VAL_FREQ'], 0],
10881
+ ['get', 'CODE_ID'],
10882
+ ['format',
10883
+ ['get', 'TXT_NAME'], { 'font-scale': 0.8 },
10884
+ '\n\n\n\n\n\n', {},
10885
+ ['get', 'CODE_ID'], { 'font-scale': 1.5, 'text-font': ['literal', ['Morse']] },
10886
+ '\n', {},
10887
+ ['concat',
10888
+ ['case', ['==', ['get', 'ARINC'], ''], '', ['concat', ' ', ['get', 'ARINC'], ' ']],
10889
+ ['get', 'VAL_FREQ'], ' ', ['get', 'CODE_ID'],
10890
+ ], {},
10891
+ ],
10892
+ ],
10893
+ },
10894
+ paint: { 'text-color': T.navAidDetailText, 'text-halo-color': T.navAidDetailHalo, 'text-halo-width': 0.2 },
10895
+ },
10896
+ {
10897
+ id: 'ndb_label_detail', type: 'symbol', source: sourceId, 'source-layer': 'ndb', minzoom: 8,
10898
+ layout: {
10899
+ 'text-max-width': 20,
10900
+ 'text-allow-overlap': false,
10901
+ 'text-size': ['interpolate', ['exponential', 2], ['zoom'], 5, 6, 7, 10.5],
10902
+ 'text-radial-offset': 1,
10903
+ 'text-justify': 'auto',
10904
+ 'text-variable-anchor': ['bottom', 'right', 'left', 'top', 'bottom-right', 'bottom-left', 'top-right', 'top-left'],
10905
+ 'text-font': ['Fira Code SemiBold'],
10906
+ 'text-padding': 8,
10907
+ 'text-line-height': 0.2,
10908
+ 'text-field': [
10909
+ 'case',
10910
+ ['==', ['get', 'VAL_FREQ'], 0],
10911
+ ['get', 'CODE_ID'],
10912
+ ['format',
10913
+ ['get', 'TXT_NAME'], { 'font-scale': 0.8 },
10914
+ '\n\n\n\n\n\n', {},
10915
+ ['get', 'CODE_ID'], { 'font-scale': 1.5, 'text-font': ['literal', ['Morse']] },
10916
+ '\n', {},
10917
+ ['get', 'VAL_FREQ'], ' ', ['get', 'CODE_ID'], {},
10918
+ ],
10919
+ ],
10920
+ },
10921
+ paint: { 'text-color': T.navAidDetailText, 'text-halo-color': T.navAidDetailHalo, 'text-halo-width': 0.2 },
10922
+ },
10340
10923
  {
10341
10924
  id: 'airline_point', type: 'symbol', source: sourceId, 'source-layer': 'waypoint', minzoom: 6,
10342
10925
  layout: {
@@ -10349,7 +10932,7 @@ function buildLayers(themeId = 'light') {
10349
10932
  "text-letter-spacing": 0.02,
10350
10933
  'text-variable-anchor-offset': ['bottom', [0, -0.6], 'top', [0, 0.6], 'right', [-0.6, 0], 'left', [0.6, 0], 'bottom-right', [-0.4, -0.4], 'bottom-left', [0.4, -0.4], 'top-right', [-0.4, 0.4], 'top-left', [0.4, 0.4]],
10351
10934
  'text-justify': 'auto',
10352
- 'text-font': ['Open Sans Semibold']
10935
+ 'text-font': frutigerBold
10353
10936
  },
10354
10937
  paint: {
10355
10938
  'icon-color': T.waypoint,
@@ -10365,7 +10948,7 @@ function buildLayers(themeId = 'light') {
10365
10948
  },
10366
10949
  {
10367
10950
  id: 'waypoint-off-airway-symbol', type: 'symbol', source: sourceId, 'source-layer': 'waypoint-off-airway', minzoom: 7,
10368
- layout: { 'icon-image': ['case', ['==', ['get', 'report_type'], 'C'], 'designate_point_inway', 'designate_point_notinway'], 'icon-size': 0.6, 'icon-allow-overlap': true, 'icon-ignore-placement': true, 'text-field': ['get', 'CODE_ID'], 'text-size': 9, 'text-variable-anchor-offset': ['bottom', [0, -0.6], 'top', [0, 0.6], 'right', [-0.6, 0], 'left', [0.6, 0], 'bottom-right', [-0.4, -0.4], 'bottom-left', [0.4, -0.4], 'top-right', [-0.4, 0.4], 'top-left', [0.4, 0.4]], 'text-justify': 'auto', 'text-optional': true },
10951
+ layout: { 'icon-image': ['case', ['==', ['get', 'report_type'], 'C'], 'designate_point_inway', 'designate_point_notinway'], 'icon-size': 0.6, 'icon-allow-overlap': true, 'icon-ignore-placement': true, 'text-field': ['get', 'CODE_ID'], 'text-font': frutigerBold, 'text-size': 9, 'text-variable-anchor-offset': ['bottom', [0, -0.6], 'top', [0, 0.6], 'right', [-0.6, 0], 'left', [0.6, 0], 'bottom-right', [-0.4, -0.4], 'bottom-left', [0.4, -0.4], 'top-right', [-0.4, 0.4], 'top-left', [0.4, 0.4]], 'text-justify': 'auto', 'text-optional': true },
10369
10952
  paint: {
10370
10953
  'icon-color': T.waypoint, 'text-color': T.waypoint, 'text-halo-color': T.halo, 'text-halo-width': 1,
10371
10954
  "icon-opacity": ["interpolate", ["linear"], ["zoom"], 7, 0.5, 12, 1, 15, 0.2],
@@ -10389,12 +10972,24 @@ const CHART_THEMES = {
10389
10972
  const LAYER_GROUPS = {
10390
10973
  adiz: ['adiz-line', 'adiz-label'],
10391
10974
  airspace: ['airspaceLayer', 'airspaceLayer_line', 'airspace_label_center_layer', 'airspace_label_side_layer'],
10392
- restricted: ['restrictedLayer', 'restrictedLayer_stroke', 'restricted_line_label'],
10393
- controlled: ['controlledLayer', 'controlledLayer_stroke', 'controlled_line_label'],
10394
- airline: ['airline_radial', 'airline', 'airline_label', 'airline_point'],
10975
+ restricted: [
10976
+ 'restrictedLayer',
10977
+ 'restrictedLayer_stroke_border',
10978
+ 'restrictedLayer_stroke_bg',
10979
+ 'restrictedLayer_stroke',
10980
+ 'restricted_line_label',
10981
+ ],
10982
+ controlled: [
10983
+ 'controlledLayer',
10984
+ 'controlledLayer_stroke_left_bg',
10985
+ 'controlledLayer_stroke_border',
10986
+ 'controlledLayer_stroke',
10987
+ 'controlled_line_label',
10988
+ ],
10989
+ airline: ['airline_radial', 'airline', 'airline-shadow', 'airline_label', 'airline_point'],
10395
10990
  waypointOffAirway: ['waypoint-off-airway-symbol'],
10396
- vor: ['vor_icon_dial', 'vor_label', 'vor_icon'],
10397
- ndb: ['ndb_icon'],
10991
+ vor: ['vor_icon_dial', 'vor_icon_dial_arrow', 'vor_label', 'vor_label_detail', 'vor_icon'],
10992
+ ndb: ['ndb_icon', 'ndb_label_detail'],
10398
10993
  airport: ['airport', 'airport-runway', 'airport-runway-cross'],
10399
10994
  };
10400
10995