This blog post shows you how to make use of SceneView.hitTest() when you need to retrieve the objects that the user clicked on in a web scene. Starting with ArcGIS API for JavaScript version 4.12 you can:
- select which layers should be intersected by passing
include
orexclude
parameters to thehitTest()
method - retrieve all 3D objects that are intersected along with the distance to each object in
HitTestResult.results
- get the intersection point with the ground along with the distance to that point in
HitTestResult.ground
In this blog post we’ll look into using this new functionality and to make it more fun, we’ll use it to build a playful app that plants trees on buildings, just by moving the cursor over them:
Afterwards we’ll also look at the documentation sample and tweak it to create a small tool that visualizes a line of sight from the camera viewpoint.
So let’s start with the app that helps you plant trees in Manhattan: when a user clicks or moves the mouse over a building, then trees are placed randomly over the 2D extent of the building. The extent is retrieved by querying the SceneLayerView and the coordinates are calculated with a random function inside of that extent. Sometimes there might be trees set on the ground because the extent is different from the footprint. Using relative-to-scene
elevation mode, the trees are aligned to the building height. We are only interested in capturing the intersected buildings, so we’ll use the include
option of the hitTest method, which will disregard all other layers:
view.hitTest(event, { include: [buildingSceneLayer] })
.then(function (response) {
// response.results contains all the intersected graphics
});
Another rule of the app is that it plants more trees on buildings that are closer to the camera. How do we do that? We check the distance in the response of the hitTest method. If the camera is further away than 500m from the building, only 5 trees are planted. Otherwise it will plant 20 trees.
view.hitTest(event, { include: [buildingSceneLayer] })
.then(function (response) {
response.results.forEach(function(result) {
const objectid = result.graphic.attributes.OBJECTID;
const noTrees = result.distance > 500 ? 5 : 20;
sceneLayerView.queryExtent({ objectIds: [objectid] })
.then(function (result) {
if (result && result.extent) {
const trees = getRandomTrees(result.extent, noTrees);
treesLayer.addMany(trees);
}
});
});
});
As I mentioned in the beginning, the results array of the HitTestResult contains all the intersected buildings. So to plant more trees with a single click/mouse move I can just tilt the view and more buildings will be intersected:
To get a visual representation of how this works, check out our SceneView hitTest documentation sample:
This sample also shows the intersection with the ground, which can also be retrieved from the HitTestResult along with the distance to the ground. And if we tweak the colors a little we can almost create a small line of sight tool from the camera direction to the point where we clicked. Red represents the part that is not visible and blue is what the observer can see.
That’s about it! We’re always interested in feedback so let us know what you think about this functionality and how it helps you in your workflow.
Happy planting!
Raluca
Commenting is not enabled for this article.