Skip to content
Snippets Groups Projects
map.utils.ts 5.25 KiB
Newer Older
  • Learn to ignore specific revisions
  • Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
    import * as geojson from 'geojson';
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
    import * as L from 'leaflet';
    
    import {Location} from '../nshmp-lib/geo';
    import {MapBaseLayer} from './map-baselayer.model';
    
    /** Location transform */
    export type LocationTransform = (location: Location) => Location;
    
    /**
     * Esri raster base layers for Leaflet.
     *
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
     * https://doc.arcgis.com/en/data-appliance/latest/maps/directory-maps-data.htm
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
     */
    export function baseLayers(): Record<MapBaseLayer, L.TileLayer> {
    
      const baseLayers: Record<MapBaseLayer, L.TileLayer> = {
        /* Esri world hillshade */
        [MapBaseLayer.HILLSHADE]: L.tileLayer(
          `${ARCGIS_URL_START}Elevation/World_Hillshade${ARCGIS_URL_END}`,
          {
            ...OPTIONS,
            attribution:
              'Esri, USGS, NGA, NASA, CGIAR, N Robinson, NCEAS, NLS, OS, NMA, ' +
              'Geodatastyrelsen, Rijkswaterstaat, GSA, Geoland, FEMA, Intermap, ' +
              'and the GIS user community',
            id: MapBaseLayer.HILLSHADE,
          }
        ),
        /* Esri world hillshade */
        [MapBaseLayer.HILLSHADE_DARK]: L.tileLayer(
          `${ARCGIS_URL_START}Elevation/World_Hillshade_Dark${ARCGIS_URL_END}`,
          {
            ...OPTIONS,
            attribution:
              'Esri, USGS, NGA, NASA, CGIAR, N Robinson, NCEAS, NLS, OS, NMA, ' +
              'Geodatastyrelsen, Rijkswaterstaat, GSA, Geoland, FEMA, Intermap, ' +
              'and the GIS user community',
            id: MapBaseLayer.HILLSHADE_DARK,
          }
        ),
        /* Esri world ocean */
        [MapBaseLayer.OCEAN]: L.tileLayer(
          `${ARCGIS_URL_START}Ocean/World_Ocean_Base${ARCGIS_URL_END}`,
          {
            ...OPTIONS,
            attribution: 'Esri, Garmin, GEBCO, NOAA NGDC, and other contributors',
            id: MapBaseLayer.OCEAN,
            maxZoom: 10,
          }
        ),
        /* Esri world physical map */
        [MapBaseLayer.PHYSICAL]: L.tileLayer(
          `${ARCGIS_URL_START}World_Physical_Map${ARCGIS_URL_END}`,
          {
            ...OPTIONS,
            attribution: 'U.S. National Park Service',
            id: MapBaseLayer.PHYSICAL,
            maxZoom: 8,
          }
        ),
        [MapBaseLayer.SATELLITE]: L.tileLayer(
          `${ARCGIS_URL_START}World_Imagery${ARCGIS_URL_END}`,
          {
            ...OPTIONS,
            attribution:
              'Esri, Maxar, Earthstar Geographics, and the GIS User Community',
            id: MapBaseLayer.SATELLITE,
          }
        ),
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
        [MapBaseLayer.USGS_TOPO]: L.tileLayer(
          'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}',
    
          {
            ...OPTIONS,
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
            attribution: `Esri, USGS | Esri, TomTom, FAO, NOAA, USGS | USGS The National Map: National Boundaries
           Dataset, 3DEP Elevation Program, Geographic Names Information System, National Hydrography
           Dataset, National Land Cover Database, National Structures Dataset, and National
           Transportation Dataset; USGS Global Ecosystems; U.S. Census Bureau TIGER/Line data;
           USFS Road data; Natural Earth Data; U.S. Department of State HIU; NOAA National
           Centers for Environmental Information. Data refreshed February, 2025.`,
            id: MapBaseLayer.USGS_TOPO,
    
          }
        ),
      };
    
      return baseLayers;
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
    }
    
    /**
     * Returns a specific Esri raster base layer.
     */
    export function baseLayer(baseLayer: MapBaseLayer): L.TileLayer {
    
      return baseLayers()[baseLayer];
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
    }
    
    /**
     * Transform coordinates in a Feature Collection.
     *
     * @param featureCollection The feature collection
     * @param transform The transform function to use
     */
    export function transformCoordinates(
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
      featureCollection: geojson.FeatureCollection,
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
      transform: LocationTransform = loc => loc
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
    ): geojson.FeatureCollection {
    
    Clayton, Brandon Scott's avatar
    Clayton, Brandon Scott committed
      for (const feature of featureCollection.features) {
        const geometry = feature.geometry;
    
        switch (geometry.type) {
          case 'LineString': {
            geometry.coordinates = geometry.coordinates.map(coord =>
              transformCoordinate(coord, transform)
            );
            break;
          }
          case 'MultiLineString': {
            geometry.coordinates = geometry.coordinates.map(position =>
              position.map(coord => transformCoordinate(coord, transform))
            );
            break;
          }
          case 'MultiPoint': {
            geometry.coordinates = geometry.coordinates.map(coord =>
              transformCoordinate(coord, transform)
            );
            break;
          }
          case 'MultiPolygon': {
            geometry.coordinates = geometry.coordinates.map(positions =>
              positions.map(position =>
                position.map(coord => transformCoordinate(coord, transform))
              )
            );
            break;
          }
          case 'Point': {
            geometry.coordinates = transformCoordinate(
              geometry.coordinates,
              transform
            );
            break;
          }
          case 'Polygon': {
            geometry.coordinates = geometry.coordinates.map(position =>
              position.map(coord => transformCoordinate(coord, transform))
            );
            break;
          }
        }
      }
    
      return featureCollection;
    }
    
    const ARCGIS_URL_START =
      'https://services.arcgisonline.com/arcgis/rest/services/';
    const ARCGIS_URL_END = '/MapServer/tile/{z}/{y}/{x}';
    const OPTIONS: L.MapOptions = {
      maxZoom: 16,
    };
    
    function transformCoordinate(
      coordinates: number[],
      transform: LocationTransform
    ): number[] {
      const longitude = coordinates[0];
      const latitude = coordinates[1];
    
      const location = transform({
        latitude,
        longitude,
      });
    
      return [location.longitude, location.latitude];
    }