Select to view content in your preferred language

Auto-panning map so that infowindow is fully visible

15092
14
07-15-2011 12:17 PM
LisaEidson
Occasional Contributor
I'm looking for some guidance on how to make my map pan when an infowindow is launched (result of an identify) if the infowindow is not completely within view.

Take this example:

Here's my map prototype: satellite Bing layer with wilderness boundaries ArcGIS dynamic service that my colleague maintains overlayed.


When you click within the Absaroka-Beartooth Wilderness boundary you get the infowindow with the results of an identify (grabs and ID number then outputs data from an array). Although I've used tabs to ensure that the infowindow can contain a fair amount of information but isn't too large, depending on where you click it will often be partially obscured (with the rest being outside the current map view).


If the infowindow isn't fully shown, I want the map to pan so that it is. So in this example, I want the map to pan to the below view.


This seems like a pretty useful operation (Google Maps api, for example, automatically takes care of this) but I haven't been able to find any examples or anything about how to do it. So any assistance would be much appreciated. Thanks in advance.

The code for the prototype map from which I took the above screen snaps is available on my website at: http://www.wilderness.net/mapTest_esri3_strip.htm
14 Replies
StevenHaslemore
Regular Contributor
I'm having an issue with the infoWindow location updating after the map.infoWindow.show(..) line.

The code in this thread is working perfectly and places the infoWindow where it should be, but the event is then propagating into the esri api code, producing exceptions in onAnimate, and subsequently updating the infoWindow location to incorrect locations.

I've tried to stop this behavior with

dojo.connect(disruptionsPolyline, "onClick", function(a){
    dojo.stopEvent(a);
    addInfoWindowCode(a);
});


Another curiosity is, if the infoWindow has multiple features in it, switching between them will update the infoWindow to the correct location.

Any thoughts appreciated.

Thanks,
Steven
0 Kudos
DianaBenedict
Frequent Contributor
Personally, I got so frustrated with the InfoWindow (not displaying fully in the area of interest, jumping around when you go to the next feature, etc...) that I ended up using a dojo FloatingPane instead.  I had to do a lot more coding and still have some "kinks" to work out but the experience is much nicer. Unfortunately I can not show you all a working sample because our test website is behind a firewall but I can submit some sample code to get you started with at least setting up the floating pane correctly, It will then be up to you to set up the content within the floating pane.


function createFloatingPane(floatingPaneId, paneTitle, tabContainerID) {
//  /*** floating panes ************************************************/
  //add a dock
  //I don't use the dock for user interaction. You could however make it a region in the container or position it somewhere in the app
  //If you display the dock, much like the floating panes, you'll need to do some css and dojo work to make it look and function right
  //So why create a dock? If you don't, dojo will do it for you and you won't like the result (see the example at http://dojotoolkit.org/reference-guide/1.7/dojox/layout/FloatingPane.html#dojox-layout-floatingpane)
  var dock = new dojox.layout.Dock({
    id: "dock",
    style: 'position:absolute; bottom:0; right:0; height:0px; width:0px; display:none; z-index:0;'
    //class: "dockClass"
  }, dojo.create('div', null, dojo.body()));

  //add a floating pane
  var floatingPaneAttributes = new dojox.layout.FloatingPane({
    id: floatingPaneId,
    title: paneTitle,
    resizable: true, //allow resizing
    closable: true, //we never want to close a floating pane - this method destroys the dijit
    dockable: true, // yes we want to dock it
    dockTo: dock, //if you create the floating pane outside of the same function as the dock, you'll need to set as dijit.byId('dock')
    style: 'position:absolute;top:130px;left:402px;width:420;height:450px;visibility:hidden;z-index:999 !important'
    //class: "foatingPaneClass"
    //style: 'position:absolute;top:130px;left:402px;width:240px;height:320px;visibility:hidden;z-index:999 !important'
    //you must set position:absolute; and provide a top and left value (right and bottom DO NOT WORK and will cause the floating pane to appear in strange places depending on browser, for example 125684 pixels right)
    //Why top and left? The position of a floating pane is a relationship between the top-left corner of dojo.window and the top-left corner of the dijit
    //you must also set a height and width
    //z-index is mainly irrelavant as the dijit will control its own z-index, but I always set it to 999 !important to avoid the occasional and mysterious problem of the title and content panes of the floating pane appearing at different z-indexes
  }, dojo.create('div', null, dojo.body()));

  floatingPaneAttributes.resize({ w: 420, h: 450 });

  //add the TabContainer to the Floating Pane
  var tc = new dijit.layout.TabContainer({
    id: tabContainerID,
    tabPosition:'bottom',
    style: "height: 100%; width: 100%;",
    class: "claro"
  });
         
  // place the tabcontainer into content pane.
  // IMPORTANT: SINCE FLOATING PANE IS NOT A "Container", WE MUST ATTACH THE TABCONTAINER TO ITS DOM NODE.
  tc.placeAt(floatingPaneAttributes.containerNode);
  // call startup to layout everyone.
  floatingPaneAttributes.startup();

  //Override the close function so the control does not get destroyed
  floatingPaneAttributes.close = function () {
    floatingPaneAttributes.minimize();
    _isFloatingPaneVisible = false;
    clearSelectedFeatureLayers();
    map.graphics.clear();
    toolbarOption = "None";
  };

  //connect the events
  dojo.connect(floatingPaneAttributes, 'onFocus', function () {
    dijit.byId(floatingPaneId).bringToTop()
  });

  dojo.connect(floatingPaneAttributes, 'onShow', function () {
    dijit.byId(floatingPaneId).bringToTop();
    drawToolbar.deactivate();
    map.enableMapNavigation();
    toolbarOption = "ModifyAttributes"
    map.disableScrollWheelZoom();
    navToolbar.activate(esri.toolbars.Navigation.PAN);
  });
}


