PopUp on FeatureLayer with severeal overlapping graphics

772
5
Jump to solution
09-21-2017 05:57 AM
MichaelLodes2
Occasional Contributor

Hi all,

I am working with JavaScript 4.4. With a FeatureLayer from URL clicking on overlapping graphics, the popUpTemplate shows all popUps (1 to 4... for example). Using a FeatureLayer with client side graphics ("source: features"), the popUpTemplate shows just the information about the feature lying on the top of them. Is it a bug?

You can see my code below. Compare the two layers defined in my code by commenting and uncommenting please.


Best Regards,

Michael

require([
  "esri/Map",
  "esri/views/MapView",
  "esri/layers/FeatureLayer",
  "esri/renderers/SimpleRenderer",
  "esri/symbols/SimpleMarkerSymbol",
  "esri/geometry/Point",
  "dojo/domReady!"
], function(
  Map, MapView, FeatureLayer, SimpleRenderer, SimpleMarkerSymbol, Point
) {


var features = [      
    {             
    
     geometry: new Point({
        latitude: 38.726941,  
        longitude: -101.883768

      }),   
      attributes: {
        ObjectID: 1
        
    }
  },
          
          {             
    
     geometry: new Point({
        latitude: 38.711841,  
        longitude: -101.883668

      }),   
      attributes: {
        ObjectID: 2
        
    }
  },

{             
    
     geometry: new Point({
        latitude: 38.781641,  
        longitude: -101.883968

      }),   
      attributes: {
        ObjectID: 3
    }
  },
{             
    
     geometry: new Point({
        latitude: 38.726991,  
        longitude: -101.883748

      }),   
      attributes: {
        ObjectID: 4
    }
  }
                
];



var renderer = new SimpleRenderer({
    
     symbol: new SimpleMarkerSymbol({
        color: [139,69,19],
        size: "15pt",
        outline: { // autocasts as new SimpleLineSymbol()
          color: [255, 255, 255],
          width: 2
        }
      })
    
    });


//  var layer = new FeatureLayer({
//
//    url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/US_counties_employment_2016/Featur...",
//    outFields: [ "CIVLBFR_CY", "NOT_LABORFORCE_16", "COUNTY", "STATE", "POP_16UP", "UNEMPRT_CY", "UNEMP_CY", "EMP_CY" ],
//    renderer: renderer,
//    popupTemplate: {
//      title: "Title",
//      content: "Test"
//  }
//  });

var layer = new FeatureLayer({
    fields: [
        {
        name: "ObjectID",
        alias: "ObjectID",
        type: "oid"
        }
    ],
    objectIdField: "ObjectID",
    geometryType: "point",
    source: features,  
    renderer: renderer,
    popupTemplate: {
      title: "Title",
      content: "Test"
    }
  
});




  var map = new Map({
    basemap: "gray",
    layers: [ layer ]
  });

  var view = new MapView({
    container: "viewDiv",
    map: map,
    center: [-101.883768, 38.726941],
    zoom: 6
  });





});
0 Kudos
1 Solution

Accepted Solutions
ThomasSolow
Regular Contributor

Yes, this is a bug.

You can solve it by adding something like this:

// where layer is your FeatureLayer
layer.createQuery = function(){
  let q = layer.__proto__.createQuery.call(layer);
  q.outFields = null;
  q.where = null;
  return q;
}

You'd have to do this for each feature layer you create that you want to behave like this.  A better solution would probably be to create a subclass that inherits from FeatureLayer and fix this method there and then use that class instead of FeatureLayer, like this:

var FL2 = FeatureLayer.createSubclass([], {
  createQuery: function(){
    var= this.inherited(arguments);
    q.outFields = null;
    q.where = null;
    return q;
  }
});

var layer = new FL2({...});

Keep in mind that you're changing how createQuery behaves and that may screw something else up, although it's probably safe to do for client-side feature layers.

View solution in original post

0 Kudos
5 Replies
ThomasSolow
Regular Contributor

Yes, this is a bug.

You can solve it by adding something like this:

// where layer is your FeatureLayer
layer.createQuery = function(){
  let q = layer.__proto__.createQuery.call(layer);
  q.outFields = null;
  q.where = null;
  return q;
}

You'd have to do this for each feature layer you create that you want to behave like this.  A better solution would probably be to create a subclass that inherits from FeatureLayer and fix this method there and then use that class instead of FeatureLayer, like this:

var FL2 = FeatureLayer.createSubclass([], {
  createQuery: function(){
    var= this.inherited(arguments);
    q.outFields = null;
    q.where = null;
    return q;
  }
});

var layer = new FL2({...});

Keep in mind that you're changing how createQuery behaves and that may screw something else up, although it's probably safe to do for client-side feature layers.

0 Kudos
MichaelLodes2
Occasional Contributor

Hi Thomas,

your solution works great on the upper code snippet.

I integrated your solution into my whole code and realized that it still doesn't work.

I think it has something to do with the projection of my points with GeometryService and then pushing them into the layer.

Can you say where the problem is?

