Select to view content in your preferred language

SketchViewModel geometry editing bug 4.19

729
2
06-03-2021 06:09 PM
JoelBennett
MVP Regular Contributor

The interactive geometry-editing utility of the SketchViewModel will not work if the view's extent is not normalized. This can be verified in the sample "Edit features with the Editor widget" with the following steps:

  1. Load the sample.
  2. Pan east (or west) until you go all the way around the world. This will go much faster if you zoom way out, pan, and then zoom back in to the editable features.
  3. In the "Editor" widget, click "Edit feature".
  4. Click on a polygon feature; this puts the feature into interactive geometry-editing mode.
  5. Move the mouse cursor over the rotation handle; note that rotation handle doesn't become highlighted like it should.
  6. Click and drag on the rotation handle; the feature is not rotated, and the map is panned instead. The same occurs if you attempt to use the resize handles or drag the feature to a new location.

This was observed in 4.18 and 4.19; I don't know if it worked in previous versions or not.

I haven't attempted to troubleshoot the API code itself. Instead, my current workaround is to detect if the view's extent is normalized before using the SketchViewModel, and if it is not, to normalize it before allowing further action to take place.

0 Kudos
2 Replies
JoelBennett
MVP Regular Contributor

As a revision to what I said about the issue earlier, the problem occurs whenever the geometry being edited isn't normalized to the view.  That is, it occurs in cases where the geometry's x values don't fall within the range of the view's xmin and xmax, but because of wrapping, the geometry still displays within the view.

As a result, I gave up on trying workarounds, and went straight to the heart of the issue, which turns out to be the toScreen function of the MapView.  When using interactive geometry editing with the SketchViewModel, it uses an internal GraphicsLayer to display the rotation and resizing handles (etc).  As you move the mouse, it constantly checks to see if the mouse is over one of those handles, and it does so in part by using the _intersectDistance2D function of the esri/views/interactive/GraphicManipulator class.  Within this function is a call to MapView.toScreen.  If the geographic coordinates of those handles are not within the xmin and xmax of the view's extent, the returned ScreenPoint's x value will be off the charts (i.e. well outside of your screen's width).  It shouldn't work this way since the handle is clearly on the screen.  As a result, _intersectDistance2D concludes the mouse pointer is nowhere near the handle, and so you ultimately can't use it.

As it turns out, I was already dealing with this kind of issue elsewhere, so I had a custom function added directly to the Point prototype called normalizeToView.  Here is the implementation (note that spatialReferenceUtils is the module esri/geometry/support/spatialReferenceUtils):

 

Point.prototype.normalizeToView = function(view) {
    var point = this.clone();

    if ((view) && (view.extent) && (!view.extent.intersects(this))) {
        var info = spatialReferenceUtils.getInfo(view.spatialReference);

        if (info) {
            var extents = view.extent.clone().normalize();
            var nPoint = this.clone().normalize();
            var intersects = false;

            for (var x = 0; x < extents.length; x++) {
                if (extents[x].intersects(nPoint)) {
                    intersects = true;
                    break;
                }
            }

            if (intersects) {
                var worldWidth = info.valid[1] * 2;

                while (point.x < view.extent.xmin)
                    point.x += worldWidth;

                while (point.x > view.extent.xmax)
                    point.x -= worldWidth;
            }
        }
    }

    return point;
};

 

Therefore, I just revised the toScreen function to use this if it was available.  In the file esri/views/MapView.js, I did the following:

 

Search for:

U=this._normalizeInput(U);

 

Replace with:

U=this._normalizeInput((((U)&&(typeof U.normalizeToView=="function"))?U.normalizeToView(this):U));

 

0 Kudos
JoelBennett
MVP Regular Contributor

This was fixed in version 4.22, presumably as a result of the "MapView.hitTest improvements for GraphicsLayer" mentioned in the release notes.