Introduction

How a FeatureLayer queries the model for data has an impact on the user experience.

  • If the model contains a lot of data, you may not want the FeatureLayer to load it all with a single query.

  • In addition, features in a model may only be relevant at specific scales.

    For example, you may not be interested in retrieving small buildings from a model when the map is zoomed out too far to show those buildings.

To handle such scenarios, each FeatureLayer can be configured with a LoadingStrategy. Such a loading strategy defines in what manner the layer should retrieve data from the model.

Spatial filtering using a LoadingStrategy

You activate spatial filtering by switching from the LoadEverything strategy to the LoadSpatially strategy:

  • LoadEverything: the layer queries the model once to load all data.

  • LoadSpatially: the layer queries the model only for data inside the current view (spatial filtering). If the map extent changes, the layer will submit a new query to the model for features inside the new extent.

    To use the LoadSpatially data loading strategy, the model must support bounding box queries with the spatialQuery method (see Add support for spatial queries to a Store for more info). A WFSFeatureStore is an example of a Store that supports this capability.

Scale-based filtering using a QueryProvider

By installing a QueryProvider on the loading strategy you can also control which features are queried at each scale level.

A QueryProvider allows you to send a data server query that determines what data must be loaded. You can change the query based on the current scale of the view: you define the scale breaks where you want the query to change, and define the query associated with each scale break.

The QueryProvider defines what Feature instances must be shown at different map scales. For example when viewing road data, you can install a QueryProvider which only queries the highways when the map is zoomed out, and does not load the smaller roads until zooming in.

In a 3D scene, there is no universal scale for the whole view. Areas towards the horizon have a different scale compared to areas close to the camera.

To deal with this, the LoadSpatially strategy will divide the area of the map that needs to be painted in different zones, each with their own scale level. For each of these zones, a request will be made with the bounds and scale of the corresponding zone.

This multi-scale approach in 3D scenes reduces the memory usage as well as the visual clutter.

A QueryProvider example

The QueryProvider in the example below limits the amount of city data downloaded from the server by setting 2 scale breaks, resulting in 3 detail levels:

  1. If you have zoomed out of the map completely, no cities are loaded from the server.

  2. If you zoom in beyond the first scale break, cities with over half a million inhabitants are loaded from the server.

  3. If you zoom in beyond the second scale break, all cities are loaded from the server, regardless of their total population.

Program: Using a query provider to assign different classes of features to different scales
//Define the different scale ranges
const scaleRanges = [
  1.0 / 20000000,
  1.0 / 500000
];

//Define the queries corresponding to those scale ranges
const scaleQueries = [
  QueryProvider.QUERY_NONE,
  {
    //Use the functions from the FilterFactory module to create a filter
    filter: gt(property("TOT_POP"), literal(500000))
  },
  {}
];

//Create the provider, and overwrite the methods to return the correct scales and queries
class CitiesQueryProvider extends QueryProvider{

  getQueryForLevel(level: number): object | null {
    return scaleQueries[level];
  }

  getQueryLevelScales = function(layer?: FeatureLayer, map?: Map): number[] {
    return scaleRanges;
  }
}
const citiesQueryProvider = new CitiesQueryProvider();

Provided that spatial queries are supported by the Store, it is good practice to use a QueryProvider in combination with a LoadSpatially loading strategy, because it prevents the requests of data that covers areas outside the view.

Next to the LoadingStrategy and QueryProvider, the visibility of a Layer also determines whether or not data is loaded. When an invisible layer is added to the map, the layer will not query the model. It will query the model for data only when the visibility of the Layer is activated again.