Editor: Cut Visible Sample with FeatureCollection

2177
15
08-05-2013 12:12 PM
DerivenC
New Contributor II
There used to be an example where you could cut features with the edit tools.  It has since been removed but still exists in the archives (and works):

http://developers.arcgis.com/en/javascript/samples/ed_editing_widget/index.html

A
nd the option in the configuration still exists by setting cutVisible to true:

https://developers.arcgis.com/en/javascript/jsapi/editor.html

M
y question is: can I use this option against a FeatureLayer that is constructed by a feature collection?
https://developers.arcgis.com/en/javascript/jsapi/featurelayer.html#featurelayer2

I
can perform a union but the cut doesn't seem to work.  And without any documentation on the cut, I'm not sure if it ever worked for this type of scenario.

We are using ArcGIS for Server 10.0 and ArcGIS for JS 3.5.
0 Kudos
15 Replies
DerivenC
New Contributor II
bump for response please
0 Kudos
DerivenC
New Contributor II
I merged two samples (Editing: Editor widget with simple toolbar + Vector Feature Layers: Feature collection) and tried them locally as well as in the ArcGIS sandbox.  Cut doesn't work.  I check the developer tools and notice that no calls to the GeometryService are made.  It's like it does nothing at all.  Can someone please tell me why?

<!DOCTYPE html><html>  
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <!--The viewport meta tag is used to improve the presentation and behavior of the
    samples on iOS devices-->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Cut Feature Collection</title>
  <link rel="stylesheet" href="http://js.arcgis.com/3.6/js/dojo/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.6/js/esri/css/esri.css">
     <style>
      html,body{height:100%;width:100%;margin:0;overflow:hidden;}
      #map{
        padding:0;
      }
      #header{
        font-size: 1.1em;
        font-family: sans-serif;
        padding-left: 1em;
        padding-top:4px;
        color:#660000;
      }
      .templatePicker {
        border: none;
      }


      .dj_ie .infowindow .window .top .right .user .content { position: relative; }
      .dj_ie .simpleInfoWindow .content {position: relative;}
    </style>


    <script>var dojoConfig = { parseOnLoad: true };</script>
    <script src="http://js.arcgis.com/3.6/"></script>
    <script>
      var map;
      require([
        "esri/map",
        "esri/toolbars/edit",
        "esri/layers/ArcGISTiledMapServiceLayer",
        "esri/layers/FeatureLayer",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/dijit/editing/Editor",
        "esri/dijit/editing/TemplatePicker",
        "esri/dijit/PopupTemplate",
        "esri/request",
        "esri/geometry/Point",
        "esri/graphic",
        "esri/config",
        "dojo/i18n!esri/nls/jsapi",
        "dojo/_base/array", "dojo/parser", "dojo/keys",
        "dijit/layout/BorderContainer", "dijit/layout/ContentPane", 
        "dojo/on",
        "dojo/_base/array",
        "dojo/domReady!"
      ], function(
        Map, 
        Edit,
        ArcGISTiledMapServiceLayer,
        FeatureLayer, 
        SimpleMarkerSymbol,
        SimpleLineSymbol,
        Editor,
        TemplatePicker,
        PopupTemplate,
        esriRequest,
        Point,
        Graphic,
        esriConfig,
        jsapiBundle,
        arrayUtils,
        parser,
        keys,
        BorderContainer,
        ContentPane,
        on,
        array
      ) {


        var featureLayer;
        parser.parse();
        jsapiBundle.toolbars.draw.start = jsapiBundle.toolbars.draw.start +  "<br>Press <b>ALT</b> to enable snapping";
        esriConfig.defaults.geometryService = new esri.tasks.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
        map = new Map("map", {
          basemap: "satellite",
          center: [-46.807, 32.553],
          zoom: 3
        });
        
        var labels = new ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer");
        map.addLayer(labels);


        //create a feature collection
        var featureCollection = {
          "layerDefinition": null,
          "featureSet": {
            "features": [],
            "geometryType": "esriGeometryPolygon"
          }
        };
        featureCollection.layerDefinition = {
            "geometryType": "esriGeometryPolygon",
            "objectIdField": "ObjectID",
            "drawingInfo" : {
                "renderer" : {
                    "type" : "simple", 
                    "symbol" : {
                        "type" : "esriSFS", 
                        "style" : "esriSFSSolid", 
                        "color" : null, 
                        "outline" : {
                            "type" : "esriSLS", 
                            "style" : "esriSLSSolid", 
                            "color" : [
                                0, 
                                0, 
                                0, 
                                255
                            ], 
                            "width" : 1
                        }
                    }, 
                    "label" : "", 
                    "description" : ""
                },
            },
          "fields": [{
            "name": "ObjectID",
            "alias": "ObjectID",
            "type": "esriFieldTypeOID"
          }, {
            "name": "description",
            "alias": "Description",
            "type": "esriFieldTypeString"
          }, {
            "name": "title",
            "alias": "Title",
            "type": "esriFieldTypeString"
          }]
        };


        //define a popup template
        var popupTemplate = new PopupTemplate({
          title: "{title}",
          description: "{description}"
        });


        //create a feature layer based on the feature collection
        featureLayer = new FeatureLayer(featureCollection, {
          id: 'fcLayer',
          infoTemplate: popupTemplate
        });


        //associate the features with the popup on click
        featureLayer.on("click", function(evt) {
          map.infoWindow.setFeatures([evt.graphic]);
        });


        map.on("layers-add-result", initEditor);
        //add the feature layer
        map.addLayers([featureLayer]);
        
        function initEditor(evt) {
          var templateLayers = arrayUtils.map(evt.layers, function(result){
            return result.layer;
          });
          var templatePicker = new TemplatePicker({
            featureLayers: templateLayers,
            grouping: true,
            rows: "auto",
            columns: 3
          }, "templateDiv");
          templatePicker.startup();


          var layers = arrayUtils.map(evt.layers, function(result) {
            return { featureLayer: result.layer };
          });
          var settings = {
            map: map,
            templatePicker: templatePicker,
            layerInfos: layers,
            toolbarVisible: true,
            createOptions: {
              polylineDrawTools:[ Editor.CREATE_TOOL_FREEHAND_POLYLINE ],
              polygonDrawTools: [ Editor.CREATE_TOOL_FREEHAND_POLYGON,
                Editor.CREATE_TOOL_CIRCLE,
                Editor.CREATE_TOOL_TRIANGLE,
                Editor.CREATE_TOOL_RECTANGLE
              ]
            },
            toolbarOptions: {
              reshapeVisible: true,
              cutVisible: true,
              mergeVisible: true
            }
          };


          var params = {settings: settings};    
          var myEditor = new Editor(params,'editorDiv');
          //define snapping options
          var symbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CROSS, 
            15, 
            new SimpleLineSymbol(
              SimpleLineSymbol.STYLE_SOLID, 
              new Color([255, 0, 0, 0.5]), 
              5
            ), 
            null
          );
          map.enableSnapping({
            snapPointSymbol: symbol,
            tolerance: 20,
            snapKey: keys.ALT
          });
    
          myEditor.startup();
        }
    });
    </script>
  </head>
    <body class="claro">
    <div id="main" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'" style="height:width:100%;height:100%;">
      <div data-dojo-type="dijit/layout/ContentPane" id="header" data-dojo-props="region:'top'">
        Cut Polygons
      </div>
      <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'left'" style="width: 300px;overflow:hidden;">
        <div id="templateDiv"></div>
        <div id="editorDiv"></div>
      </div>
      <div data-dojo-type="dijit/layout/ContentPane" id="map" data-dojo-props="region:'center'"></div>
    </div>
  </body>


