Select to view content in your preferred language

Selecting graphics programmatically

1845
5
11-07-2013 05:35 AM
AdamReiter
Emerging Contributor
I understand this isn't exactly a rare question here, but I still haven't found an ideal solution.  What I want to do is have exactly the same behavior when I select a graphic on the map as when I select it from a list outside the map, ie the InfoWindow pops up using the InfoTemplate/attributes of the graphic I've specified and the graphic gets the "selected" icon (the blue square).

It isn't too difficult to hack around this:
//gfx is a graphic that comes from elsewhere...
map.infoWindow.setTitle(gfx.getTitle());
map.infoWindow.setContent(gfx.getContent());
map.infoWindow.show(gfx.geometry);


However, this doesn't produce the same behavior as a click.  The map's InfoWindow "onShow" event fires but the event has no graphic attached, and if you had a graphic selected already, the blue selected icon on the map stays where it is and doesn't attach to the new graphic.

Is there something I missing, or is the best way to simply stop using InfoTemplates entirely and rely on infoWindow.show?
0 Kudos
5 Replies
TracySchloss
Honored Contributor
I'm not sure if I'm following your question exactly, but the short answer is you ought to be able to use a mix of infoTemplate and infoWindow.show.

You mention clicking on a list, how are you determining which feature that it goes with, featureLayer.selectFeatures? QueryTask? 

When I'm selecting from something external to the map, it's almost always a grid.  I select the feature from the map based on a queryTask.   To see the highlighted symbol, I've been creating a graphic, using the geometry of the results of that query, adding it right before I set the infoWindow content.  And at the top of that function I always hide the infoWindow and clear the map graphics, so I don't have the symbol from a previous click.
0 Kudos
AdamReiter
Emerging Contributor
Sorry I'm not being very clear.  I forgot to stress that in this case the Graphic is already on the map, I'm just trying to highlight it.  I spent some time trying to figure out how to trick the map into thinking I'd clicked on a graphic and I was hoping there was a more straightforward way to do it.

What I'm really looking for is something like:
map.selectGraphic(gfx); //not a real function

Where the graphic is already on the map.  I can pretend the graphic is selected by repopulating and showing the info window at the Graphic's point, but it seems silly to go through all that when it's such a straightforward thing to want to do.
0 Kudos
TracySchloss
Honored Contributor
That sounds like wishful thinking.  To me, graphics are all just something short lived, so I'm not surprised to have to continually recreate and clear them as I go.
0 Kudos
AdamReiter
Emerging Contributor
Maybe there's a better way to accomplish what I'm trying to do then.  Here's the basic workflow:

1.) User uses the DrawTool to query a location on the map.
2.) Service returns a result list.
3.) Graphics are placed on the map in the drawn query area AND items are placed in an HTML list corresponding to the graphics.

The user then needs to be able to either select the graphic on the map OR the the item in the list, with the same result: the InfoWindow being opened and the graphic being highlighted.  I'm keeping a map of the graphics with keys corresponding to the list items for easy recovery.

