SceneLayerView.queryFeatures() returns only objectID, no other fields, no geometry?

2919
13
Jump to solution
10-09-2017 08:26 PM
nie
by
New Contributor II

FeatureLayerView.queryFeatures() returns all the field values and the geometry, but using SceneLayerView.queryFeatures() I can get only the objectid.

0 Kudos
1 Solution

Accepted Solutions
RalucaNicola1
Esri Contributor

Can you post some code snippet on how you do the query? Posting the service url would also be really helpful.

But some general tips:

- make sure you set `outFields: ["*"]` on the query that you pass into the queryFeatures method. 

- you can't get the geometry of a SceneLayer feature from the queryFeatures method, but you can get the 3D extent using queryExtent.

Otherwise check this sample on how to use SceneLayerView queries: ArcGIS API for JavaScript Sandbox 

View solution in original post

13 Replies
ThomasSolow
Occasional Contributor III

Can you show an example sceneLayer to test this?

It may be that, in general, sceneLayers features don't send their attributes to the client.

0 Kudos
nie
by
New Contributor II

I mean the SceneLayerView, not the SceneLayer, so the queryFeatures function only do query at the client side, there's no such a process about sending something, am I right? 

0 Kudos
RalucaNicola1
Esri Contributor

Can you post some code snippet on how you do the query? Posting the service url would also be really helpful.

But some general tips:

- make sure you set `outFields: ["*"]` on the query that you pass into the queryFeatures method. 

- you can't get the geometry of a SceneLayer feature from the queryFeatures method, but you can get the 3D extent using queryExtent.

Otherwise check this sample on how to use SceneLayerView queries: ArcGIS API for JavaScript Sandbox 

nie
by
New Contributor II

1.

the code snippet is really simple, I just find the scenelayerview instance from sceneview's allLayerViews property and do the query:

lyrVw = this.view.allLayerViews.find(l=>l.layer.title ==='LayerTitle')
let featureSet = await lyrVw.queryFeatures()‍‍‍‍

featureSet.features has all the loaded features of this scenelayer currently in the scene, but there geometry property is null.

2.

As soon as I got your reply, I changed the code and execute the query like this:

let featureSet = await lyrVw.queryFeatures({outFields: ['*']})

this time the featureSet.features have all the field values! I'm confused here because the same code(leaving the queryFeatures's parameter blank) returns the expected result, the only difference is changing the LayerTitle to let the lyrVw equals an instance of FeatureLayerView. Is it a better practice to always set the Query params?

3.

You said I can't get the SceneLayer feature's geometry, is this going to be supported in future?

For now, I want to get the particular feature from query and open the popup, so I did wanted to pass the geometry as parameter to the Popup's open function to set the popup windows's location. I will try calculating the center point from the extent, it should work the same.

0 Kudos
ThomasSolow
Occasional Contributor III

When you set outFields to ["*"] I don't think the query is going to be client-side anymore.  This may be okay for your use case.  You can check in dev tools, but I'd bet that you're firing off a bunch of requests when you do this.

Scene Layers only fetch the object id field by default.  They also fetch any field that is needed in the client for a renderer.  There's no easy way to specify which fields should be fetched, although there are probably a number of options for forcing the layer to fetch the attributes you want.

This means that, normally, SceneLayerView.queryFeatures() will only return the object id plus whichever fields the layer decided are required by the renderer.  The client-side query can't return any fields that weren't fetched to draw the layer to begin with.  When you pass in outFields, the layer seems to query the Scene Service rather than doing a client-side query.  This is a little confusing: my assumption was that LayerView.queryFeatures() is always client-side.  

I don't know a lot about Scene Layer geometries, but I don't think they're like Esri geometries.  Scene Services return some binary format that can represent vertices, meshes, pyramids, etc.  I'm not sure how to get access to that data or what coordinate system it will be in.

nie
by
New Contributor II

I've just debugged the code, yes, you're right. When I set outFields to ["*"] several new request appear in the Network panel of Chrome Dev Tools. I didn't noticed that and thought LayerView.queryFeatures() is always client-side.

You mentioned that there're probably some options for forcing the attributes fetch, is there some similar api to force the SceneLayer to fetch attributes from its linked FeatureLayer/FeatureService?

I need to set the SceneLayer's renderer to reflect its attribute changes, but attributes stored in SceneLayer/SceneService and been used to render never change after the service has been published. I have asked about this (here), for now I have to watch the SceneLayerView's updating and request attributes from the connected FeatureService manually.

0 Kudos
ThomasSolow
Occasional Contributor III
 for now I have to watch the SceneLayerView's updating and request attributes from the connected FeatureService manually.

I can't think of a better way to do this off the top of my head.

When you said:

I need to set the SceneLayer's renderer to reflect its attribute changes

What do you mean by attribute changes? 

0 Kudos
nie
by
New Contributor II

For example, a scene layer named "buildings" has a field storing the usage info, then those building features are rendered with different color according to the usage field. What was expected is, change the usage field value and the renderer style will automatically refresh to "reflect" the field value change.

Now I can applyEdits to the linked feature layer, but the scene layer's renderer style won't update. That's why I need to manually request attributes from the linked feature layer, and wonder if there're some options to force the API to do this.

0 Kudos
ThomasSolow
Occasional Contributor III

Thanks, I understand now.

I don't think there's an easy way to get the API to do this.  The way I'd approach this is something like:

-Add scene layer to map.

-Create companion feature layer but don't add it (is this done automatically?).

-Whenever the view is stationary query the featureLayer and keep the resulting features in an array, overwriting the array whenever the extent changes.

-Modify the renderer on the sceneLayer to use the features from the featurelayer instead of the features in the scenelayer, if they exist

Something like this:

const view;

// companion feature layer
const featureLayer;
// array to hold features
const featuresArray = [];

// sceneLayer
const sceneLayer;

// watch for when view stops moving
view.watch('stationary', isStationary => {
  if (isStationary){
    getFeatures(view.extent);
  }
});

// update features in view
function getFeatures(extent){
  const q = featureLayer.createQuery();
  q.geometry = extent;
  q.outFields = ['*'];
  featureLayer.queryFeatures(q).then(featureSet => featuresArray = featureSet.features);
}

// override the getSymbol method on the renderer
sceneLayer.renderer.getSymbol = function(g){
  // objectId of the feature being rendered
  let oid = g.attributes[sceneLayer.objectIdField];
  // search featureLayer for the same feature
  let feature = featuresArray.find(f => f.attributes[sceneLayer.objectIdField] === oid);
  if (feature){
    // if we found a feature, use that feature to generate a symbol
    return sceneLayer.renderer.__proto__.getSymbol.call(sceneLayer.renderer, feature);
  } else {
    // if we didn't, use the sceneLayer's version to generate a symbol
    return sceneLayer.renderer.__proto__.getSymbol.call(sceneLayer.renderer, g);
  }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I don't have access to a scenelayer that has a companion feature layer so I can't test this, but in general I think it should work.  It may not be an improvement over what you have currently though.

0 Kudos