</html>
0 Kudos
DerivenC
New Contributor II
Here's a better sample that doesn't work.  I took the layer information from the Wildfire feature layer and plugged it into a feature collection-based feature layer.  Doesn't work.  Doesn't call the geometry service or do anything.  So I can only assume that feature collection-based feature layers are simple not supported; because it must check during the cut, "is this a feature collection or not?"

*shrug*
0 Kudos
DerivenC
New Contributor II
Figured it out by delving into the API.  Had to modify the API to get it to work due to a bug in the editor code.  Unfortunately now I have to use a hosted API solution until it gets fixed in core.

Now to figure out reshapeVisible .. or not. 🙂
0 Kudos
DerivenC
New Contributor II
Here is the fix that I did from version 3.6 to 3.7.  This is the fix for 3.7 specifically.

In the file /js/esri/dijit/editing/Editor-all.js for the "esri/dijit/editing/tools/Cut" class' _onDrawEnd...

change...

var p = new l;p.geometry = a;
k.forEach(b, function (a, b) {
 this._settings.editor._selectionHelper.selectFeatures(,
  p, f.SELECTION_NEW, m.hitch(this, "_cutFeatures", a, p))
}, this)


to...

var p = new l;p.geometry = a;
var __extentBasedQuery = new l;
__extentBasedQuery.geometry = esri.geometry.fromJson(p.geometry).getExtent();
k.forEach(b, function (a, b) {
 this._settings.editor._selectionHelper.selectFeatures(,
  __extentBasedQuery, f.SELECTION_NEW, m.hitch(this, "_cutFeatures", a, p))
}, this)


