Fade back map outside of polygon

532
5
Jump to solution
03-04-2020 11:50 PM
rsharma
Occasional Contributor III

I have a simple map with polygons on graphics layer, i need to  fade map outside that polygon and show polygon as a hole in the map. I get some relative answer in older version, but it is not helpful.

I want to show like this image

My code is below

<script>
       require(["esri/views/MapView",
      "esri/WebMap",
      "esri/Graphic",
      "esri/layers/GraphicsLayer",
      "esri/geometry/Polygon",
      "esri/geometry/SpatialReference"
    ], function (MapView, WebMap, Graphic, GraphicsLayer, Polygon, SpatialReference) {

         let validSymbol,
          newDevelopmentGraphic;

        /************************************************************
         * Creates a new WebMap instance. A WebMap must reference
         * a PortalItem ID that represents a WebMap saved to
         * arcgis.com or an on-premise portal.
         *
         * To load a WebMap from an on-premise portal, set the portal
         * url with esriConfig.portalUrl.
         ************************************************************/
        var webmap = new WebMap({
          portalItem: {
            // autocasts as new PortalItem()
            id: ""
          }
        });

        /************************************************************
         * Set the WebMap instance to the map property in a MapView.
         ************************************************************/
        var view = new MapView({
          map: webmap,
          container: "viewDiv",
          center: ['<?=$map_xy_coordinate['x']?>', '<?=$map_xy_coordinate['y']?>'],
          zoom: 15
        });

        var graphicsLayer = new GraphicsLayer();
        webmap.add(graphicsLayer);  
        view.when(function() {
          // Add the boundary polygon and new lot polygon graphics
          addGraphics();
         });
      function addGraphics() {
          //pass geographic vertices
          const vertices = <?php echo json_encode($map_ring_coordinate);?>;
          const polygon = createGeometry(vertices);
          //console.log(polygon);
          validSymbol = createSymbol([0, 170, 255, 0.2], "solid", 2, [
            255,
            255,
            255
          ]);
          newDevelopmentGraphic = new Graphic({
            geometry: polygon,
            symbol: validSymbol,
            attributes: {
            newDevelopment: "new store"
            }
          });
          graphicsLayer.addMany([newDevelopmentGraphic]);
        }
        function createGeometry(vertices) {
          return new Polygon({
            rings: vertices,
            spatialReference: new SpatialReference({wkid:4326})
          });
        }
        function createSymbol(color, style, width, outlineColor) {
          return {
            type: "simple-fill",
            style: style,
            color: color,
            outline: {
              color: outlineColor,
              width: width
            }
          };
        }
      });
    </script>

0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Esteemed Contributor

Rajni,

   You can do something like this:

...
        graphicsLayer.add(newDevelopmentGraphic);
        var mapExtent = view.extent.expand(9);
        var overlayGeom = geometryEngine.difference(mapExtent, newDevelopmentGraphic.geometry);

        var symbol2 = {
          type: "simple-fill",
          style: "solid",
          color: [129, 129, 129, 0.8],
          outline: {
            color: [255, 255, 255, 0],
            width: 0
          }
        };

        overLayGra = new Graphic({
          geometry: overlayGeom,
          symbol: symbol2
        });
        graphicsLayer.add(overLayGra);
      }

But you would have to figure out how to update the overlay when the newDevelopmentGraphic is being moved or reshaped. I don't have any input on this since I do not think this is a good workflow. Of course you will have to add geometryEngine to your apps require array.

View solution in original post

5 Replies
RobertScheitlin__GISP
MVP Esteemed Contributor

Rajni,

I get some relative answer in older version, but it is not helpful.

What relative answer in older version. A link would help. And why is it not helpful?

0 Kudos
rsharma
Occasional Contributor III

I find this link and it uses shape files that i don't use, and couldn't understand how to do it

Fade back map outside of polygon 

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Rajni,

   You can do something like this:

