Watching a graphics Layer for changes

2576
3
Jump to solution
05-27-2021 10:19 AM
MikeDolbow
New Contributor III

Anyone successfully set up a watch event (using watchUtils or some other kind of listener) on changes in the Graphics Layer? I got what I wanted working by watching the mapView for "updating" (code below) but that seems overkill because it fires with every map event, even ones that have nothing to do with graphics. I tried the following but it doesn't work:

watchUtils.on(graphicsLayer,"graphics","change",function(){
...
});

...and watchUtils.when(graphicsLayer.... only fired once, when the layer was added.

Here's what worked, just curious if it can be optimized/improved:

   //Watch the app.MapView for the updating property to assess graphics situation.
   watchUtils.watch(app.mapView,"updating",function(){
    //console.log("map updating.");
        if (this.graphics.items.length > 0) {
       ...code block to execute
        }
   });

 

0 Kudos
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor

When you say the watchUtil didn't work, did nothing happen? When I used that in one of the samples, it fired once after all the graphics were added

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>Add Graphics to a SceneView | Sample | ArcGIS API for JavaScript 4.19</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.19/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.19/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

    <script>
      require(["esri/Map", "esri/views/SceneView", "esri/layers/GraphicsLayer", "esri/Graphic", "esri/core/watchUtils"], (
        Map,
        SceneView,
        GraphicsLayer,
        Graphic,
        watchUtils
      ) => {
        const map = new Map({
          basemap: "hybrid"
        });

        const view = new SceneView({
          container: "viewDiv",
          map: map,

          camera: {
            // autocasts as new Camera()
            position: {
              // autocasts as new Point()
              x: -0.17746710975334712,
              y: 51.44543992422466,
              z: 1266.7049653716385
            },
            heading: 0.34445102566290225,
            tilt: 82.95536300536367
          }
        });

        /*********************
         * Add graphics layer
         *********************/

        const graphicsLayer = new GraphicsLayer();
        map.add(graphicsLayer);
        
        watchUtils.on(graphicsLayer, "graphics", "change", () => {console.log('Graphics added!');});

        /*************************
         * Add a 3D point graphic
         *************************/

        // London
        const point = {
          type: "point", // autocasts as new Point()
          x: -0.178,
          y: 51.48791,
          z: 1010
        };

        const markerSymbol = {
          type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
          color: [226, 119, 40],
          outline: {
            // autocasts as new SimpleLineSymbol()
            color: [255, 255, 255],
            width: 2
          }
        };

        const pointGraphic = new Graphic({
          geometry: point,
          symbol: markerSymbol
        });
console.log('Add point');
        graphicsLayer.add(pointGraphic);

        /****************************
         * Add a 3D polyline graphic
         ****************************/

        const polyline = {
          type: "polyline", // autocasts as new Polyline()
          paths: [[-0.178, 51.48791, 0], [-0.178, 51.48791, 1000]]
        };

        const lineSymbol = {
          type: "simple-line", // autocasts as SimpleLineSymbol()
          color: [226, 119, 40],
          width: 4
        };

        const polylineGraphic = new Graphic({
          geometry: polyline,
          symbol: lineSymbol
        });
console.log('Add polyline');
        graphicsLayer.add(polylineGraphic);

        /***************************
         * Add a 3D polygon graphic
         ***************************/

        const polygon = {
          type: "polygon", // autocasts as new Polygon()
          rings: [
            [-0.184, 51.48391, 400],
            [-0.184, 51.49091, 500],
            [-0.172, 51.49091, 500],
            [-0.172, 51.48391, 400],
            [-0.184, 51.48391, 400]
          ]
        };

        const fillSymbol = {
          type: "simple-fill", // autocasts as new SimpleFillSymbol()
          color: [227, 139, 79, 0.8],
          outline: {
            // autocasts as new SimpleLineSymbol()
            color: [255, 255, 255],
            width: 2
          }
        };

        const polygonGraphic = new Graphic({
          geometry: polygon,
          symbol: fillSymbol
        });
console.log('Add polygon');
        graphicsLayer.add(polygonGraphic);
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>

 

View solution in original post

0 Kudos
3 Replies
KenBuja
MVP Esteemed Contributor

When you say the watchUtil didn't work, did nothing happen? When I used that in one of the samples, it fired once after all the graphics were added

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>Add Graphics to a SceneView | Sample | ArcGIS API for JavaScript 4.19</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.19/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.19/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

    <script>
      require(["esri/Map", "esri/views/SceneView", "esri/layers/GraphicsLayer", "esri/Graphic", "esri/core/watchUtils"], (
        Map,
        SceneView,
        GraphicsLayer,
        Graphic,
        watchUtils
      ) => {
        const map = new Map({
          basemap: "hybrid"
        });

        const view = new SceneView({
          container: "viewDiv",
          map: map,

          camera: {
            // autocasts as new Camera()
            position: {
              // autocasts as new Point()
              x: -0.17746710975334712,
              y: 51.44543992422466,
              z: 1266.7049653716385
            },
            heading: 0.34445102566290225,
            tilt: 82.95536300536367
          }
        });

        /*********************
         * Add graphics layer
         *********************/

        const graphicsLayer = new GraphicsLayer();
        map.add(graphicsLayer);
        
        watchUtils.on(graphicsLayer, "graphics", "change", () => {console.log('Graphics added!');});

        /*************************
         * Add a 3D point graphic
         *************************/

        // London
        const point = {
          type: "point", // autocasts as new Point()
          x: -0.178,
          y: 51.48791,
          z: 1010
        };

        const markerSymbol = {
          type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
          color: [226, 119, 40],
          outline: {
            // autocasts as new SimpleLineSymbol()
            color: [255, 255, 255],
            width: 2
          }
        };

        const pointGraphic = new Graphic({
          geometry: point,
          symbol: markerSymbol
        });
console.log('Add point');
        graphicsLayer.add(pointGraphic);

        /****************************
         * Add a 3D polyline graphic
         ****************************/

        const polyline = {
          type: "polyline", // autocasts as new Polyline()
          paths: [[-0.178, 51.48791, 0], [-0.178, 51.48791, 1000]]
        };

        const lineSymbol = {
          type: "simple-line", // autocasts as SimpleLineSymbol()
          color: [226, 119, 40],
          width: 4
        };

        const polylineGraphic = new Graphic({
          geometry: polyline,
          symbol: lineSymbol
        });
console.log('Add polyline');
        graphicsLayer.add(polylineGraphic);

        /***************************
         * Add a 3D polygon graphic
         ***************************/

        const polygon = {
          type: "polygon", // autocasts as new Polygon()
          rings: [
            [-0.184, 51.48391, 400],
            [-0.184, 51.49091, 500],
            [-0.172, 51.49091, 500],
            [-0.172, 51.48391, 400],
            [-0.184, 51.48391, 400]
          ]
        };

        const fillSymbol = {
          type: "simple-fill", // autocasts as new SimpleFillSymbol()
          color: [227, 139, 79, 0.8],
          outline: {
            // autocasts as new SimpleLineSymbol()
            color: [255, 255, 255],
            width: 2
          }
        };

        const polygonGraphic = new Graphic({
          geometry: polygon,
          symbol: fillSymbol
        });
console.log('Add polygon');
        graphicsLayer.add(polygonGraphic);
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>

 

0 Kudos
MikeDolbow
New Contributor III

Dang. I don't remember what happened when I tried it in my code, which is a spaghetti mess of course. But I just tried it in the SketchWidget sample (clicking to create graphics is more like my use case) and it worked fine.

watchUtils.on(graphicsLayer,"graphics","change",function(){
console.log("Graphics Changed!");
});

At least this confirms for me that I was on the right track with that methodology...now I just have to debug why it failed with my code at the time. Thanks!

0 Kudos
MikeDolbow
New Contributor III

Update for anyone struggling similarly to me, I got that method working:

watchUtils.on(graphicsLayer, "graphics", "change", function (evt) {

The reason it wasn't working was that I had graphics being added/created via app.MapView.graphics instead of the graphicsLayer. They are two separate containers! So the watch was working, but not detecting anything because I was adding graphics to the "wrong" place. Making sure each graphic creation took place within graphicsLayer did the trick.

Of course, now I'm struggling to make sure I can detect creation of graphics from several methods. Search result graphics appear to be created in the app.MapView by default...I can override that, but then I need to customize each type. And it appears that featureLayer sources create additional graphics (probably in the app.MapView!) that I can't detect/clear!

 

0 Kudos