Style a feature layer
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. Layers in OpenLayers can contain style functions, which use attribute values to change the appearance of features. This allows you to create complex, data-driven visualizations by relating visual variables to data attributes.
In this tutorial, you apply different styles to enhance the visualization of the Trailheads, Trails and Parks and Open Spaces feature layers.
Prerequisites
You need a free ArcGIS developer account to access your dashboard and API keys. The API key must be scoped to access the services used in this tutorial.
Steps
Create a new pen
- To get started, either complete the Display a map tutorial or .
Set the API key
To access ArcGIS location services, you need an API key.
Go to your dashboard to get an API key.
In CodePen, update
apiKey
to use your key.Change line const apiKey = "YOUR-API-KEY"; const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL);
Style trailheads with a hiker image and labels
A Style
in OpenLayers has several possible components: an image, text, stroke, fill and so on. To display a hiker icon for the trailheads layer, you use an Icon
style as the image
component. Specify which image file as the src
, and the size as the scale
parameter.
To display the trailhead name, you use a Text
style. Use a left
value for textAlign
with an offsetX
of 10 to display the labels to the right of the icons. Use Fill
and Stroke
styles as the fill
and stroke
properties to give the labels white text with a teal outline. The font
property is a CSS font definition. Since the label for each trailhead is different, use a function to return a Style
for a given feature. Set the text
property using feature's TRL_NAME
attribute.
Add a map load handler to the
olms
initialization. Inside, create atrailheadStyle
function that takes afeature
and returns aStyle
containing anIcon
style. Usehttp://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png
for thesrc
and set ascale
of 25%.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
Add a
Text
style to display labels with white text, teal outline, in an italic sans-serif font. Set thetext
property using the feature'sTRL_NAME
attribute.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
Add the Trailheads feature layer to the map
Use a Vector
layer with a Vector
source to display the trailheads.
For more information about adding feature layers using GeoJSON, see the Add a feature layer as GeoJSON tutorial.
Add a
Vector
layer with aVector
source to load and display the trailheads feature layer. Setdeclutter
to be true to prevent label overlap. Pass thetrailheadsStyle
function as thestyle
property. Usemap.addLayer
to add this layer to the map.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
At the top right, click Run to test your map. You should see hiker icons and trailhead labels.
Style trail width by elevation gain
To visualize the elevation gain of a trail you can use the width of a Stroke
style. To do this, create another function which returns a Style
. The width
of the style's stroke
property will be a calculation converting feet of elevation gain to pixels of width.
Create a
trailStyle
function that takes afeature
and returns aStyle
with aStroke
style. Set thecolor
to pink, and calculate thewidth
property from the feature'sELEV_GAIN
attribute.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
Add the Trails feature layer as a
Vector
layer with a GeoJSONVector
source. Pass yourtrailStyle
function as thestyle
property. UseinsertAt
to add this layer below the trailheads layer.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
At the top right, click Run to test your map. You should see the hiking trails in pink with thicker lines for those with more elevation gain.
Add a filtered bike-only trails layer
To dipslay bike-only trails, you can add another style function to display a dashed line for trails that allow biking. You can display a dashed line by passing an array of alternating stroke and gap segments length as the lineDash
property in a Stroke
style.
The same source from the trailsLayer
can be used.
Create a
bikeTrailsStyle
function. If the feature has aYes
value forUSE_BIKE
, return a white dashedStroke
style. Otherwise, do not return aStyle
, so the feature will not be displayed.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
Add a
bikeTrailsLayer
using the source fromtrailsLayer
, with thebikeTrailsStyle
function. Insert the layer above thetrailsLayer
.Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
At the top right, click Run to test your map. You should now see the bike-accessible trails with a dashed line.
Style a polygon layer
You can use color to communicate the category of a feature, such as the type of a park or open space. Use a style function to returns a Fill
style, in which you derive the color
property from the feature's TYPE
property.
Create a
parksStyle
function which returns aFill
style. Look up the feature'sTYPE
attribute in a table to give a different color forNatural Areas
,Regionla Open Space
,Local Park
andRegional Recreation Park
. If the type is not one of these, make the color transparent.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
Create a
Vector
layer with aVector
source for the parks feature layer. Pass yourparksStyle
function as thestyle
property, with a low opacity. Insert the parks layer below the trails layers.Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>OpenLayers Tutorials: Style feature layers</title> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@6.1.4/dist/olms.js" type="text/javascript"></script> </head> <body> <div id="map"></div> <script> const apiKey = "YOUR-API-KEY"; const map = new ol.Map({ target: "map" }); map.setView( new ol.View({ center: ol.proj.fromLonLat([-118.805, 34.027]), zoom: 12 }) ); const basemapId = "ArcGIS:Streets"; const basemapURL = "https://basemaps-api.arcgis.com/arcgis/rest/services/styles/" + basemapId + "?type=style&apiKey=" + apiKey; olms(map, basemapURL).then(function (map) { const trailheadStyle = function (feature) { return new ol.style.Style({ image: new ol.style.Icon({ src: "http://static.arcgis.com/images/Symbols/NPS/npsPictograph_0231b.png", scale: 0.25 }), text: new ol.style.Text({ text: feature.get("TRL_NAME"), font: "italic 12px sans-serif", offsetX: 10, textAlign: "left", fill: new ol.style.Fill({ color: "#FFFFFF" }), stroke: new ol.style.Stroke({ color: "#5E8D74", width: 3 }) }) }); }; 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"; const trailheadsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailheadsLayerURL }), style: trailheadStyle, declutter: true }); map.addLayer(trailheadsLayer); const trailStyle = function (feature) { return new ol.style.Style({ stroke: new ol.style.Stroke({ color: "#BA55D3", width: 3 + (4 * feature.get("ELEV_GAIN")) / 2300 }) }); }; 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"; const trailsLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: trailsLayerURL }), style: trailStyle }); map.getLayers().insertAt(1, trailsLayer); const bikeTrailsStyle = function (feature) { if (feature.get("USE_BIKE") === "Yes") { return new ol.style.Style({ stroke: new ol.style.Stroke({ lineDash: [1, 4], color: "white", width: 2 }) }); } }; const bikeTrailsLayer = new ol.layer.Vector({ source: trailsLayer.getSource(), style: bikeTrailsStyle }); map.getLayers().insertAt(2, bikeTrailsLayer); const parksStyle = function (feature) { const type = feature.get("TYPE"); const colorTable = { "Natural Areas": "#9E559C", "Regional Open Space": "#A7C636", "Local Park": "#149ECE", "Regional Recreation Park": "#ED5151" }; return new ol.style.Style({ fill: new ol.style.Fill({ color: colorTable[feature.get("TYPE")] || "transparent" }) }); }; 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"; const parksLayer = new ol.layer.Vector({ source: new ol.source.Vector({ format: new ol.format.GeoJSON(), url: parksLayerURL }), opacity: 0.2, style: parksStyle }); map.getLayers().insertAt(1, parksLayer); }); </script> </body> </html>
Run the app
In CodePen, run your code to display the map.
You should now see parks of different colors, beneath the trails and trailhead layers.
What's next?
Learn how to use additional ArcGIS location services in these tutorials: