Add a raster tile layer

Learn how to add a raster tile layer to a map.

A raster tile layer, also known as an image tile layer, displays imagery such as satellite photography or hillshading. You can combine raster tile layers to enhance the display of a street basemap layer, position the layer on top of existing layers, or position it under existing layers. When positioned above other layers, you need to give the raster tile layer a level of transparency so that users can see through it to the basemap. This combined basemap layer technique is used to enhance overall visualization.

In this tutorial, you add a Hillshade raster tile layer, which is a basemap layer composed of jpeg images, on top of a street basemap layer.

Prerequisites

You need an ArcGIS account to access the developer dashboard and create an API key.

Steps

Create a new pen

  1. To get started, either complete the Display a map tutorial or .

Set the API key

To access location services, you need an API key or OAuth 2.0 access token.

  1. Go to your dashboard to get an API key. The API key must be scoped to access the services used in this tutorial.

  2. In CodePen, update apiKey to use your key.

              
    Change line
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //
    
    const apiKey = "YOUR_API_KEY";
    const basemapEnum = "ArcGIS:Streets";
    const map = new mapboxgl.Map({
      container: "map", // the id of the div element
      style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
      zoom: 12, // starting zoom
      center: [-118.805, 34.027] // starting location [longitude, latitude]
    });
    

Add a load event handler