To be honest, it's been a while since I made this bug fix.  So I cannot recall exactly why it works.  But it had something to do with passing an extent rather than the geometry itself.
0 Kudos
DerivenC
New Contributor II
Also by adding cutVisible:true to this example shows that it does not work correctly:

https://developers.arcgis.com/en/javascript/jssamples/ed_simpletoolbar.html

<!DOCTYPE html><html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <!--The viewport meta tag is used to improve the presentation and behavior of the samples 
      on iOS devices-->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Edit rivers and waterbodies</title>


    <link rel="stylesheet" href="http://js.arcgis.com/3.8/js/dojo/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.8/js/esri/css/esri.css" />
    <style>
      html,body{height:100%;width:100%;margin:0;overflow:hidden;}
      #map{
        padding:0;
      }
      #header{
        font-size: 1.1em;
        font-family: sans-serif;
        padding-left: 1em;
        padding-top:4px;
        color:#660000;
      }
      .templatePicker {
        border: none;
      }


      .dj_ie .infowindow .window .top .right .user .content { position: relative; }
      .dj_ie .simpleInfoWindow .content {position: relative;}
    </style>
    
    <script src="http://js.arcgis.com/3.8/"></script>
    <script>
      var map;
      
      require([
        "esri/map", 
        "esri/tasks/GeometryService",
        "esri/toolbars/edit",


        "esri/layers/ArcGISTiledMapServiceLayer",
        "esri/layers/FeatureLayer",


        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol",


        "esri/dijit/editing/Editor",
        "esri/dijit/editing/TemplatePicker",


        "esri/config",
        "dojo/i18n!esri/nls/jsapi",


        "dojo/_base/array", "dojo/parser", "dojo/keys",


        "dijit/layout/BorderContainer", "dijit/layout/ContentPane", 
        "dojo/domReady!"
      ], function(
        Map, GeometryService, Edit, 
        ArcGISTiledMapServiceLayer, FeatureLayer,
        SimpleMarkerSymbol, SimpleLineSymbol, 
        Editor, TemplatePicker,
        esriConfig, jsapiBundle,
        arrayUtils, parser, keys
      ) {
        parser.parse();       


        // snapping is enabled for this sample - change the tooltip to reflect this
        jsapiBundle.toolbars.draw.start = jsapiBundle.toolbars.draw.start +  "<br>Press <b>ALT</b> to enable snapping";
       
        // refer to "Using the Proxy Page" for more information:  https://developers.arcgis.com/en/javascript/jshelp/ags_proxy.html
        esriConfig.defaults.io.proxyUrl = "/proxy";    


        //This service is for development and testing purposes only. We recommend that you create your own geometry service for use within your applications. 
        esriConfig.defaults.geometryService = new GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
        
        map = new Map("map", { 
          basemap: "satellite",
          center: [-96.541, 38.351],
          zoom: 14,
          slider: false 
        });


        map.on("layers-add-result", initEditor);
       
        //add boundaries and place names 
        var labels = new ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer");
        map.addLayer(labels);


        var rivers = new FeatureLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Hydrography/Watershed173811/FeatureServer/1",{
          mode: FeatureLayer.MODE_ONDEMAND, 
          outFields: ['*']
        });


        var waterbodies = new FeatureLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Hydrography/Watershed173811/FeatureServer/0",{
          mode: FeatureLayer.MODE_ONDEMAND, 
          outFields: ['*']
        });


        map.addLayers([waterbodies,rivers]);


        function initEditor(evt) {
          var templateLayers = arrayUtils.map(evt.layers, function(result){
            return result.layer;
          });
          var templatePicker = new TemplatePicker({
            featureLayers: templateLayers,
            grouping: true,
            rows: "auto",
            columns: 3
          }, "templateDiv");
          templatePicker.startup();


          var layers = arrayUtils.map(evt.layers, function(result) {
            return { featureLayer: result.layer };
          });
          var settings = {
            map: map,
            templatePicker: templatePicker,
            layerInfos: layers,
            toolbarVisible: true,
            createOptions: {
              polylineDrawTools:[ Editor.CREATE_TOOL_FREEHAND_POLYLINE ],
              polygonDrawTools: [ Editor.CREATE_TOOL_FREEHAND_POLYGON,
                Editor.CREATE_TOOL_CIRCLE,
                Editor.CREATE_TOOL_TRIANGLE,
                Editor.CREATE_TOOL_RECTANGLE
              ]
            },
            toolbarOptions: {
              reshapeVisible: true,
              cutVisible: true
            }
          };


          var params = {settings: settings};    
          var myEditor = new Editor(params,'editorDiv');
          //define snapping options
          var symbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CROSS, 
            15, 
            new SimpleLineSymbol(
              SimpleLineSymbol.STYLE_SOLID, 
              new Color([255, 0, 0, 0.5]), 
              5
            ), 
            null
          );
          map.enableSnapping({
            snapPointSymbol: symbol,
            tolerance: 20,
            snapKey: keys.ALT
          });
    
          myEditor.startup();
        }
      });
    </script>
  </head>
  <body class="claro">
    <div id="main" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'" style="height:width:100%;height:100%;">
      <div data-dojo-type="dijit/layout/ContentPane" id="header" data-dojo-props="region:'top'">
        Edit Hydrography
      </div>
      <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'left'" style="width: 300px;overflow:hidden;">
        <div id="templateDiv"></div>
        <div id="editorDiv"></div>
      </div>
      <div data-dojo-type="dijit/layout/ContentPane" id="map" data-dojo-props="region:'center'"></div>
    </div>
  </body>