...
        graphicsLayer.add(newDevelopmentGraphic);
        var mapExtent = view.extent.expand(9);
        var overlayGeom = geometryEngine.difference(mapExtent, newDevelopmentGraphic.geometry);

        var symbol2 = {
          type: "simple-fill",
          style: "solid",
          color: [129, 129, 129, 0.8],
          outline: {
            color: [255, 255, 255, 0],
            width: 0
          }
        };

        overLayGra = new Graphic({
          geometry: overlayGeom,
          symbol: symbol2
        });
        graphicsLayer.add(overLayGra);
      }

But you would have to figure out how to update the overlay when the newDevelopmentGraphic is being moved or reshaped. I don't have any input on this since I do not think this is a good workflow. Of course you will have to add geometryEngine to your apps require array.

rsharma
Occasional Contributor III

Its not working, It only show overlay on whole map.

like this my polygon also covered with overlay

This is my code:

function addGraphics() {
          //pass geographic vertices
          const vertices = <?php echo json_encode($map_ring_coordinate);?>;
          const polygon = createGeometry(vertices);
          //console.log(polygon);
          validSymbol = createSymbol([255, 121, 25, 0.0], "solid", 2, [
           255, 121, 25
          ]);
          newDevelopmentGraphic = new Graphic({
            geometry: polygon,
            symbol: validSymbol,
            attributes: {
            newDevelopment: "new store"
            }
          });
          graphicsLayer.add(newDevelopmentGraphic);
        var mapExtent = view.extent.expand(9);
        var overlayGeom = geometryEngine.difference(mapExtent, newDevelopmentGraphic.geometry);

        var symbol2 = {
          type: "simple-fill",
          style: "solid",
          color: [129, 129, 129, 0.5],
          outline: {
            color: [255, 255, 255, 0],
            width: 0
          }
        };

        overLayGra = new Graphic({
          geometry: overlayGeom,
          symbol: symbol2
        });
        graphicsLayer.add(overLayGra);
        }

I don't want to move and reshape the graphics so their is no need to think of it

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Rajni,

  Works fine for me. Compare the code to find your mistake.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>Intro to MapView - Create a 2D map - 4.14</title>
  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
  </style>

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

  <script>
    require(["esri/views/MapView",
      "esri/WebMap",
      "esri/Graphic",
      "esri/layers/GraphicsLayer",
      "esri/widgets/Sketch/SketchViewModel",
      "esri/geometry/Polygon",
      "esri/geometry/SpatialReference",
      "esri/geometry/support/webMercatorUtils",
      "esri/geometry/geometryEngine"
    ], function (MapView, WebMap, Graphic, GraphicsLayer, SketchViewModel, Polygon, SpatialReference, webMercatorUtils, geometryEngine) {

      let sketchViewModel,
        validSymbol,
        newDevelopmentGraphic,
        overLayGra;
      /************************************************************
       * Creates a new WebMap instance. A WebMap must reference
       * a PortalItem ID that represents a WebMap saved to
       * arcgis.com or an on-premise portal.
       *
       * To load a WebMap from an on-premise portal, set the portal
       * url with esriConfig.portalUrl.
       ************************************************************/
      var webmap = new WebMap({
        portalItem: {
          // autocasts as new PortalItem()
          id: "a8e76ad6641b46978f148cba03ab3e2d"
        }
      });

      /************************************************************
       * Set the WebMap instance to the map property in a MapView.
       ************************************************************/
      var view = new MapView({
        map: webmap,
        container: "viewDiv",
        center: [175.9258624, -37.55590445],
        zoom: 20
      });

      var graphicsLayer = new GraphicsLayer();
      webmap.add(graphicsLayer);

      setUpGraphicClickHandler();

      view.when(function () {
        // Add the boundary polygon and new lot polygon graphics
        addGraphics();

        // Create a new instance of sketchViewModel
        sketchViewModel = new SketchViewModel({
          view: view,
          layer: graphicsLayer,
          updateOnGraphicClick: false,
          defaultUpdateOptions: {
            // set the default options for the update operations
            toggleToolOnClick: false // only reshape operation will be enabled
          }
        });

        // Listen to sketchViewModel's update event to do
        // graphic reshape or move validation
        sketchViewModel.on(["update", "undo", "redo"], onGraphicUpdate);
        sketchViewModel.update([newDevelopmentGraphic], {tool: "reshape"});
      });

      function onGraphicUpdate(event) {
        // get the graphic as it is being updated
        const graphic = event.graphics[0];

        // check if the update event's the toolEventInfo.type is move-stop or reshape-stop
        // then it means user finished moving or reshaping the graphic, call complete method.
        // this will change update event state to complete and we will check the validity of the graphic location.
        if (
          event.toolEventInfo &&
          (event.toolEventInfo.type === "move-stop" ||
            event.toolEventInfo.type === "reshape-stop")
        ) {
          sketchViewModel.complete();
        } else if (event.state === "cancel" || event.state === "complete") {
          // graphic moving or reshaping has been completed or cancelled
          // if the graphic is in an illegal spot, call sketchviewmodel's update method again
          // giving user a chance to correct the location of the graphic
          sketchViewModel.update([graphic], {
            tool: "reshape"
          });
        } else {
          graphic.symbol = validSymbol;
        }
      }

      // This function is called when a user clicks on the view.
      function setUpGraphicClickHandler() {
        view.on("click", function (event) {
          // check if the sketch's state active if it is then that means
          // the graphic is already being updated, no action required.
          if (sketchViewModel.state === "active") {
            return;
          }
          view.hitTest(event).then(function (response) {
            var results = response.results;
            // Check if the new development graphic was clicked and pass
            // the graphic to sketchViewModel.update() with reshape tool.
            //console.log(results);
            results.forEach(function (result) {
              console.log(result.mapPoint);
              if (
                result.graphic.layer === sketchViewModel.layer &&
                result.graphic.attributes &&
                result.graphic.attributes.newDevelopment
              ) {
                sketchViewModel.update([result.graphic], {
                  tool: "reshape"
                });
              }
            });
          });
        });
      }

      function addGraphics() {
        const vertices = [
          [175.9258624, -37.55590445],
          [175.9258630667, -37.55587745],
          [175.9258671333, -37.5557153],
          [175.92626316670004, -37.5557216],
          [175.92625955, -37.5558657],
          [175.9262584333, -37.5559107333],
          [175.9258624, -37.55590445]
        ];

        const polygon = createGeometry(vertices);
        validSymbol = createSymbol([255, 255, 255, 0.3], "solid", 2, [
          255,121,5]);
        newDevelopmentGraphic = new Graphic({
          geometry: webMercatorUtils.geographicToWebMercator(polygon),
          symbol: validSymbol,
          attributes: {
            newDevelopment: "new store"
          }
        });
        graphicsLayer.add(newDevelopmentGraphic);
        var mapExtent = view.extent.expand(9);
        var overlayGeom = geometryEngine.difference(mapExtent, newDevelopmentGraphic.geometry);

        var symbol2 = {
          type: "simple-fill",
          style: "solid",
          color: [129, 129, 129, 0.8],
          outline: {
            color: [255, 255, 255, 0],
            width: 0
          }
        };

        overLayGra = new Graphic({
          geometry: overlayGeom,
          symbol: symbol2
        });
        graphicsLayer.add(overLayGra);
      }

      function createGeometry(vertices) {
        return new Polygon({
          rings: vertices,
          spatialReference: new SpatialReference({
            wkid: 4326
          })
        });
      }

      function createSymbol(color, style, width, outlineColor) {
        return {
          type: "simple-fill",
          style: style,
          color: color,
          outline: {
            color: outlineColor,
            width: width,
            style: "dash"
          }
        };
      }
    });
  </script>
</head>

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

</html>