To add layers to the map, you need to use the load event to ensure the map is fully loaded.

  1. Add an event handler for the load event.

    For more information about the load event, see the Mapbox GL JS documentation.

                                                                            
    Add line.Add line.Add line.Add line.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
        </style>
      </head>
    
      <body>
        <div id="map"></div>
    
        <script>
          const apiKey = "YOUR_API_KEY";
          const basemapEnum = "ArcGIS:Streets";
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
            zoom: 12, // starting zoom
            center: [-118.805, 34.027] // starting location [longitude, latitude]
          });
    
          map.once("load", () => {
            // This code runs once the base style has finished loading.
    
            map.addSource("hillshade", {
              type: "raster",
              tiles: [
                "https://server.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}.jpeg?token=" + apiKey
            // Find the first non-background layer in order to add our raster layer before it.
            const layers = map.getStyle().layers;
            const bottomLayer = layers.find((layer) => layer.type !== "background");
                id: "hillshade-raster",
                type: "raster",
                source: "hillshade"
            layers.forEach((layer) => {
              if (layer.type === "fill" && !layer.id.match(/(Water area|Marine area|Bathymetry|Building)/)) {
                map.setPaintProperty(layer.id, "fill-opacity", 0.5);
          });
    
        </script>
    
      </body>
    </html>

Add a raster source

You need to define a source for the raster tiles. This tells the Map how to access the data for the layer, but does not display it.

  1. Inside the load event handler, add a raster source with id hillshade.

    While there are several types of source, the most common are vector for vector tiles, raster for raster tiles, and geojson for a set of features represented as GeoJSON.

    For more information, see the Mapbox GL JS Style Specification

                                                                            
    Add line.Add line.Add line.Add line.Add line.Add line.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
        </style>
      </head>
    
      <body>
        <div id="map"></div>
    
        <script>
          const apiKey = "YOUR_API_KEY";
          const basemapEnum = "ArcGIS:Streets";
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
            zoom: 12, // starting zoom
            center: [-118.805, 34.027] // starting location [longitude, latitude]
          map.once("load", () => {
            // This code runs once the base style has finished loading.
    
            map.addSource("hillshade", {
              type: "raster",
              tiles: [
                "https://server.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}.jpeg?token=" + apiKey
              ]
            });
    
            // Find the first non-background layer in order to add our raster layer before it.
            const layers = map.getStyle().layers;
            const bottomLayer = layers.find((layer) => layer.type !== "background");
                id: "hillshade-raster",
                type: "raster",
                source: "hillshade"
            layers.forEach((layer) => {
              if (layer.type === "fill" && !layer.id.match(/(Water area|Marine area|Bathymetry|Building)/)) {
                map.setPaintProperty(layer.id, "fill-opacity", 0.5);
          });
        </script>
    
      </body>
    </html>

Add a raster layer

To display the raster tiles, add a layer of type raster.

A layer in Mapbox GL JS is a visual representation of the data within one source

For more information, see the Mapbox GL JS Style Specification.

  1. Add a raster layer with id hillshade-raster, connected to the hillshade source.

                                                                            
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
        </style>
      </head>
    
      <body>
        <div id="map"></div>
    
        <script>
          const apiKey = "YOUR_API_KEY";
          const basemapEnum = "ArcGIS:Streets";
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
            zoom: 12, // starting zoom
            center: [-118.805, 34.027] // starting location [longitude, latitude]
          map.once("load", () => {
            // This code runs once the base style has finished loading.
    
            map.addSource("hillshade", {
              type: "raster",
              tiles: [
                "https://server.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}.jpeg?token=" + apiKey
              ]
            });
    
            // Find the first non-background layer in order to add our raster layer before it.
            const layers = map.getStyle().layers;
            const bottomLayer = layers.find((layer) => layer.type !== "background");
            map.addLayer(
              {
                id: "hillshade-raster",
                type: "raster",
                source: "hillshade"
              },
    
            );
    
            layers.forEach((layer) => {
              if (layer.type === "fill" && !layer.id.match(/(Water area|Marine area|Bathymetry|Building)/)) {
                map.setPaintProperty(layer.id, "fill-opacity", 0.5);
          });
        </script>
    
      </body>
    </html>
  2. At the top right, click Run. You should see the hillshade layer only.

Adjust the basemap

By default, the hillshade layer is added on top of all the basemap layers. To visually combine hillshading with roads and park layers, you need to make two changes.

  1. Move the hillshade layer below every layer except the background layer. You do this by passing the id of the next layer as an extra argument to map.addLayer.

  2. Reduce the opacity of most fill layers so the hillshade layer can be seen through them. In the ArcGIS:Streets basemap, this includes several layers whose ids begin with Water area, Marine area, Bathymetry or Building. You can use map.getStyle to get the current style, and its layers property to access all layers. Use map.setPaintProperty to change the fill-opacity for each layer.

  3. In the load handler, find the id of the first non-background layer. Modify your addLayer call to insert the raster layer before that layer.

                                                                            
    Add line.Add line.Add line.Add line.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
        </style>
      </head>
    
      <body>
        <div id="map"></div>
    
        <script>
          const apiKey = "YOUR_API_KEY";
          const basemapEnum = "ArcGIS:Streets";
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
            zoom: 12, // starting zoom
            center: [-118.805, 34.027] // starting location [longitude, latitude]
          map.once("load", () => {
            // This code runs once the base style has finished loading.
            map.addSource("hillshade", {
              type: "raster",
              tiles: [
                "https://server.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}.jpeg?token=" + apiKey
            // Find the first non-background layer in order to add our raster layer before it.
            const layers = map.getStyle().layers;
            const bottomLayer = layers.find((layer) => layer.type !== "background");
    
            map.addLayer(
              {
                id: "hillshade-raster",
                type: "raster",
                source: "hillshade"
              },
    
              bottomLayer.id
    
            );
            layers.forEach((layer) => {
              if (layer.type === "fill" && !layer.id.match(/(Water area|Marine area|Bathymetry|Building)/)) {
                map.setPaintProperty(layer.id, "fill-opacity", 0.5);
        </script>
    
      </body>
    </html>
  4. Set 50% fill-opacity for every fill layer except water and building layers.

                                                                            
    Add line.Add line.Add line.Add line.Add line.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
        <script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
        <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
        <style>
          html,
          body,
          #map {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 14px;
            color: #323232;
        </style>
      </head>
    
      <body>
        <div id="map"></div>
    
        <script>
          const apiKey = "YOUR_API_KEY";
          const basemapEnum = "ArcGIS:Streets";
          const map = new mapboxgl.Map({
            container: "map", // the id of the div element
            style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
            zoom: 12, // starting zoom
            center: [-118.805, 34.027] // starting location [longitude, latitude]
          map.once("load", () => {
            // This code runs once the base style has finished loading.
            map.addSource("hillshade", {
              type: "raster",
              tiles: [
                "https://server.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}.jpeg?token=" + apiKey
            // Find the first non-background layer in order to add our raster layer before it.
            const layers = map.getStyle().layers;
            const bottomLayer = layers.find((layer) => layer.type !== "background");
                id: "hillshade-raster",
                type: "raster",
                source: "hillshade"
              bottomLayer.id
    
            );
    
            layers.forEach((layer) => {
              if (layer.type === "fill" && !layer.id.match(/(Water area|Marine area|Bathymetry|Building)/)) {
                map.setPaintProperty(layer.id, "fill-opacity", 0.5);
              }
            });
        </script>
    
      </body>
    </html>

Run the app

In CodePen, run your code to display the map.

Your map should display a semi-transparent hillshade layer overlaid over a basemap. You should see the hillshade layer combined with other layers, with labels, roads, buildings and water areas clearly visible over the top.

What's next?

Learn how to use additional ArcGIS location services in these tutorials:

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.