Learn how to use style a feature layer.
A feature layer is a dataset in a feature service hosted in an ArcGIS portal. 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.
In this tutorial, you use symbol, line, and fill layers to style three hosted feature layers using the MapLibre ArcGIS plugin.
Prerequisites
You need an ArcGIS Location Platform or ArcGIS Online account.
Steps
Get the starter app
Select a type of authentication below and follow the steps to create a new application.
Set up authentication
Create developer credentials in your portal for the type of authentication you selected.
Set developer credentials
Use the API key or OAuth developer credentials so your application can access ArcGIS services.
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 zoom: 12, // starting zoom center: [-118.805, 34.027] // starting location [longitude, latitude] }); const basemapStyle = maplibreArcGIS.BasemapStyle.applyStyle(map, { style: 'arcgis/outdoor', token: accessToken }); map.loadImage("https://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png").then((resp) => { });
-
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").then((resp) => { map.addImage("hiker-icon", resp.data); });
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 an asynchronous function called
show
. Inside, use the plugin to create a newTrailheads Feature
object that references the Trailheads feature service, then add the sources to the map.Layer Use dark colors for code blocks map.loadImage("https://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png").then((resp) => { map.addImage("hiker-icon", resp.data); }); async function showTrailheads() { const trailheads = await maplibreArcGIS.FeatureLayer.fromUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0"); trailheads.addSourcesTo(map); }); }
-
Add a symbol layer for the hiker icons. Use
icon-image
to reference the icon you loaded.Use dark colors for code blocks async function showTrailheads() { const trailheads = await maplibreArcGIS.FeatureLayer.fromUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0"); trailheads.addSourcesTo(map); map.addLayer({ ...trailheads.layer, type: "symbol", 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 Use dark colors for code blocks map.addLayer({ ...trailheads.layer, type: "symbol", 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", async () => { await showTrailheads(); });
Style and display all trails
-
Create an asynchronous function called
show
. Inside, use the plugin to create a newTrails Feature
object that references Trails feature service, then add the sources to the map.Layer Use dark colors for code blocks }, paint: { "text-color": "white", "text-halo-color": "seagreen", "text-halo-width": 2 } }); } async function showTrails() { const trails = await maplibreArcGIS.FeatureLayer.fromUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0"); trails.addSourcesTo(map);
-
Add a line layer with id
trails-line
to display thetrails
source.Use dark colors for code blocks async function showTrails() { const trails = await maplibreArcGIS.FeatureLayer.fromUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0"); trails.addSourcesTo(map); map.addLayer({ ...trails.layer, paint: { "line-color": "hsl(291, 44%, 60%)", "line-opacity": 0.75 } });
-
To show trails that allow bikes with a dashed line, create a new layer that sits above the other layer. You can reuse the existing source with a different id of
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({ ...trails.layer, paint: { "line-color": "hsl(291, 44%, 60%)", "line-width": ["interpolate", ["linear"], ["get", "ELEV_GAIN"], 0, 3, 2300, 7], "line-opacity": 0.75 } }); map.addLayer({ ...trails.layer, id: "bike-trails", filter: ["==", ["get", "USE_BIKE"], "Yes"], paint: { "line-dasharray": [1, 2], "line-width": 2, "line-color": "hsl(300, 100%, 78.4%)" } }); }
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({ ...trails.layer, paint: { "line-color": "hsl(291, 44%, 60%)", "line-width": ["interpolate", ["linear"], ["get", "ELEV_GAIN"], 0, 3, 2300, 7], "line-opacity": 0.75 } });
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 an asynchronous function called
show
. Inside, use the plugin to create a newParks Feature
object that references the Parks feature service, then add the sources to the map.Layer Use dark colors for code blocks map.addLayer({ ...trails.layer, id: "bike-trails", filter: ["==", ["get", "USE_BIKE"], "Yes"], paint: { "line-dasharray": [1, 2], "line-width": 2, "line-color": "hsl(300, 100%, 78.4%)" } }); } async function showParks() { const parks = await maplibreArcGIS.FeatureLayer.fromUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0"); parks.addSourcesTo(map); }
-
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 async function showParks() { const parks = await maplibreArcGIS.FeatureLayer.fromUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0"); parks.addSourcesTo(map); map.addLayer({ ...parks.layer, // The layer property contains a preformatted maplibre layer, including a layer ID and source. paint: { // Override default paint properties provided by parks.layer "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", async () => { await showParks(); await showTrails(); await showTrailheads(); });
Run the app
Run the app.
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 location services in these tutorials: