Home > Back-end >  Snapping with Sketch widget and Magnifier
Snapping with Sketch widget and Magnifier

Time:10-23

I am working on utilize snapping with the Sketch widget in 2D. It also takes advantage of the Magnifier to make it easier to snap to the vertices of existing graphics.

For me the snapping and editing widget is working fine and have no issue. Further I want to add the magnifier, to my code, I try some code to add but not getting successful. Below is my code.

Any suggestion?

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />

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

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

      #configurationDiv {
        padding: 10px;
        text-align: left;
        width: 250px;
      }

      .switch {
        position: relative;
        display: inline-block;
        width: 45px;
        height: 22px;
        vertical-align: middle;
      }

      .switch input {
        opacity: 0;
        width: 0;
        height: 0;
      }

      .slider {
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #ccc;
        -webkit-transition: 0.4s;
        transition: 0.4s;
      }

      .slider:before {
        position: absolute;
        content: "";
        height: 20px;
        width: 20px;
        left: 3px;
        bottom: 1px;
        background-color: white;
        -webkit-transition: 0.4s;
        transition: 0.4s;
      }

      input:checked .slider {
        background-color: #2196f3;
      }

      input:focus .slider {
        box-shadow: 0 0 1px #2196f3;
      }

      input:checked .slider:before {
        -webkit-transform: translateX(20px);
        -ms-transform: translateX(20px);
        transform: translateX(20px);
      }

      /* Rounded sliders */
      .slider.round {
        border-radius: 20px;
      }

      .slider.round:before {
        border-radius: 50%;
      }

      .labelText {
        padding-left: 5px;
        font-size: 15px;
      }

      #mainDiv {
        padding: 8px;
      }
    </style>
    <script>
      require([
        "esri/widgets/Sketch",
        "esri/Map",
        "esri/layers/GraphicsLayer",
        "esri/views/MapView",
        "esri/widgets/Expand"
      ], (Sketch, Map, GraphicsLayer, MapView, Expand) => {
        // Get reference to div elements
        const magnifierSlider = document.getElementById("magnifierCheckbox");
        const labelText = document.getElementById("labelText");
        const selfSnapCheckBox = document.getElementById(
          "selfSnappingCheckbox"
        );
        const featureSnapCheckBox = document.getElementById(
          "featureSnappingCheckbox"
        );
        let toggle;

        const graphicsLayer = new GraphicsLayer();

        const map = new Map({
          basemap: "streets-navigation-vector",
          layers: [graphicsLayer]
        });

        const view = new MapView({
          container: "viewDiv",
          map: map,
          zoom: 6,
          center: [38.33081, 0.36532]
        });

        const sketch = new Sketch({
          layer: graphicsLayer,
          view: view,
          // graphic will be selected as soon as it is created
          creationMode: "update",
          snappingOptions: {
            // autocasts as SnappingOptions()
            enabled: true, // snapping will be on by default
            // feature snapping will be enabled on the GraphicsLayer
            featureSources: [{ layer: graphicsLayer }]
          }
        });

        const configurationExpand = new Expand({
          expandIconClass: "esri-icon-settings2",
          expandTooltip: "Show snapping configuration",
          expanded: true,
          view: view,
          content: document.getElementById("configurationDiv")
        });

        view.when(() => {
          // add the ui components to the view
          view.ui.add(sketch, "top-right");
          view.ui.add(configurationExpand, "bottom-right");

          // Magnifier
          view.magnifier.visible = false;
          view.magnifier.factor = 1.7; // magnification factor
          view.magnifier.size = 150; // magnifier image size
          view.magnifier.offset = { x: 75, y: 75 }; // x and y offset values

          view.on("pointer-move", (evt) => {
            view.magnifier.position = { x: evt.x, y: evt.y };
          });
          view.on(["key-down", "key-up"], (event) => {
            if (event.type === "key-down" && event.key === "m") {
              view.magnifier.visible = toggle ? false : true;
            }
            if (event.type === "key-up" && event.key === "m") {
              view.magnifier.visible = toggle ? true : false;
            }
            magnifierSlider.checked = view.magnifier.visible;
          });
        });

        // event listeners to toggle the Magnifier as well
        // as the individual snapping functionality like self and feature snapping.
        magnifierSlider.onchange = () => {
          toggleMagnifier();
        };

        selfSnapCheckBox.checked = sketch.snappingOptions.selfEnabled;
        selfSnapCheckBox.addEventListener("change", (event) => {
          sketch.snappingOptions.selfEnabled = event.target.checked
            ? true
            : false;
        });

        featureSnapCheckBox.checked = sketch.snappingOptions.featureEnabled;
        featureSnapCheckBox.addEventListener("change", (event) => {
          sketch.snappingOptions.featureEnabled = event.target.checked
            ? true
            : false;
        });

     
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="configurationDiv" class="esri-widget">
      <h3>Toggle SnappingOptions</h3>
      <table id="configurationTable">
        <tr>
          <td>
            <label for="selfSnappingCheckbox" id="selfSnappingCheckboxLabel">
              - self snapping</label
            >
          </td>
          <td><input type="checkbox" id="selfSnappingCheckbox" /></td>
        </tr>
        <tr>
          <td>
            <label
              for="featureSnappingCheckbox"
              id="featureSnappingCheckboxLabel"
            >
              - feature snapping</label
            >
          </td>
          <td><input type="checkbox" id="featureSnappingCheckbox" /></td>
        </tr>
      </table>
      <hr />
      <div id="mainDiv" class="esri-widget">
        <label class="switch">
          <input id="magnifierCheckbox" type="checkbox" />
          <span class="slider round"></span>
        </label>
        <label class="labelText" id="labelText">Magnifier</label>
        <p>
          <i>Hold down the <b>'m'</b> key to toggle the Magnifier</i>
        </p>
      </div>
    </div>
  </body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

If I understand correctly the idea,

  • if magnifier checkbox is checked then while m key is pressed magnifier widget is shown.

Then you just need a couple of twist to the code,

<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

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

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

        #configurationDiv {
            padding: 10px;
            text-align: left;
            width: 250px;
        }

        .switch {
            position: relative;
            display: inline-block;
            width: 45px;
            height: 22px;
            vertical-align: middle;
        }

        .switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }

        .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            -webkit-transition: 0.4s;
            transition: 0.4s;
        }

        .slider:before {
            position: absolute;
            content: "";
            height: 20px;
            width: 20px;
            left: 3px;
            bottom: 1px;
            background-color: white;
            -webkit-transition: 0.4s;
            transition: 0.4s;
        }

        input:checked .slider {
            background-color: #2196f3;
        }

        input:focus .slider {
            box-shadow: 0 0 1px #2196f3;
        }

        input:checked .slider:before {
            -webkit-transform: translateX(20px);
            -ms-transform: translateX(20px);
            transform: translateX(20px);
        }

        /* Rounded sliders */
        .slider.round {
            border-radius: 20px;
        }

        .slider.round:before {
            border-radius: 50%;
        }

        .labelText {
            padding-left: 5px;
            font-size: 15px;
        }

        #mainDiv {
            padding: 8px;
        }
    </style>
    <script>
        require([
            "esri/widgets/Sketch",
            "esri/Map",
            "esri/layers/GraphicsLayer",
            "esri/views/MapView",
            "esri/widgets/Expand"
        ], (Sketch, Map, GraphicsLayer, MapView, Expand) => {
            // Get reference to div elements
            const magnifierSlider = document.getElementById("magnifierCheckbox");
            const labelText = document.getElementById("labelText");
            const selfSnapCheckBox = document.getElementById(
                "selfSnappingCheckbox"
            );
            const featureSnapCheckBox = document.getElementById(
                "featureSnappingCheckbox"
            );
            let toggle;

            const graphicsLayer = new GraphicsLayer();

            const map = new Map({
                basemap: "streets-navigation-vector",
                layers: [graphicsLayer]
            });

            const view = new MapView({
                container: "viewDiv",
                map: map,
                zoom: 6,
                center: [38.33081, 0.36532]
            });

            const sketch = new Sketch({
                layer: graphicsLayer,
                view: view,
                // graphic will be selected as soon as it is created
                creationMode: "update",
                snappingOptions: {
                    // autocasts as SnappingOptions()
                    enabled: true, // snapping will be on by default
                    // feature snapping will be enabled on the GraphicsLayer
                    featureSources: [{ layer: graphicsLayer }]
                }
            });

            const configurationExpand = new Expand({
                expandIconClass: "esri-icon-settings2",
                expandTooltip: "Show snapping configuration",
                expanded: true,
                view: view,
                content: document.getElementById("configurationDiv")
            });

            view.when(() => {
                // add the ui components to the view
                view.ui.add(sketch, "top-right");
                view.ui.add(configurationExpand, "bottom-right");

                // Magnifier
                view.magnifier.visible = false;
                view.magnifier.factor = 1.7; // magnification factor
                view.magnifier.size = 150; // magnifier image size
                view.magnifier.offset = { x: 75, y: 75 }; // x and y offset values

                view.on("pointer-move", (evt) => {
                    view.magnifier.position = { x: evt.x, y: evt.y };
                });
                view.on(["key-down", "key-up"], (event) => {
                    if (toggle) { // magnifierSlider is checked?
                        if (event.type === "key-down" && event.key === "m") {
                            view.magnifier.visible = true;
                        }
                        if (event.type === "key-up" && event.key === "m") {
                            view.magnifier.visible = false;
                        }
                    }
                    // magnifierSlider.checked = view.magnifier.visible;
                });
            });

            // event listeners to toggle the Magnifier as well
            // as the individual snapping functionality like self and feature snapping.
            magnifierSlider.onchange = () => {
                toggle = magnifierSlider.checked;
            };

            selfSnapCheckBox.checked = sketch.snappingOptions.selfEnabled;
            selfSnapCheckBox.addEventListener("change", (event) => {
                sketch.snappingOptions.selfEnabled = event.target.checked
                    ? true
                    : false;
            });

            featureSnapCheckBox.checked = sketch.snappingOptions.featureEnabled;
            featureSnapCheckBox.addEventListener("change", (event) => {
                sketch.snappingOptions.featureEnabled = event.target.checked
                    ? true
                    : false;
            });


        });
    </script>
</head>

<body>
    <div id="viewDiv"></div>
    <div id="configurationDiv" class="esri-widget">
        <h3>Toggle SnappingOptions</h3>
        <table id="configurationTable">
            <tr>
                <td>
                    <label for="selfSnappingCheckbox" id="selfSnappingCheckboxLabel">
                        - self snapping</label>
                </td>
                <td><input type="checkbox" id="selfSnappingCheckbox" /></td>
            </tr>
            <tr>
                <td>
                    <label for="featureSnappingCheckbox" id="featureSnappingCheckboxLabel">
                        - feature snapping</label>
                </td>
                <td><input type="checkbox" id="featureSnappingCheckbox" /></td>
            </tr>
        </table>
        <hr />
        <div id="mainDiv" class="esri-widget">
            <label class="switch">
                <input id="magnifierCheckbox" type="checkbox" />
                <span class="slider round"></span>
            </label>
            <label class="labelText" id="labelText">Magnifier</label>
            <p>
                <i>Hold down the <b>'m'</b> key to toggle the Magnifier</i>
            </p>
        </div>
    </div>
</body>

</html>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You can achieve this by defining the magnifier function in your code, as follows:

function toggleMagnifier() {
  toggle = !toggle;
  view.magnifier.visible = toggle;
  view.focus(); 
}