</html>




What you'll get is only a portion of the polygon, rather than two or more cut up pieces of the original polygon.  And the cut does not persist.
0 Kudos
derekswingley1
Frequent Contributor
Thanks for the additional info.

Running the editor sample on my machine with cutVisible: true does indeed work but there are two things that are probably contributing to you not seeing it work:


  • the services being used are slow, I've seen the cut operation take ten seconds or longer, unfortunately

  • pushing edits back to sampleserver3 requires a proxy


Once edits are pushed back to sampleserver3, the queries to show the new features can each take a few seconds so it takes additional time for the cut features to appear. When you say "And the cut does not persist", it sounds like edits aren't making their way back to the service on sampleserver3, which is expected if you aren't using a proxy when running locally.

Questions: 


  • how long are you waiting for the cut operation to complete?

  • do you see a request to the cut endpoint on tasks.arcgisonline.com?

  • do you have a proxy set up when running this sample locally?


Regarding using the cut operation with a feature collection and why your fix works:  when using a feature collection, we can only query by extents and not arbitrary lines/polygons. I'll take this use case back to the team and see what we want to do. At the very least, we should log something to the console saying the attempted query isn't supported when using a feature layer from a feature collection.
0 Kudos
DerivenC
New Contributor II

Questions: 

  • how long are you waiting for the cut operation to complete?

  • do you see a request to the cut endpoint on tasks.arcgisonline.com?

  • do you have a proxy set up when running this sample locally?

Regarding using the cut operation with a feature collection and why your fix works:  when using a feature collection, we can only query by extents and not arbitrary lines/polygons. I'll take this use case back to the team and see what we want to do. At the very least, we should log something to the console saying the attempted query isn't supported when using a feature layer from a feature collection.


To your bullet point questions, I believe you are spot on.  My use case doesn't utilize feature layers (and I'll explain that in a moment).  So the samples were more like guides for me to assess the editor's stability more than anything else.  When I noticed the lag, that told me that the cut tool didn't work.  I cannot recall if I tried my "bug fix" with a feature layer.  Maybe it works?

Ok .. so my mapping system does not use feature layers .. yet.  The reason for this is its own chapter, I would rather not divulge.  But the system is very sound and stable.  If ever you want to see it, let me know and we can do a WebEx demo.  Once you see it, you'll understand the complexity.  This system really pushes ArcGIS.  Lot of things customized and tweaked to reach the end goal.

But back to the feature layers.  This is my usage scenario:

  • User selects a layer to edit

  • Frontend gets the tile layer's info and creates a feature collection from it

  • User edits this feature collection.  (add, delete, edit, merge, cut, reshape)

  • When ready, the user commits the changes (or abandons them)

  • Frontend sends the changes to the backend service that updates the tile layer and recaches it

  • When done, the layer on the map is refreshed

Not everyone can see the beauty of this.  But for what my system needs, it works wonders.  This is why I always pull down the API and make my changes.  It's worth the hassle.  The cut tool works perfectly.  (Please don't take it away from me. heh)  Blame Kelly for opening my eyes to feature collections.  They are amazingly useful!
0 Kudos
DerivenC
New Contributor II
One more thought: proxy.  My mapping system relies heavily on proxy.  Security reasons.  But I don't have the problem with lag and delays because I use a multi-subdomain solution which originally came from ESRI (looks like the blog post is dead).  Something I always have to fight when ArcGIS for JS has some drastic change.  I posted how to get it working here:

http://forums.arcgis.com/threads/87739-Option-to-Disable-CORS-or-Use-withCredentials?p=310920&viewfu...

Multiple subdomaining is the best solution for ArcGIS/JS maps.  Hands down.
0 Kudos