Note that I had to override the floatingPane.close method ... this is a bit of a hack. I know that there is a better way to do this but for now it seems to work.  I think the way to do this is to declare a custom floating pane and override my own close functionality but I am not that verse with Dojo to create a custom widget.  If someone wants to play with that and show me a better way that would be great!

Also, note that I connected some events to handle and I also created a TabContainter within the floating pane ...obviously you can add whatever content pane you wish. But the trick to get it load correctly was the use of the .containerNode (tc.placeAt(floatingPaneAttributes.containerNode); )

After I got this to work I was able to hook up a highlight selected fetaure so that the user can see which feature we are currently viewing.  I just added a simple graphic to the map with highlight color or interest.

Like I said lots more work to do but it seems to work mostly OK.
0 Kudos
SteveCole
Honored Contributor
@Diana-

Do you have a screenshot of what that looks like that you could share?

I'm in the same boat and the code provided earlier in this thread didn't work well for me and my own kludgy code to "sense" where my feature is on the map and adjust accordingly is almost more trouble than it's worth.

I did submit an enhancement idea for ESRI to add an option to map creation so that the API takes care of all this. It's ESRI's code and they know it better than any one of us. Vote if you're so inclined.
0 Kudos
DianaBenedict
Frequent Contributor
@Diana-

Do you have a screenshot of what that looks like that you could share?

I'm in the same boat and the code provided earlier in this thread didn't work well for me and my own kludgy code to "sense" where my feature is on the map and adjust accordingly is almost more trouble than it's worth.

I did submit an enhancement idea for ESRI to add an option to map creation so that the API takes care of all this. It's ESRI's code and they know it better than any one of us. Vote if you're so inclined.


Attached is a screen shot of the AttributeInspector that I have hooked up to a div in the 1st tab container.

So esentially what I did is the following:
1) create the floating panel as described in previous thread
2) used the AttributeInspector Dijit and set up the layerInfos and FieldInfos as needed
3) add the tab page(s) as needed and attached the AttributeInspector to the tab page (see example code below)
4) statup the attribute inspector dijit
NOTE: I would think that you could use the InfoTemplate object or something else to set up your content as needed in lieu of the attribute inspector (I think) and just attach the content to the tab container (tab page)
5) set up a map.onClick event to select my features of interest --> since I am using an AttributeInspector, I do not need to setFeatures to the attribute Inspector ..but here is where you would need to attach the content to the selected features (somehow)
6) onSelection complete --> show the floating pane

//tabObjectArray is an array of  custom object with the following properties
// { TabOrder: tabConfig.GroupOrder, TabTitle: tabConfig.Title, TabContent: "<div id='" + tabConfig.DivHolderId + "' ></div><br /><br />" }

function addTabPagesToTabControl(tabControl, tabObjectArray) {
  require(["dojo/_base/array", "dijit/layout/ContentPane"], function (array, contentPane) {
    if (tabControl.hasChildren()) {
      var tabControlChildren = tabControl.getChildren();
       //work still in progress, need to remove all child nodes (I think)
      alert("tabcontrol has children count = " + tabControlChildren.length);
    };
    array.forEach(tabObjectArray, function (tabObject) {
      var tabPage = new contentPane({
        title: tabObject.TabTitle,
        content: tabObject.TabContent
      });
      tabControl.addChild(tabPage);
    });
  });
}

function showAttributePane() {
  var attributePane = dijit.byId(_floatingPaneId);
  if (attributePane) {
    disableToolbars();
    attributePane.show()
  }
}


Like I said, I still need to work through some more stuff here. I don't even have a real framework set up yet. Currently I am just testing different options and figuring out the best way to do things based on our requirements. Then I will worry about getting it all set up correctly within a real framework ... so the code might seem a bit scattered at the moment.
0 Kudos
Hernando_CountyProperty_Apprai
Regular Contributor

Thank you so much.  This is just what I was looking for.

0 Kudos