Here's #3 if it helps:
//results returned
for (var index in results) {
  result = results[index];

  attr = {
    "name": result.name,
    "lon": result.longitude,
    "lat": result.latitude
  };

  template = {
     title: "${name}",
     body: infoWindowMinimizedFragment //HTML fragment
  };
   
  pt = new Point(attr.lon, attr.lat);
  gfx = new Graphic(pt, symbols.resultSy, attr, new InfoTemplate(template.title, template.body));
    
  resultsLayer.add(gfx);
  graphicsIndex[result.name] = gfx;


Then, when the use clicks an item in the list:
var gfx = graphicsIndex[event.target.innerHTML];
 
//map.selectGraphic(gfx);  wishful thinking

map.infoWindow.setTitle(gfx.getTitle());
map.infoWindow.setContent(gfx.getContent());
map.infoWindow.show(gfx.geometry);

With this setup I get the problems stated in the original post: no graphic in the InfoWindow show event and the built-in blue graphic highlight doesn't update (which means I either have to disable it or scrap InfoTemplates entirely).

If there's a better, more robust way to do this I'd love to find it.  I've run into this problem several times in several different ESRI applications.
0 Kudos
TracySchloss
Honored Contributor
I don't think there's a really elegant way to do it, but you should be able to at least have the graphic appear highlighted on the right feature.  There are multiple ways to define infoTemplates, popups etc, so I don't know if the way I go about it fits into what you have done or not.  You may have all this established in your code already, but here's how I go about it:

I like a large yellow circle with a transparency on it so it stands out.  I define my symbol at beginning, along with my popup, which I use in my map definition.

 highlightMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 22,
        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
        new Color([255,255,0]), 2),
        new Color([255,255,0,0.5]));
        var popup = new Popup({ 
          fillSymbol: new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255,200,0]), 2), new Color([255,255,0,0.30])) ,
        markerSymbol:  highlightMarkerSymbol
        }, dojo.create("div")); 
       
map = new Map("mapDiv", {
          basemap: "topo",
          center: [-92.593, 38.5],
          infoWindow:popup,
          sliderPosition: "top-left",
          sliderStyle: "large",
          zoom: 7
        });


I'm not using a featurelayer, I'm just defining the infoTemplate in the results handler of my Identify Task.  Since I'm clicking on the map, and I have my infoWindow defined as popup in my map constructor, this is giving me my highlight symbol automatically without explicitly telling it to 'draw a graphic'.  This example looks a little different because I have my Identify set as deferred with 'promise/all' so I had to also manage which layer my identify was coming from

    var formatResults = arrayUtils.map(results, function(result){        
        var feature = result.feature;
        var layerName = result.layerName;           
        feature.attributes.layerName = result.layerName;
        feature.setInfoTemplate(generateInfoTemplate);
        generateInfoTemplate.setTitle("Layer Information");//don't need a graphic, it's drawing from the infoWindow:popup in the map constructor
        return feature;            
     });
         
    if (formatResults.length === 0) {
        map.infoWindow.clearFeatures();
    } else {
        map.infoWindow.setFeatures(formatResults);
        map.infoWindow.show(idPoint);
    }  
{/CODE]

When I'm outside the map, in my grid, the items in that list aren't aware they are associated with a graphic, they're just data.   But the data includes the objectID, so I'm running a query to get back to what the corresponding graphic is.  This is a function that needs to work from one of two grids I have, so there's extra lines and incoming parameters here:

    //highlights the feature when the user selects from the grid
 function highlightFeatureFromGrid(event, dGrid, qTask) {
   app.map.graphics.clear();
   app.map.infoWindow.hide();
   var row = dGrid.row(event);
   var query = new Query();
   var objid = [row.data.objectid];
   query.where = "OBJECTID = " + objid; 
   query.returnGeometry = true;
   query.outFields = ["*"];
   query.outSpatialReference = spatialReference;
   qTask.execute(query, function (results) {
        var feature = results.features[0];//should only be on feature by that id in that layer
        var graphic;  
        if (results.displayFieldName == 'VENDORID'){
            feature.setInfoTemplate(venInfoTemplate);
        }else {
            feature.setInfoTemplate(offSatInfoTemplate);
        }

         app.map.centerAndZoom(feature.geometry, 12);
         graphic = new Graphic(feature.geometry, highlightMarkerSymbol,feature.attributes, feature.infoTemplate);                             

        app.map.graphics.add(graphic);  
        app.map.infoWindow.setContent(feature.getContent());
        app.map.infoWindow.setTitle(feature.getTitle());
        app.map.infoWindow.show(feature.geometry);                   
    });
}    


Assuming that gfx in your example is an esri Graphic and not something else, you ought to be able to just construct and draw a new Graphic over the top using the parameters of the existing one.

It ain't elegant, but it works.
0 Kudos