I'm trying to dynamically add graphics to a scene and have tried several things.
I have a scene in an app that shows the 3d buildings in the city. When the user loads the app, I want the buildings to be colored based on the attributes of a feature layer. The feature layer shows the status and type of group homes as a parcel. I want to loop over all the group homes and find the associated 3d building and change it's color and I'm running into trouble. I tried running a spatial query on the sceneLayer using the geometry and discovered this isn't possible. I then went to the 3d sceneLayer's associatedLayer and was still unable to get the .then functions to fire.
function colorHomes(){
var bldg_lyr;
scene.layers.forEach(function(nextLayerView){
if (nextLayerView.url.indexOf("Building") > 0){
bldg_lyr = nextLayerView.associatedLayer;
}
});
//get all alf features
var alfQueryTask = new QueryTask({ url: "..../rest/services/NS/ActiveALFsTest/MapServer/0" });
var alfQuery = new Query({
where: "1=1",
outFields: ["NameFacility", "ADDRESS", "TypeFacility"],
returnGeometry: true,
outSpatialReference: view.spatialReference
});
alfQueryTask.execute(alfQuery).then(function(alfResults){
//loop over each feature
alfResults.features.forEach(function(alfFeature){
var bldgQuery = new Query({
geometry: alfFeature.geometry,
//objectIds: [13006],
outFields: ["OBJECTID"]
});
bldg_lyr.queryFeatures(bldgQuery).then(function (bldgResults){
if (bldgResults.length > 0){
console.log("++++++++++++++++++SUCCESS++++++++++++++++++");
bldgResults.forEach(function(bldg){
console.log(bldg.attributes.OBJECTID);
});
}
},
function (bldgResults){
console.log("Ouch! That's gotta hurt.");
});
});
});
}
Solved! Go to Solution.
Does your scene layer have an associated feature layer? You can check that with the getFieldUsageInfo method. If `supportsLayerQuery` is `true`, then you can do spatial queries and your query above only needs the spatial relationship and the spatial reference. Here is a working snippet that is setting a polygon geometry on a query and when the query executes it returns all the ID's of the buildings that intersect that polygon: SceneLayer polygon intersection.
The important part is:
var query = sceneLayer.createQuery();
query.geometry = polygon;
query.spatialRelationship = 'intersects';
query.inSpatialReference = SpatialReference.WebMercator;
query.outSpatialReference = SpatialReference.WebMercator;
sceneLayer.queryObjectIds(query)
.then(function(result){
console.log(result);
})
.catch(function(err){
console.log(err);
});
Does your scene layer have an associated feature layer? You can check that with the getFieldUsageInfo method. If `supportsLayerQuery` is `true`, then you can do spatial queries and your query above only needs the spatial relationship and the spatial reference. Here is a working snippet that is setting a polygon geometry on a query and when the query executes it returns all the ID's of the buildings that intersect that polygon: SceneLayer polygon intersection.
The important part is:
var query = sceneLayer.createQuery();
query.geometry = polygon;
query.spatialRelationship = 'intersects';
query.inSpatialReference = SpatialReference.WebMercator;
query.outSpatialReference = SpatialReference.WebMercator;
sceneLayer.queryObjectIds(query)
.then(function(result){
console.log(result);
})
.catch(function(err){
console.log(err);
});
Thanks. I knew it would work because I published the buildings with pro as a webscene and I also replaced the webmap in one of the samples with mine and was able to click on a building and see the info. I changed the way the .then was called to the syntax you had and changed the bldgResults.forEach to bldgResults.features.forEach. I can get the building attributes now. Only task left is to change the color/symbol of the building in the scene.
function colorHomes(){
var bldg_lyr;
scene.layers.forEach(function(nextLayerView){
if (nextLayerView.url.indexOf("Building") > 0){
bldg_lyr = nextLayerView; //.associatedLayer;
}
});
view.whenLayerView(bldg_lyr).then(function(bldg_lyr_view){
var alfQueryTask = new QueryTask({ url: "https://.../FeatureServer/0" });
var alfQuery = new Query({
where: "1=1",
outFields: ["NameFacility", "ADDRESS", "TypeFacility"],
returnGeometry: true,
outSpatialReference: view.spatialReference
});
alfQueryTask.execute(alfQuery).then(function(alfResults){
//loop over each feature
alfResults.features.forEach(function(alfFeature){
var bldgQuery = new Query({
geometry: alfFeature.geometry,
spatialRelationship: "intersects",
inSpatialReference: SpatialReference.WebMercator,
outSpatialReference: SpatialReference.WebMercator,
outFields: ["OBJECTID","BLDGHEIGHT"]
});
bldg_lyr.queryFeatures(bldgQuery)
.then(function (bldgResults){
if (bldgResults.features.length > 0){
bldgResults.features.forEach(function(bldg){
//console.log(bldg.attributes.OBJECTID);
});
}else{
//console.log("no feature found");
}
})
.catch(function(err){
conlole.log(err);
});
});
});
});
}
Did I understand correctly that you want to visualize the buildings based on the status or type of the parcel that is used for the query?
The most performant way to achieve this would be to do a preprocessing in ArcGIS Pro: spatial join of buildings with polygons and add the corresponding attributes to the buildings.
Now if your building data is "light" and you need to do this on the client side, a unique value renderer based on object ids might work too. I made a new example where I change the color of the buildings returned from the query based on the objectid. This is not optimal though, if there are thousands of unique values at some point the browser might run out of memory. SceneLayer polygon intersection with renderer
The app will take an address entered by a user and search within a 1,000 ft buffer for any existing facilities. If there are, these need to be presented to the user.
I would like to color the 150 or so existing facilities on 1 of 3 classes so users can see a map of the existing facilities. Then I want to color in the conflicts when they are identified. This would be the building that was requested, 1 or 2 facilities and the buffer graphic.
I don't really want assign attributes to the buildings because it has to be dynamic as the status and number of these houses change. I have to integrate into an existing C#.NET web app that is already using a custom dll of rest api calls. The dll was written to simplify the non-gis programmers job of integrating into the GIS. All of this is done mapless in the .NET app through rest. But they want to see/show the map.
Thank you very much for your help, I'm going to try this right now.