Introduction

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

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

  • Features in a model may also only be relevant at specific scales.

    For example, you may not want to retrieve small buildings from a model when users zoomed out of the map too far to see those buildings.

To handle such scenarios, you can configure each FeatureLayer with a LoadingStrategy. Such a loading strategy defines in what manner the layer retrieves 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 submits 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.

You use a QueryProvider to send a data server query that determines what data to load. 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. Then, you define the query associated with each scale break.

The QueryProvider defines what Feature instances to show at different map scales. For example, you can install a QueryProvider for road data. It queries the highways when users zoomed out on the map, and does not load the smaller roads until map users zoom 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 divides the displayed area of the map into several zones, each with its own scale level. A request is made for each of the zones, with the bounds and scale of the zone.

This multi-scale approach in 3D scenes reduces the memory usage and 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, the application does not load cities from the server.

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

  3. If you zoom in beyond the second scale break, the application loads all cities 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();

If the Store supports spatial queries, it is good practice to use a QueryProvider in combination with a LoadSpatially loading strategy. It prevents requests of data that covers areas outside the view.

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