Learn how to use data-driven styling to apply symbol colors and styles to feature layers.
A feature layer is a dataset in a feature service hosted in ArcGIS. Each feature layer contains features with a single geometry type (point, line, or polygon), and a set of attributes. A feature layer can be styled in MapLibre GL JS with a layer connected to a GeoJSON source. Layers can contain expressions which use attribute values to calculate values. This lets you create complex, data-driven visualizations by relating visual variables to data attributes.
In this tutorial, you use symbol, line and fill layers to style three hosted feature layers in ArcGIS.
Prerequisites
You need an ArcGIS Location Platform or ArcGIS Online account.
Steps
Create a new pen
- To get started, either complete the Display a map tutorial or .
Get an access token
You need an access token with the correct privileges to access the resources used in this tutorial.
-
Go to the Create an API key tutorial and create an API key with the following privilege(s):
- Privileges
- Location services > Basemaps
- Item access
- Note: If you are using your own custom data layer for this tutorial, you need to grant the API key credentials access to the layer item. Learn more in Item access privileges.
- Privileges
-
Copy the API key access token to your clipboard when prompted.
-
In CodePen, update the
access
variable to use your access token.Token Use dark colors for code blocks const accessToken = "YOUR_ACCESS_TOKEN"; const basemapEnum = "arcgis/streets"; const map = new maplibregl.Map({ container: "map", // the id of the div element style: `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapEnum}?token=${accessToken}`, zoom: 12, // starting zoom center: [-118.805, 34.027] // starting location [longitude, latitude] });
To learn about the other types of authentication available, go to Types of authentication.
Load a hiker icon
To use an image as an icon, you must first load the image into the map style using map.load
and map.add
.
-
Call
map.load
withImage 'https
as the first parameter. The second parameter is a callback taking an error and the image.://static.arcgis.com/images/ Symbols/ NP S/nps Pictograph _0231b.png' See the MapLibre GL JS documentation for more information.
Use dark colors for code blocks const map = new maplibregl.Map({ container: "map", // the id of the div element style: `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapEnum}?token=${accessToken}`, zoom: 12, // starting zoom center: [-118.805, 34.027] // starting location [longitude, latitude] }); map.loadImage("https://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", (error, image) => { });
-
Call
map.add
to defineImage hiker-icon
as the provided image.A MapLibre style can contain a number of images as part of its sprite file.
map.add
is required to display images that are not included in its sprite file.Image See the MapLibre GL JS documentation for more information.
Use dark colors for code blocks map.loadImage("https://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", (error, image) => { if (error) { throw error; } map.addImage("hiker-icon", image); });
Style and display trailheads with a hiker icon and labels
To display an icon of a hiker for each trailhead, along with a label, you can use a single symbol
layer. Properties for the label start with text-
and properties for the icon start with icon-
.
-
Create a function called
show
. Inside, add a GeoJSON source.Trailheads Use dark colors for code blocks map.loadImage("https://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", (error, image) => { if (error) { throw error; } map.addImage("hiker-icon", image); }); function showTrailheads() { const trailheadsLayerName = "Trailheads"; const trailheadsLayerURL = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/" + trailheadsLayerName + "/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson"; map.addSource("trailheads", { type: "geojson", data: trailheadsLayerURL }); }
-
Add a symbol layer for the hiker icons. Use
icon-image
to reference the icon you loaded.Use dark colors for code blocks function showTrailheads() { const trailheadsLayerName = "Trailheads"; const trailheadsLayerURL = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/" + trailheadsLayerName + "/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson"; map.addSource("trailheads", { type: "geojson", data: trailheadsLayerURL }); map.addLayer({ id: "trailheads-symbol", type: "symbol", source: "trailheads", layout: { "icon-image": "hiker-icon", "icon-size": 0.3, "icon-allow-overlap": true, } }); }
-
Add additional label properties. Set a
text-anchor
ofbottom
, with atext-offset
of[0, -2]
to position the label above the icon. Use theTRL
attribute as the text field._NAME For more information see the MapLibre GL JS documentation.
Use dark colors for code blocks map.addLayer({ id: "trailheads-symbol", type: "symbol", source: "trailheads", layout: { "icon-image": "hiker-icon", "icon-size": 0.3, "icon-allow-overlap": true, "text-font": ["Arial Italic"], "text-field": ["get", "TRL_NAME"], "text-size": 12, "text-anchor": "bottom", "text-offset": [0, -2] }, paint: { "text-color": "white", "text-halo-color": "seagreen", "text-halo-width": 2 } });
Add a load event handler
It is important to wait for the MapLibre GL JS map to finish loading before adding any layers.
-
Add an event handler to the map
load
event. Inside, call theshow
function.Trailheads Use dark colors for code blocks }, paint: { "text-color": "white", "text-halo-color": "seagreen", "text-halo-width": 2 } }); } map.on("load", () => { showTrailheads(); });
-
At the top right, click Run to test your map. You should see icons and labels at each of the trailheads.
Style and display all trails
-
Create a
show
function. Inside, add a GeoJSON source with idTrails trails
.Use dark colors for code blocks }, paint: { "text-color": "white", "text-halo-color": "seagreen", "text-halo-width": 2 } }); } function showTrails() { const trailsLayerName = "Trails"; const trailsLayerURL = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/" + trailsLayerName + "/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson"; map.addSource("trails", { type: "geojson", data: trailsLayerURL }); }
-
Add a line layer with id
trails-line
to display thetrails
source.Use dark colors for code blocks function showTrails() { const trailsLayerName = "Trails"; const trailsLayerURL = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/" + trailsLayerName + "/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson"; map.addSource("trails", { type: "geojson", data: trailsLayerURL }); map.addLayer({ id: "trails-line", type: "line", source: "trails", paint: { "line-color": "hsl(291, 44%, 60%)", "line-opacity": 0.75 } }); }
-
At the top right, click Run to test your map. The trails should display as purple lines.
Style trail width by elevation gain
To make the width of the trail line reflect the elevation gain, you can use a MapLibre GL expression as the value of the line-width
. You use the ['interpolate']
and ['get']
expressions to achieve this.
['interpolate', ['linear'], ...
creates a linear mapping from one range of input values (the number of feet of elevation gain) to a range of output values (the number of pixels of line width). You provide "stops", such as mapping 2,300 feet to 7 pixels. See the MapLibre Style Specification for details.
['get', '
accesses the ELEV
property. See the MapLibre Style Specification for details.
-
Update the
trails-line
layer definition that calculatesline-width
from theELEV
attribute._GAIN Use dark colors for code blocks map.addLayer({ id: "trails-line", type: "line", source: "trails", paint: { "line-color": "hsl(291, 44%, 60%)", "line-width": ["interpolate", ["linear"], ["get", "ELEV_GAIN"], 0, 3, 2300, 7], "line-opacity": 0.75 } });
-
At the top right, click Run to test your map. The trails should display as purple lines with varying thickness based on elevation gain.
Display bike-only trails
You can limit a layer to display only certain features by setting a filter. A filter is defined by an expression that should evaluate to true for the features you want included.
To show trails that allow bikes with a dashed line, you can create a new layer that sits above the other trails layer. You can reuse the existing source.
-
Create a function called
show
. Inside, add a layer with idBike Trails biketrails-line
. Use a filter to only show trails whereUSE
has a value of_BIKE YES
. Setline-dasharray
to[1, 2]
to create short dashes.Use dark colors for code blocks map.addLayer({ id: "trails-line", type: "line", source: "trails", paint: { "line-color": "hsl(291, 44%, 60%)", "line-width": ["interpolate", ["linear"], ["get", "ELEV_GAIN"], 0, 3, 2300, 7], "line-opacity": 0.75 } }); } function showBikeTrails() { map.addLayer({ id: "biketrails-line", type: "line", source: "trails", filter: ["==", ["get", "USE_BIKE"], "Yes"], paint: { "line-dasharray": [1, 2], "line-width": 2, "line-color": "hsl(300, 100%, 78.4%)" } }); }
-
In the load event handler, call the
show
andTrails show
functions. Add the calls beforeBike Trails show
so that the trails layers are placed beneath the trailheads.Trailheads Use dark colors for code blocks map.on("load", () => { showTrails(); showBikeTrails(); showTrailheads(); });
-
At the top right, click Run to test your map. The trails should appear as dashed lines for trails that allow bikes.
Display park areas with different colors
You can use a different style for each unique attribute value in a feature layer. Use a ['match', ...]
expression to display park polygons with different colors depending on the TYPE
field.
A ['match', ...]
expression choose between several different output values depending on the input value. See the MapLibre Style Specification for details.
-
Create a function called
show
. Inside, add a GeoJSON source for the parks. Give it an id ofParks parks
.Use dark colors for code blocks map.addLayer({ id: "biketrails-line", type: "line", source: "trails", filter: ["==", ["get", "USE_BIKE"], "Yes"], paint: { "line-dasharray": [1, 2], "line-width": 2, "line-color": "hsl(300, 100%, 78.4%)" } }); } function showParks() { const parksLayerName = "Parks_and_Open_Space"; const parksLayerURL = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/" + parksLayerName + "/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson"; map.addSource("parks", { type: "geojson", data: parksLayerURL }); }
-
Add a fill layer with id
parks-fill
and sourceparks
. For the fill color, use amatch
expression for differentTYPE
values.Use dark colors for code blocks function showParks() { const parksLayerName = "Parks_and_Open_Space"; const parksLayerURL = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/" + parksLayerName + "/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson"; map.addSource("parks", { type: "geojson", data: parksLayerURL }); map.addLayer({ id: "parks-fill", type: "fill", source: "parks", paint: { "fill-color": [ "match", ["get", "TYPE"], "Natural Areas", "#9E559C", "Regional Open Space", "#A7C636", "Local Park", "#149ECE", "Regional Recreation Park", "#ED5151", "black" ], "fill-opacity": 0.2 } }); }
-
Back inside the load event handler, call the
show
functions. Place it before the other functions so that the parks layer is placed under the trails and trailheads.Parks Use dark colors for code blocks map.on("load", () => { showParks(); showTrails(); showBikeTrails(); showTrailheads(); });
Run the app
In CodePen, run your code to display the map.
You should now see trailheads with icons and labels, trails whose width varies by elevation, dashed lines for trails that allow bikes, and parks of different colors.
What's next?
Learn how to use additional ArcGIS location services in these tutorials: