Managing Map Data Sources
A weather map can display a variety of different weather data sources at once, such as radar, satellite, earthquakes and storm cells. You can complete control over which data sources appear on your weather map and can add or remove them at any time.
Data Source Types
There are three primary data types for a weather map: raster/tile, point and shape:
tile
: A raster image or tile layer, such as radar or temperatures.vector
: Vector point, polyline and/or polygon data, such as storm reports and convective outlooks.geojson
: Avector
layer that uses data provided in valid GeoJSON format.text
: Data values are rendered as text labels, such as observation elements like temperature or wind speeds.
Using Layer Codes
The interactive weather map has built-in support for automatically creating and managing the various data sources associated with supported layer codes. These layer codes correspond to those currently offered through Xweather Map (opens in a new tab)s.
However, point and shape layers are rendered using data from the Xweather Weather API (opens in a new tab) instead of Maps raster imagery which considerably reduces the number of map units consumed by your weather map. For example, stormcells
and stormreports
layers will use API data instead of Maps imagery on a weather map.
Data Source Types for Layer Codes
The following tables indicate which layer codes are rendered as point, shape or text layers using API data. All other layer codes will use Xweather Raster Maps raster layers:
Layer | Type |
---|---|
air-quality | vector |
convective | vector |
drought-monitor | vector |
earthquakes | vector |
fires | vector |
fire-outlook | vector |
observations | text |
records | vector |
river-observations | vector |
stormcells | vector |
stormreports | vector |
tropical-cyclones | vector |
You can override the default data source type used for a particular layer code by providing a different value for type
in the layer options when calling addLayer()
:
map.addLayer('stormcells', {
type: 'tile'
});
The above would then render stormcells using the Maps raster tile layer instead of requesting data from the Xweather Weather API and rendering the result as markers. The downside to rendering point data as raster tiles is they will not be interactive, meaning you won't be able to select a marker to reveal the callout with additional details for that item.
Adding Layers
To add a layer to your map, just use addLayer()
:
map.addLayer('radar');
You can also add multiple layers at once using addLayers()
:
map.addLayers(['satellite','radar','stormreports']);
When adding layers with their code, you can also provide additional configuration options for the layer as the second parameter to addLayer()
. This should be an object containing values for one or all of the following options depending on the type of layer you're adding (e.g. tile or vector).
Changing the Layer Type
For instance, if you wanted to show storm cells on the map using raster Maps layers instead of as a point data source, you can specify the type
value to override the default source type to use:
map.addLayer('stormcells', {
type: 'tile'
});
Adding Raster Layers
Raster layers are added to the map as tiles. By default, tile data is dependent upon the parent map's current timeline position and will update as the timeline is scrubbed or animated. However, you can specify a specific date/time or time offset when adding a layer by providing custom configuration options.
Raster Layer Options
Option | Type | Description | |
---|---|---|---|
type | string | Type of content source to use if supported by the layer. Supports tile , point or shape . | |
style | RasterStyle | Style configuration to use when rendering the layer on the map. Refer to the styling guide for more details and configuration options. | |
time | Date or number | The timestamp to use for the source data, either as a Date or Epoch time in milliseconds. This value will be ignored if offset is also defined. | |
offset | number or string | Time offset to use for the layer's data. If an offset is defined, then the layer will only display data for that time interval regardless of the global timeline time interval and its animation will be disabled. | |
alwaysShow | boolean | Whether this tile source should always be visible regardless of past or future state. Default value is false . | |
animation | AnimationOptions | Animation options for the layer. Not all options will be used for a specific layer since its animation is managed by the global map timeline. |
Controlling Raster Layer Order
Some raster tile layers should always appear above or below other layers. When adding layers using addLayer()
without a custom RasterStyle
configuration, the layer will always be added on top of all other layers. However, you may want the layer to be inserted at a particular index or at the bottom of the stack.
To control the order in which the layer will be inserted, include a custom RasterStyle
with your call to addLayer()
that specifies the desired z-index of the layer. If the specified z-index value is higher than the total number of layers currently on the map, then the layer will be added to the top of the stack instead.
map.addLayer('satellite', {
style: {
zIndex: 1
}
});
Some third-party mapping libraries allow you to insert layers relative to the map's own layers, such as Mapbox GL (opens in a new tab). If you're using one of these mapping strategies, you can also specify which layer your weather layer should be inserted under. For instance, the following would add the satellite layer underneath the Mapbox layer whose identifier is national_parks
:
map.addLayer('satellite', {
style: {
belowLayer: 'national_park'
}
});
You can also change a layer's stacking order after it's been added to the map by using either bringLayerToFront()
, sendLayerToBack()
, or setLayerOrder()
:
// sends the existing satellite layer behind all other weather layers
map.sendLayerToBack('satellite');
// brings the existing radar layer above all other weather layers
map.bringLayerToFront('radar');
// move the existing alerts layer to third position in the stack of existing weather layers
// z-index positions are zero-based, meaning `0` is the bottom position
map.setLayerOrder('alerts', 2);
Note that using any of the above methods for changing layer ordering will not also add the layer to the map if it does not exist. They only affect existing weather layers. You will still need to add the layer beforehand using addLayer()
or the map's initial configuration.
Using Raster Maps Valid Times
By default, Xweather Raster Maps (opens in a new tab) will automatically redirect requests to the appropriate valid time for the dataset. However, you may need to access the valid times directly in your own applications, such as performing animations for exact valid times in the dataset.
The layerInfo
instance on InteractiveMap
provides a validTimes
property that you can use for fetching the valid times associated with a specific Maps layer. This is just an instance of LayerTimes
that provides two methods for fetching a layer's valid times: times()
and timesInRange()
.
You can fetch the latest valid times for a layer:
map.layerInfo.validTimes.times('radar', 20).then((times) => {
// do something with times...
});
Or, you can fetch the valid times within a specific date range:
const from = map.timeline.startDate();
const to = map.timeline.endDate();
map.layerInfo.validTimes.timesInRange('radar', from, to, 300).then((times) => {
// do something with times...
});
If you want to ensure only valid times are using during a layer's animation, you can also force that layer's datasource animation to use a static set of times you provide:
const source = app.map.getSourceForLayer('radar');
if (source && source.animation) {
const from = map.timeline.startDate();
const to = map.timeline.endDate();
// set the layer's animation intervals to exact valid times instead of auto-calculating
app.map.layerInfo.validTimes.timesInRange('radar', from, to, 300).then((times) => {
const intervals = 10;
const every = Math.ceil(times.length / intervals);
source.animation.setTimes(times, every);
});
// get the actual time for each interval during animation playback, such as displaying
// in the interface alongside the layer control
source.animation.on('advance:image', (e) => {
const { time } = e.data || {};
console.log(new Date(time));
});
}
Note, however, you will need to use the above code each time you need to update the layer's animation data, such as when map data refreshes or the global timeline range changes.
If you want to revert a layer's animation to use the default method of auto-calculating interval times, just set the animation times to a null
value:
const source = app.map.getSourceForLayer('radar');
if (source && source.animation) {
source.animation.setTimes(null);
}
Adding Vector Layers
Vector layers are added to the map as markers and/or polylines and polygons. By default, a vector layer will request data from its configured source based on the global timeline's date range. However, you can configure different behavior using the various layer data
options described below.
Vector Layer Options
Option | Type | Description | |
---|---|---|---|
type | string | Type of content source to use, if supported by the layer. Supports tile , point or shape . | |
style | VectorStyle | Style configuration to use when rendering the layer on the map. Refer to the styling guide for more details and configuration options. | |
data | object | Provides the data-related configuration options for the layer. | |
data.request | object | Request options for vector layers. | |
data.request.endpoint | string | API endpoint to use for the request. | |
data.request.action | string | API action to use for the request. Default value is within for point content sources and search for shape content sources. | |
data.request.parameters | object | Defines the request parameters to use when requesting data for the layer. | |
data.url | string or Function | The URL string to request data from for the data source. Value may be a function that receives information about the map, such as current coordinate bounds, to format a URL string before returning. | |
data.items | array | An array of records to display on the map. If this value is provided, then data will not be requested from a remote source. | |
data.properties | object | Data key-path configuration for property values. | |
data.properties.id | string | Property key path to use for each object's identifier. | |
data.properties.root | string | Key path to the root of the node containing the array of data elements (e.g. features ). If not provided, then the root node is assumed to contain the array of data elements. | |
data.properties.category | string | Property key path to use for an object's category or grouping, if any. | |
data.properties.timestamp | string | Defines the key path of the property to use for a model object's time value. | |
data.properties.value | string | Defines the key path of the property to use for a model object's displayed value. | |
data.properties.points | string or string[] | Property key path that contains the point/coordinate data for the layer. This value can also be an array of key paths, in which case the points will be combined when rendering the data source's points on the map. | |
data.properties.path | string | Property key path to use for the object's coordinate path that defines the shape. If the value of this property is an array, then multiple paths will be rendered on the map for the model. | |
data.formatter | Function | An optional formatter function that can be used to format layer data before being processed for rendering on the map. This function receives the entire dataset loaded for the layer and should return the formatted data to use when rendering map elements. | |
data.coordinate | Function | A function that returns the geographical coordinate based on the model object. | |
data.geometry | Function | A function that returns the shape's GeoJSON geometry based on the model object. | |
data.reversedCoords | boolean | A Boolean indicating whether the data's coordinate arrays are reversed from the GeoJSON standard (e.g. [lat, lon] instead of the default of [lon, lat] ). | |
animation | AnimationOptions | Animation options for the layer. Not all options will be used for a specific layer since its animation is managed by the global map timeline. | |
refresh | number | Data auto-update interval, in seconds. Default value is 0 , which disables auto-updating. |
Changing the Request Parameters
Since point, shape and text data sources request their data from the Xweather Weather API instead of rendering static raster imagery, it uses an ApiRequest
object to setup and perform the request internally.
Each layer will setup the default request parameters to use for its request, but you can also override these default values when you add these layers to the map. Just provide your custom API request parameters as an object assigned to the request.parameters
property of your layer options object:
map.addLayer('stormcells', {
data: {
request: {
parameters: {
filter: 'tornado'
}
}
}
});
Note You will not be able to override certain API request parameters for point, shape and text data sources since they are controlled by the visible map bounds and timeline start and end range. These parameters include: from
, to
, p
, and limit
.
Adding Text Layers
For text layers, such as observations
, you also need to provide the property key paths that correspond to the time and the value you want to display from the data returned by an API request. You specify these key paths using the time
and value
properties within the request.property
object of your layer options object when adding a layer.
For instance, the following will display the current temperature as text using the value key path of periods.ob.tempF
whose valid time is defined by the property at key path periods.ob.timestamp
for each object in the API response:
map.addLayer('observations', {
data: {
properties: {
timestamp: 'periods.ob.timestamp',
value: 'periods.ob.tempF'
}
}
});
The time
key path should always be the same value regardless of the value for value
. To change the value that gets rendered to the map, just use a different key path for value
:
map.addLayer('observations', {
data: {
properties: {
timestamp: 'periods.ob.timestamp',
value: 'periods.ob.windSpeedMPH'
}
}
});
The value
property also accepts a callback function that can be used to format and return the value that gets rendered on the map instead of using a key path. This callback will receive the model's data as an argument, allowing you to access the complete model data when formatting the label's value for the map.
The following configuration would render a stormreports
layer for only snow-related reports as text instead of points and outputs the snow total value to the map:
map.addLayer('stormreports', {
type: 'text',
data: {
request: {
parameters: {
filter: 'snow'
}
},
properties: {
timestamp: 'report.timestamp',
value: (data) => {
const { report: { detail: { snowIN: val }}} = data;
if (val) {
return val.toFixed(1);
}
return null;
}
}
}
});
Removing Layers
Removing layers from the map is similar to adding them. To remove a layer from your map, just use removeLayer()
:
map.removeLayer('radar');
You can also remove multiple layers at once using removeLayers()
:
map.removeLayers(['satellite','stormreports']);