I'm not sure if this is the most prudent way to go about this, so feel free to critique my code structure as well.
Okay, long story short, I have about a feature service that has tens of thousands of features. I only want the features contained within the current camera extent to be displayed, so:
So anytime the camera changes, I tell the wrapper layer to execute a query on its internal layer based on the current extent of the view. So far, so good. This all works in the code.
Here's the problem: The features aren't drawing. I've printed the JSON of the wrapper layer to the console, so I know that the source of the wrapper layer has been set to the result of the query correctly, but...
The features don't have symbols. 'symbol: null'
The internal layer has a Unique Value renderer that was built from the REST service, and when I create the wrapper layer I pass this render to the wrapper layers. I know that this renderer is present in the wrapper layer at the time of the query.
I can't figure out why the wrapper layer is not using it's renderer to generate symbols for the features, so I'm wondering if there is a function call that I need to make in order to make the layer redraw itself and use its renderer to generate the proper symbols.
Any thoughts or wisdom is appreciated.
Tristan,
Can you provide a sample of this?
Of course! I've attached the full source code to the initial post for reference, but here are the relevant lines:
- This is the function with which I create the wrapper layers, using the inner layers. In this function the inner layers have already been loaded.
// Returns a layer promise which has all of the important characteristics of the passed layer, and which carries a reference to the original layer in the property 'subordinate'
function createWrapperLayer( featLayer ){
console.log( 'Creating wrapper layer for ', featLayer.title );
// Grab the features in the featLayer which are visible to the initial extent of the view. Assign those as the source.
// Wait for the results of the query to return, then pass it into the next function to be used as the resultant layer's source.
// Here we read out all of the important information from the original layer
var subTitle = featLayer.title;
var subID = featLayer.id;
var subFields = featLayer.fields;
var subObjID = featLayer.objectIdField;
var subSpRef = featLayer.spatialReference;
var subGeoType = featLayer.geometryType;
var subRender = featLayer.renderer;
// We have to wait for the query to finish execution to create the wrapper layer
visibleFeats.then(
function(visibleFeats) {
// Now we create the actual layer
visiLayer = new FeatureLayer({
title: subTitle,
id: subID,
objectIdField: subObjID,
source: findFeaturesInCameraExtent( featLayer ), // In order to execute this function, featLayers must already be loaded.
fields: subFields,
visible: true,
spatialReference: subSpRef,
geometryType: subGeoType,
renderer: subRender
});
// Here we add a prototype attribute 'subordinate' to the visiLayer so that we can access the feature layer again later
visiLayer.subordinate = featLayer;
// And return it
visiLayer.then(function( vLayer ) {
console.log( vLayer );
});
visiLayer.load();
map.add( visiLayer );
});
}
- This is the function which initiates the querying of the inner layers, and sets the source of the wrapper layer to the query's result(s)
// This is the function that will be called each time the camera changes.
// It
function updateVisibleFeatures() {
map.layers.forEach(function(layer) {
if ( layer.visible == true && layer.id != layerBounds.id ) { // Cycle through every layer except for the bounds// layer.subordinate is a reference to the internal layer that the wrapper layer is wrapped around
// it is the layer that is built from the REST service, and contains all available features.
visibleFeats = findFeaturesInCameraExtent( layer.subordinate );
visibleFeats.then(
function( visibleFeats ) {
layer.source = visibleFeats.features;
console.log( layer );
},// Function that is called in case the promise fails
function( reason ) {
console.log( 'Updating visible features failed: ', reason );
});
}
});
}
And this is the subroutine that actually executes the query
// Function which, given a layer, will return the features of that layer that are contained within the camera extent.
// Function returns a promise, and the resultant featureSet should be accessed with the '.then()' function
function findFeaturesInCameraExtent( layer ) {
var query = layer.createQuery(); // Create a blank query
query.geometry = view.extent
query.spatialRelationship = "contains";
var results = layer.queryFeatures( query ) // Apply the spatial query to the layer, return a promise of the result
// Returns a promise which, once resolved, will contain all of the features returned by the query
return results;
}