ArcGIS Blog

3D Visualization & Analytics

ArcGIS Maps SDK for JavaScript

Clicking in a 3D web scene can do that?

By Raluca Nicola

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 or exclude parameters to the hitTest() 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:

The purple trees are the trees planted on streets. They currently exist in Manhattan. The green ones are planted by the user.

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.

A line of sight analysis shows the intersections between two points: an observer and a target. In this case the observer is the camera and the target is set by the user anywhere in the scene.

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:

More trees are being planted on the buildings closer to the camera because of the 500m distance rule.

To get a visual representation of how this works, check out our SceneView hitTest documentation sample:

ArcGIS API for JavaScript sample - SceneView hitTest

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.

The example live: https://codepen.io/ralucanicola/pen/OJJxvRe?&editable=true&editors=100

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

Share this article