Delete a vertice of polygon on edited shape

Jérémie Perez 1 Reputation point
2020-11-27T08:47:05.877+00:00

Hi,

I'm moving a web app from Bing map to Azure maps. In this web app, I using polygon to delimited the delivery area.

On azure maps, I succeed to edit a shape using a method related to the ticket azure-drawing-tools-module-default-selected-shape.html

With this method, I can modify my polygon, add new vertice but I can't delete it.
Furthermore, when the polygon is on edition mode, I can't move on the map.

Any ideas on how to achieve this?

Azure Maps
Azure Maps
An Azure service that provides geospatial APIs to add maps, spatial analytics, and mobility solutions to apps.
836 questions
{count} votes

2 answers

Sort by: Most helpful
  1. rbrundritt 20,921 Reputation points Microsoft Employee Moderator
    2020-12-02T22:40:18.937+00:00

    Support for deleting individual vertices is planned but won't be available until around mid-next year. There is no easy way to achieve this with the current drawing tools. It may be possible to handle this outside of the drawing tools some how (i.e. add your own handles/buttons to each vertices).

    As for the map not panning. The drawing tools in Azure Maps have some advance interaction support which make it much easier for all users to use it (i.e. accessibility support). By default the drawing managers interaction type is set to hybrid which allows you to draw by dragging or clicking points. If you limit the interaction type to just clicking, you could then use the following code to get the map to support panning while drawing.

    //Create an instance of the drawing manager and display the drawing toolbar.
    drawingManager = new atlas.drawing.DrawingManager(map, {
        interactionType: 'click',
        toolbar: new atlas.control.DrawingToolbar({
            position: 'top-right'
        })
    });
    
    //When the drawing started, check to see if the interaction type is set to click, and if it is, re-enable panning of the map.
    map.events.add('drawingstarted', drawingManager, () => {
        if (drawingManager.getOptions().interactionType === 'click') {
            map.setUserInteraction({ dragPanInteraction: true });
        }
    });
    
    2 people found this answer helpful.

  2. rbrundritt 20,921 Reputation points Microsoft Employee Moderator
    2022-12-05T23:12:02.56+00:00

    I don't believe this feature was ever added, and I don't believe there is any plan to add it. I moved teams not long after my original post on this thread. There are a couple of ways to achieve this today. The approach I would likely try first is as follows:

    1. Add a click event to the line and polygon layers of the drawing manager.
    2. When the click event fires, check to see if the drawing manager is in edit mode (or no mode selected). If so, proceed.
    3. Capture the shape that was clicked and calculate the closest position to the mouse position and get its index. It might be good to have a threshold for max distance offset. Store the shape and index in a temp variable, then show a popup asking with a delete button.
    4. If the button is clicked, delete the vertex from the shape by getting all the positions/coordinates in the shape as an array (getCoordinates) then use splice to remove the position based on its index, then clear the temp variable. If the popup is closed without the button being clicked, or the drawing mode changes, ignore or clear the temp variable.

    Here is a code sample. When you hover over a line or polygon the mouse pointer will change to let you know you can select a point. When clicked a popup appears with a delete button.

       <!DOCTYPE html>  
       <html lang="en">  
       <head>  
           <title></title>  
         
           <meta charset="utf-8" />  
           <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />  
         
           <!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->  
           <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />  
           <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>  
         
           <!-- Add references to the Azure Maps Map Drawing Tools JavaScript and CSS files. -->  
           <link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.css" type="text/css" />  
           <script src="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.js"></script>  
         
           <script>  
               var map, drawingManager, vertexState, popup;  
               var maxThreshold = 15; //Click must be within 15 pixels of a coordinate.  
         
               function GetMap() {  
                   //Initialize a map instance.  
                   map = new atlas.Map('myMap', {  
                       view: 'Auto',  
         
                       //Add authentication details for connecting to Azure Maps.  
                       authOptions: {  
                           authType: 'subscriptionKey',  
                           subscriptionKey: '[YOUR_AZURE_MAPS_KEY]'  
                       }  
                   });  
         
                   //Wait until the map resources are ready.  
                   map.events.add('ready', function () {  
         
                       //Create an instance of the drawing manager and display the drawing toolbar.  
                       drawingManager = new atlas.drawing.DrawingManager(map, {  
                           toolbar: new atlas.control.DrawingToolbar({  
                               position: 'top-right',  
                               buttons: ['draw-line', 'draw-polygon']  
                           })  
                       });  
         
                       //Set event on the drawing manager.  
                       map.events.add('drawingmodechanged', drawingManager, clearState);  
         
                       //Exit drawing mode after draiwng completed.  
                       map.events.add('drawingcomplete', drawingManager, () => {  
                           drawingManager.setOptions({ mode: 'idle' });  
                       });  
         
                       //Get the line and polygon layers from the drawing manager and add click events to them.  
                       var layers = drawingManager.getLayers();  
         
                       //Get preview rendering layers from the drawing manager and modify line styles to be dashed.  
                       var previewLayers = drawingManager.getPreviewLayers();  
         
                       var targetLayers = [layers.lineLayer, previewLayers.lineLayer, layers.polygonOutlineLayer, previewLayers.polygonOutlineLayer];  
         
                       map.events.add('click', targetLayers, shapeClicked);  
         
                       //When the mouse leaves the item on the layer, change the cursor back to the default which is grab.  
                       map.events.add('mouseout', targetLayers, function () {  
                           map.getCanvas().style.cursor = 'grab';  
                       });  
         
                       //When the mouse is over the layer, change the cursor to be a pointer.  
                       map.events.add('mouseover', targetLayers, function () {  
                           map.getCanvas().style.cursor = 'pointer';  
                       });  
         
                       //Create a popup and add a close event to it.  
                       popup = new atlas.Popup();  
                       map.events.add('close', popup, clearState);                  
                   });  
               }  
         
               function shapeClicked(e) {  
                   var mode = drawingManager.getOptions().mode;  
         
                   if (mode === 'edit' || mode === 'idle') {  
         
                       var shape = e.shapes[0];  
                       var position;  
         
                       //Default state.  
                       vertexState = {  
                           shape: shape,  
                           ring: 0,  
                           idx: 0  
                       };  
         
                       //Get nearest coordinate in shape to the clicked position.  
                       var shapeType = shape.getType();  
                       var coords = shape.getCoordinates();  
                       var minDist = Infinity;  
         
                       if (shapeType === 'Polygon') {  
                           for (var i = 0; i < coords.length; i++) {  
                               for (var j = 0; j < coords[i].length; j++) {  
                                   var d = atlas.math.getDistanceTo(coords[i][j], e.position);  
                                   if (d < minDist) {  
                                       vertexState.ring = i;  
                                       vertexState.idx = j;  
                                       minDist = d;  
                                       position = coords[i][j];  
                                   }  
                               }  
                           }  
                       } else if (shapeType === 'LineString') {  
                           for (var i = 0; i < coords.length; i++) {  
                               var d = atlas.math.getDistanceTo(coords[i], e.position);  
                               if (d < minDist) {  
                                   vertexState.idx = i;  
                                   minDist = d;  
                                   position = coords[i];  
                               }  
                           }  
                       } else {  
                           //Unsupported shape, ignore.  
                           return;  
                       }  
         
                       //Calculate the pixel distance between the mouse and the nearest vertex and ensure it is within the threshold distance.  
                       var p = map.positionsToPixels([position, e.position]);  
                       if (new atlas.PixelgetDistance(p[0], p[1]) > maxThreshold) {  
                           return;  
                       }  
         
                       //Create a DOM element to pass into the content of the popup.   
                       var popupContent = document.createElement('div');  
                       popupContent.style.padding = '10px';  
         
                       var button = document.createElement('input');  
                       button.type = 'button';  
                       button.value = 'Delete point';  
         
                       button.addEventListener('click', deleteVertex);  
         
                       popupContent.appendChild(button);  
         
                       popup.setOptions({  
                           content: popupContent,  
                           position: e.position  
                       });  
         
                       popup.open(map);  
                   }  
               }  
         
               function clearState() {  
                   if (vertexState) {  
                       vertexState = null;  
                       popup.close();  
                   }  
               }  
         
               function deleteVertex() {  
                   if (vertexState) {  
                       var shapeType = vertexState.shape.getType();  
         
                       if (shapeType === 'Polygon') {  
                           var coords = vertexState.shape.getCoordinates();  
         
                           //If first or last coordinate, need to remove two coords since the ring is closed. Then ensure the new ring is closed.  
                           if (vertexState.idx === 0 || vertexState.idx === coords.length) {  
                               coords[vertexState.ring] = coords[vertexState.ring].slice(1, coords.length - 2);  
                               coords[vertexState.ring].push(coords[vertexState.ring][0]);  
                           } else {  
                               coords[vertexState.ring].splice(vertexState.idx, 1);  
                           }  
         
                           //If less than 4 coordinates, polygon no longer valid. Delete it from the drawing manager.  
                           if (coords[vertexState.ring].length <= 3) {  
                               drawingManager.getSource().remove(vertexState.shape);  
                           } else {  
                               vertexState.shape.setCoordinates(coords);  
                           }  
                       } else if (shapeType === 'LineString') {  
                           var coords = vertexState.shape.getCoordinates();  
                           coords.splice(vertexState.idx, 1);  
         
                           //If less than 2 coordinates, line no longer valid. Delete it from the drawing manager.  
                           if (coords[vertexState.ring].length < 2) {  
                               drawingManager.getSource().remove(vertexState.shape);  
                           } else {  
                               vertexState.shape.setCoordinates(coords);  
                           }  
                       } else {  
                           //Unsupported shape, ignore.  
                           return;  
                       }  
         
                       clearState();  
                   }  
               }  
           </script>  
       </head>  
       <body onload="GetMap()">  
           <div id="myMap" style="position:relative;width:800px;height:600px;"></div>  
       </body>  
       </html>  
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.