So your final code will look like this:

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>
      Snapping with Sketch widget and Magnifier | Sample | ArcGIS API for
      JavaScript 4.21
    </title>

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

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

      #configurationDiv {
        padding: 10px;
        text-align: left;
        width: 250px;
      }

      .switch {
        position: relative;
        display: inline-block;
        width: 45px;
        height: 22px;
        vertical-align: middle;
      }

      .switch input {
        opacity: 0;
        width: 0;
        height: 0;
      }

      .slider {
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #ccc;
        -webkit-transition: 0.4s;
        transition: 0.4s;
      }

      .slider:before {
        position: absolute;
        content: "";
        height: 20px;
        width: 20px;
        left: 3px;
        bottom: 1px;
        background-color: white;
        -webkit-transition: 0.4s;
        transition: 0.4s;
      }

      input:checked .slider {
        background-color: #2196f3;
      }

      input:focus .slider {
        box-shadow: 0 0 1px #2196f3;
      }

      input:checked .slider:before {
        -webkit-transform: translateX(20px);
        -ms-transform: translateX(20px);
        transform: translateX(20px);
      }

      /* Rounded sliders */
      .slider.round {
        border-radius: 20px;
      }

      .slider.round:before {
        border-radius: 50%;
      }

      .labelText {
        padding-left: 5px;
        font-size: 15px;
      }

      #mainDiv {
        padding: 8px;
      }
    </style>
    <script>
      require([
        "esri/widgets/Sketch",
        "esri/Map",
        "esri/layers/GraphicsLayer",
        "esri/views/MapView",
        "esri/widgets/Expand"
      ], (Sketch, Map, GraphicsLayer, MapView, Expand) => {
        // Get reference to div elements
        const magnifierSlider = document.getElementById("magnifierCheckbox");
        const labelText = document.getElementById("labelText");
        const selfSnapCheckBox = document.getElementById(
          "selfSnappingCheckbox"
        );
        const featureSnapCheckBox = document.getElementById(
          "featureSnappingCheckbox"
        );
        let toggle;

        const graphicsLayer = new GraphicsLayer();

        const map = new Map({
          basemap: "streets-navigation-vector",
          layers: [graphicsLayer]
        });

        const view = new MapView({
          container: "viewDiv",
          map: map,
          zoom: 6,
          center: [38.33081, 0.36532]
        });

        const sketch = new Sketch({
          layer: graphicsLayer,
          view: view,
          // graphic will be selected as soon as it is created
          creationMode: "update",
          snappingOptions: {
            // autocasts as SnappingOptions()
            enabled: true, // snapping will be on by default
            // feature snapping will be enabled on the GraphicsLayer
            featureSources: [{ layer: graphicsLayer }]
          }
        });

        const configurationExpand = new Expand({
          expandIconClass: "esri-icon-settings2",
          expandTooltip: "Show snapping configuration",
          expanded: true,
          view: view,
          content: document.getElementById("configurationDiv")
        });

        view.when(() => {
          // add the ui components to the view
          view.ui.add(sketch, "top-right");
          view.ui.add(configurationExpand, "bottom-right");

          // Magnifier
          view.magnifier.visible = false;
          view.magnifier.factor = 1.7; // magnification factor
          view.magnifier.size = 150; // magnifier image size
          view.magnifier.offset = { x: 75, y: 75 }; // x and y offset values

          // displays the Magnifier wherever the cursor appears on the Map
          view.on("pointer-move", (evt) => {
            view.magnifier.position = { x: evt.x, y: evt.y };
          });

          // adding a shortcut key to toggle the Magnifier visibility. Use the 'm' key
          view.on(["key-down", "key-up"], (event) => {
            if (event.type === "key-down" && event.key === "m") {
              view.magnifier.visible = toggle ? false : true;
            }
            if (event.type === "key-up" && event.key === "m") {
              view.magnifier.visible = toggle ? true : false;
            }
            magnifierSlider.checked = view.magnifier.visible;
          });
        });

        // event listeners to toggle the Magnifier as well
        // as the individual snapping functionality like self and feature snapping.
        magnifierSlider.onchange = () => {
          toggleMagnifier();
        };

        selfSnapCheckBox.checked = sketch.snappingOptions.selfEnabled;
        selfSnapCheckBox.addEventListener("change", (event) => {
          sketch.snappingOptions.selfEnabled = event.target.checked
            ? true
            : false;
        });

        featureSnapCheckBox.checked = sketch.snappingOptions.featureEnabled;
        featureSnapCheckBox.addEventListener("change", (event) => {
          sketch.snappingOptions.featureEnabled = event.target.checked
            ? true
            : false;
        });

        // toggle the Magnifier visibility
        function toggleMagnifier() {
          toggle = !toggle;
          view.magnifier.visible = toggle;
          view.focus(); // focus back to the view to listen for 'm' key
        }
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="configurationDiv" class="esri-widget">
      <h3>Toggle SnappingOptions</h3>
      <table id="configurationTable">
        <tr>
          <td>
            <label for="selfSnappingCheckbox" id="selfSnappingCheckboxLabel">
              - self snapping</label
            >
          </td>
          <td><input type="checkbox" id="selfSnappingCheckbox" /></td>
        </tr>
        <tr>
          <td>
            <label
              for="featureSnappingCheckbox"
              id="featureSnappingCheckboxLabel"
            >
              - feature snapping</label
            >
          </td>
          <td><input type="checkbox" id="featureSnappingCheckbox" /></td>
        </tr>
      </table>
      <hr />
      <div id="mainDiv" class="esri-widget">
        <label class="switch">
          <input id="magnifierCheckbox" type="checkbox" />
          <span class="slider round"></span>
        </label>
        <label class="labelText" id="labelText">Magnifier</label>
        <p>
          <i>Hold down the <b>'m'</b> key to toggle the Magnifier</i>
        </p>
      </div>
    </div>
  </body>
</html>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related