<script>
    require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/FeatureLayer",
      "esri/Graphic",
      "esri/geometry/Point",
      "esri/symbols/SimpleMarkerSymbol",
      "esri/tasks/GeometryService",
      "esri/tasks/support/ProjectParameters",
      "esri/geometry/SpatialReference",
      "esri/widgets/Compass",
      "esri/widgets/BasemapGallery",
      "esri/widgets/Track",
      "esri/renderers/SimpleRenderer",
      "esri/geometry/SpatialReference",
      "esri/widgets/Search",
      "esri/widgets/Expand",
      "esri/widgets/LayerList",
      "dojo/domReady!"
    ], function (Map, MapView, FeatureLayer, Graphic, Point, SimpleMarkerSymbol, GeometryService, ProjectParameters, SpatialReference, Compass, BasemapGallery, Track, SimpleRenderer, SpatialReference, Search, Expand, LayerList
) {


      var geoSvc = new GeometryService({
      url: 'https://utility.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer'
    });
    
    
        //define mapCenter (by default in admin.xml. If map should center a certain point (get zoomToObject parameter from URL), zoom to given x and y values
       var mapZoom = 10;
       var mapCenter = [10.734112, 48.174298];
     
      var map = new Map({
        basemap: "osm"
      });
      
    
        var view = new MapView({
         center: mapCenter,
         container: "viewDiv",
         map: map,
         zoom: mapZoom
        });

// renderer

    var sr = new SimpleRenderer({
     symbol: new SimpleMarkerSymbol({
        color: [226, 119, 40],
        size: "15pt",
        outline: { // autocasts as new SimpleLineSymbol()
          color: [255, 255, 255],
          width: 2
        }
      })
   });
    

      // create new layer, starts emtpty
   var lyr = new FeatureLayer({
     fields: [
       {
         name: "ObjectID",
         alias: "ObjectID",
         type: "oid"
       }
    ],
    objectIdField: "ObjectID",
    geometryType: "point",
    title: "Hundestation",
    spatialReference: { wkid: 102100 },
    source: [],
    popupTemplate: {
      title: "Title",
      content: "Test"
    },
    minScale: 1000000,
    maxScale: 1,
    renderer: sr //custom renderer
  });
  
lyr.createQuery = function(){
  let q = lyr.__proto__.createQuery.call(lyr);
  q.outFields = null;
  q.where = null;
  return q;
} 
  

  
  // bugfix for not displaying several popUpTemplates

  
 
var sizeCrownSymbol = 0;          
var feature = [ 
    new Point({
      x: 4408069.551,
      y: 5338730.568,
      spatialReference: { wkid: 31468 }
    })


]; 
projectPoints (geoSvc, feature, lyr, "10", "Lagebeschreibung: Kroengelände", sizeCrownSymbol);          

var feature = [ 
    new Point({
      x: 4408681.069,
      y: 5338984.143,
      spatialReference: { wkid: 31468 }
    })


]; 
projectPoints (geoSvc, feature, lyr, "11", "Lagebeschreibung: Holzheystraße", sizeCrownSymbol);          

var feature = [ 
    new Point({
      x: 4408132.398,
      y: 5339858.609,
      spatialReference: { wkid: 31468 }
    })


]; 
projectPoints (geoSvc, feature, lyr, "12", "Lagebeschreibung: Breitlehenstraße", sizeCrownSymbol);          
                            
         
                            

          

        

map.add(lyr);



    
       // project each geomtry, then add to layer's source
   function projectPoints(geoSvc, geometries, lyr, primarykey, popUpAttributes, sizeCrownSymbol){
       
        geoSvc.project({
          geometries: geometries,
          outSpatialReference: SpatialReference.WebMercator
        }).then(geometries => {
          let features = geometries.map((geometry, idx) => {
            return new Graphic({
              geometry: geometry,
              attributes: {
                objectID: idx - 1,
                sizeCrownSymbol: sizeCrownSymbol
                
              }
            
            });
          });

          features.forEach(f => lyr.source.push(f));
          
          
          
        });
    }

    

    
    
    
    });
  </script>

Best Regards

Michael

0 Kudos
ThomasSolow
Regular Contributor

Hey Michael,

Try using outSR instead of outSpatialReference in your calls to project().  outSpatialReference was added in 4.4, but you're using 4.3 in that sample.

0 Kudos
Pierre-MatthieuPETILLOT
New Contributor

Hi all,

If I take the same code with v4.8, I have the same initial problem, even with the solution given by Thomas :

// where layer is your FeatureLayer
layer.createQuery = function(){
  let q = layer.__proto__.createQuery.call(layer);
  q.outFields = null;
  q.where = null;
  return q;
}

(this solution works great in v4.4 environment).

Do you have an other solution ?

Best regards.

0 Kudos
ThomasSolow
Regular Contributor

Hi Pierre,

It was a bad idea for me to have mentioned that approach (for exactly this reason, among others). 

A better approach would be creating your own function for querying graphics and feeding the results into the popup.  You can see an example of how to do this here (scroll down a bit for two examples).

In this case, you could write a function to query for all graphics in your layer using an extent centered on where you click: here's an example based on your sample.  The downside of this approach is that you need to pick a number of pixels to search in, which isn't ideal, but it works (I set it to 10 in that example, but realistically it should be adjusted based on your symbol size).

Alternatively, I checked your sample against the upcoming release of the API and it seems to work perfectly there.