Custom Map Layers
Layer descriptors are responsible for configuring map layers and rendering data associated with a data source based on a particular style configuration. There are two primary components to a layer: the source that provides the data to render, and a layer style (opens in a new tab) that determines how that data gets rendered on a map.
The following layer descriptors are supported. View their API documentation for more information on how to configure them and their available options:
Descriptor | Description |
---|---|
RasterLayerDescriptor | A descriptor for raster-based layers, such as tile imagery. API docs. |
SampleLayerDescriptor | A descriptor for colorized raster layers, usually from encoded raster data sources. API docs. |
ParticleLayerDescriptor | A descriptor for particle-based layers, such as wind or current flow visualizations. API docs. |
FillLayerDescriptor | A descriptor for layers that render polygon geometries, such as weather alerts or administrative boundaries. API docs. |
LineLayerDescriptor | A descriptor for layers that render line geometries, such as roads or rivers. API docs. |
CircleLayerDescriptor | A descriptor for layers that render point geometries as circles, such as weather stations or points of interest. API docs. |
SymbolLayerDescriptor | A descriptor for layers that render point geometries as symbols, such as icons or labels. API docs. |
HeatmapLayerDescriptor | A descriptor for layers that render point geometries as heatmaps, such as population density or lightning strike density. API docs. |
Adding Layers
Once you've set up your sources, you can start configuring and adding your layers to get your data rendered to your map.
For instance, we want to render the alerts
vector tile source we set up in our sources example. Since this is a vector source consisting of polygon geometry, we need to determine if we want to render the data as filled shapes using the fill
(opens in a new tab) render style, or as outlines using the stroke
(opens in a new tab) render style.
For this example, we'll choose to fill the geometry with a red color to start:
// data source must be added first
var alertsSource = VectorSourceDescriptor(id: "alerts")
alertsSource.url = URL(string: "https://maps{s}.aerisapi.com/[CLIENT_ID]_[CLIENT_SECRET]/alerts/{z}/{x}/{y}/0.pbf")
do {
_ = try controller.addSource(alertsSource)
} catch {
print("Failed to add source: \(error)")
}
// add layer and reference the above source id
let alertsLayer = FillLayerDescriptor(
id: "alerts-fill",
source: alertsSource.id,
paint: .init(
fill: .init(
color: .constant(.red)
)
)
)
do {
_ = try controller.addLayer(alertsLayer)
} catch {
print("Failed to add layer: \(error)")
}
Notice in the above configuration we're setting the source
property to alerts
, which is the identifier for the corresponding vector tile source we set up and added to the map controller prior to the layer.
Coloring every alert the same color isn't very informative. Instead, we want to use the fill color provided by a property value for each feature in the data set. In this case, you would need to know what properties are available for each feature in order to select the correct value.
For our alerts
source, each feature has a COLOR
property that gives the hexidecimal color value for that alert type:
{
"ADVISORY": "FLOOD WARNING",
"CAT": "flood",
"COLOR": "00FF00",
"EXPIREDATE": 1652270400,
"LOCATION": "madison",
"STARTDATE": 1652112060,
"VTEC": "FL.W",
"ZONE": "ILC119"
}
So we can update our layer paint configuration to reference this property's value instead to fill each polygon with the correct alert color:
let alertsLayer = FillLayerDescriptor(
id: "alerts-fill",
source: alertsSource.id,
paint: .init(
fill: .init(
color: .expression(
Expression.get("COLOR")
)
)
)
)
We can even add a black outline to the polygons so that neighboring features of the same color are clearer:
let alertsLayer = FillLayerDescriptor(
id: "alerts-fill",
source: alertsSource.id,
paint: .init(
fill: .init(
color: .expression(
Expression.get("COLOR")
)
),
stroke: .init(
color: .constant(.black)
)
)
)
By configuring our fill.color
as an .expression(Expression.get("COLOR"))
, we are informing the renderer that we want the fill color for each feature to be determined by the value of the COLOR
property in the feature's available properties. Refer to the Data-Driven Styling documentation for more information on how to style data features based on the underlying data.
Removing Layers
To remove a layer from your map and map controller, just provide the identifier you assigned the source when it was added to the map:
controller.removeLayer(id: "alerts-fill")
If the layer exists on the map, then it will be removed and perform any necessary cache and object disposal. The data source associated with the layer will still exist, however, until you explicitly remove it using removeSource(id:)
.