SnapManager not drawing point at the snap

1369
10
05-14-2018 02:25 PM
ElizabethMiller
New Contributor III

SnapManager fails to complete snap in Javascript

I am having a problem similar to the one Tyler described but the previous post did not solve my problem. I have a custom widget with a click event that uses the snapping manager to guide the user to place a point along a road. The road is in a feature service and I am using the draw toolbar to create the point. Snapping at first seems to be working great to the point of creating the little blue X that is constrained to follow the road, however, when the user actually clicks the point will be created at the actual click point and not where the blue X is showing.

How can I make the snapped point graphic actually be created on the line where the blue X seems to indicate it will be?

Right now I am adding the featurelayer to the map every time the user clicks, which is not practical in the long run, but I am just trying to get it to work.

Thank you for any help in solving this problem.

myfunction: function (evt) {


var parcelsLayer = new FeatureLayer(
"http://myurl/MapServer/0",
{
mode: FeatureLayer.MODE_ONDEMAND,
outFields: ["*"]
});
this.map.addLayer(parcelsLayer);

var snapManager = this.map.enableSnapping({
tolerance: 20,
alwaysSnap: true
});


var layerInfos = [{
layer: parcelsLayer
}];

snapManager.setLayerInfos(layerInfos);

var tb;
tb = new Draw(this.map);
tb.activate(Draw["POINT"]);

var line = new SimpleLineSymbol();
line.setColor(new Color([168, 0, 0, 1]));
line.setWidth(2);
var marker = new SimpleMarkerSymbol();
marker.setOutline(line);
marker.setStyle(SimpleMarkerSymbol.STYLE_X);

var graphic = new Graphic(evt.mapPoint, marker);

this.map.graphics.add(graphic);


}

0 Kudos
10 Replies
RobertScheitlin__GISP
MVP Emeritus

Elizabeth,

   It looks like you are using a map click event when you are using:

evt.mapPoint

The snapping happens to the Draw toolbars graphic result geometry. It does not adjust the click events geometry.

So on the DrawEnd event you would get the graphic and use its geometry that has been snapped:

var graphic = new Graphic(graphic.geometry, marker);
0 Kudos
ElizabethMiller
New Contributor III

This is not coming together for me. I can't pass the draw point because it's not a graphic, and it's not an evt. What is it? I know this isn't right, but I am not able to grab the draw point. if I try this, I get the error "cannot read property geometry of undefined."

var toolbar;
 toolbar = new Draw(this.map);
 toolbar.activate(Draw["POINT"]);
toolbar.on("draw-end", lang.hitch(this, 'onDrawEnd'));

onDrawEnd: function(){
var line = new SimpleLineSymbol();
 line.setColor(new Color([168, 0, 0, 1]));
 line.setWidth(2);
 var marker = new SimpleMarkerSymbol();
 marker.setOutline(line);
 marker.setStyle(SimpleMarkerSymbol.STYLE_X);
 
 var graphic = new Graphic(graphic.geometry, marker);
 this.map.graphics.add(graphic);
 },

I also tried using something like this but get an error 'cannot read property  'add' of undefined." It does not seem to want to use screenPoint. I'm not sure if either of these methods is the right way to go.

var deferred = this.map.snappingManager.getSnappingPoint(evt.screenPoint);
 deferred.then(function(value){
 var point;
 if(value !== undefined){
 point = value;
 console.log(point);
 } else {
 point = evt.mapPoint;
 }
 console.log(point);
 var graphic = new Graphic(evt.mapPoint, marker);
 this.map.graphics.add(graphic);
 });
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Elizabeth,

   You need to capture the draw end event data to use it:

onDrawEnd: function(evt){
  var line = new SimpleLineSymbol();
  line.setColor(new Color([168, 0, 0, 1]));
  line.setWidth(2);
  var marker = new SimpleMarkerSymbol();
  marker.setOutline(line);
  marker.setStyle(SimpleMarkerSymbol.STYLE_X);
 
  var graphic = new Graphic(evt.geometry, marker);
  this.map.graphics.add(graphic);
},
0 Kudos
ElizabethMiller
New Contributor III

Thanks again! Maybe I'm missing some other piece of code but for me that still places the point where the user clicks and not along the line where the blue snap is showing, so it is like not using the snapping manager at all. 

Here is a fiddle example I found of what I am trying to do Add Graphic to Snap Point - JSFiddle , but I'm still having trouble adapting it to a WAB widget format. I'm using the following but getSnappingPoint does not seem to return a value.  

var deferred = map.snappingManager.getSnappingPoint(evt.screenPoint);

 deferred.then(function(value){
 var point;
 
 if(value !== undefined){
 point = value;
 
 } else {
 point = evt.mapPoint;
 }
 
 var graphic = new Graphic(point, sms);
 this.map.graphics.add(graphic);
 }, function(error){
 console.log('Error');
 });
 },‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Elixabeth,

   It would be :

var deferred = this.map.snappingManager.getSnappingPoint(evt.screenPoint);

notice "this.map" is how you get the map object in a widget.

0 Kudos
ElizabethMiller
New Contributor III

Ugh, I'm so sorry I included that mistake in my example. I have in fact been using the correct format of "this.map." 


The problem is that nothing happens after the "deferred.then." "Value" is always "undefined." It seems like snappingManager.getSnappingPoint isn't working. I do have valid coordinates for evt.screenPoint though.

Are there any other prerequisites for getting snappingManager or deferred to work? I have them both loaded in my widget's define().

var deferred = this.map.snappingManager.getSnappingPoint(evt.screenPoint);
 
 deferred.then(function(value){
 var point;
 
 console.log("value is: " + value);
 //nothing happens after this

 if(value !== undefined){
 point = value;
 
 } else {
 point = evt.mapPoint;
 }
var graphic = new Graphic(point, marker);
 this.map.graphics.add(graphic);
 
 }, function(error){
 console.log('Error');
 });
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Elizabeth,

  have you checked to be sure this.map.snappingManager is not null?

0 Kudos
ElizabethMiller
New Contributor III

It seems to be good. I am getting lots of attributes back for it and they match the attributes I get back when I look at the map.snappingManager in the JSfiddle example.

I compared the deferred object in my example and the JSFiddle example too. I don't see any differences except that the example contains a valid array in the results attribute (see below).

Also, I am now using the sample esri feature service layer instead of my own just to rule out any problem with that.

The error message I get in the console now is:

Uncaught TypeError: Cannot read property 'offset' of undefined
 at Object.getSnappingPoint (SnappingManager.js:7)
 at Object.<anonymous> (Widget.js?wab_dv=2.6:338)
 at Object.<anonymous> (init.js:63)
 at Object.<anonymous> (init.js:655)
 at Object.c [as onDrawEnd] (init.js:119)
 at Object._drawEnd (draw.js:18)
 at Object._onClickHandler (draw.js:31)
 at Object.<anonymous> (init.js:63)
 at Object.c [as onClick] (init.js:119)
 at Object._fire (init.js:1299)

Here's how the example's deferred result looks:

Here's mine!

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Elizabeth,

   What about the evt.screenPoint is that a valid object?

0 Kudos