featureLayers in MapServices Drawing REALLY Slow.. Why?

1470
11
10-05-2010 12:22 PM
AlexGray
New Contributor
I am working on creating an online map using ESRI mapservices as a basemap and existing mapservices on our arcserver.. The problem I am running into is that the mapservices we have here are really slow to draw.. They do draw however.

I have no access the mapservices themselves to change them only to reference them. What might be causing this issue? Below is my unfinished code for the page...

I am working on this using the ESRI Javascript API... Any help is greatly appreciated.

     dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require("dijit.layout.AccordionContainer");
      dojo.require("esri.dijit.Legend"); 
      dojo.require("esri.map");
      dojo.require("esri.layers.FeatureLayer");
      dojo.require("dijit.form.Button");
      dojo.require("dijit.Dialog");
      dojo.require("esri.arcgis.utils");
      dojo.require("esri.toolbars.navigation");
      dojo.require("dijit.Toolbar");
    
      var mapLayers = [];
      var map;
       var legendLayers = [];
       var navToolbar;
      
       
      function init() {
        var extent = new esri.geometry.Extent({"xmin":-78.21364,"ymin":38.9500003,"xmax":-78.31262,
              "ymax":39.49891569,"spatialReference":{"wkid":4269}});
        map = new esri.Map("map", { extent: esri.geometry.geographicToWebMercator(extent)});
        dojo.connect(map, "onLoad", initOperationalLayer);
    
        var imagery = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
        map.addLayer(imagery);
        mapLayers.push(imagery);
      
      var usaTopo = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/USA_Topo_Maps/MapServer");
      map.addLayer(usaTopo);
      mapLayers.push(usaTopo);
      
      var worldStreet = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer");
      map.addLayer(worldStreet);
      mapLayers.push(worldStreet);
      
      
      navToolbar = new esri.toolbars.Navigation(map);
        dojo.connect(navToolbar, "onExtentHistoryChange", extentHistoryChangeHandler);
            
      dojo.connect(map, "onExtentChange", showExtent);
      }
       
       
      function initOperationalLayer(map) {
        var parcelContent = "<br /><b>Owner</b>: ${CAMRAGIS.MLNAM}" +
                      "<br /><b>Rec#</b>: ${PARCEL.RECNUM}" +
           "<br /><b>Acres</b>: ${CAMRAGIS.MACRE#}";
            
           
      var buildingContent = "${ADDRESS}";
      var landuseContent = "${LAND_USE}";
      var zoningContent = "${ZONING}" + 
           "<br />${DESCRIPTIO}";
      
        var parcelInfo = new esri.InfoTemplate("Parcels", parcelContent);
      var buildingInfo = new esri.InfoTemplate("ADDRESS", buildingContent);
      var landuseInfo = new esri.InfoTemplate("Future Land Use", landuseContent);
      var zoningInfo = new esri.InfoTemplate("Zoning", zoningContent);
    
        var parcelLayer = new esri.layers.FeatureLayer("http://gis1.co.frederick.va.us/ArcGIS/rest/services/GeoDoc/MapServer/1",{
          mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
          displayOnPan:false,outFields: ["*"], opacity:.5, tileWidth:50, tileHeight:50, visible:false, maxScale:0, minScale:0,
          infoTemplate: parcelInfo
        });
      
      var streetsLayer = new esri.layers.FeatureLayer("http://gis1.co.frederick.va.us/ArcGIS/rest/services/GeoDoc/MapServer/2",{
          mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
          displayOnPan:false,outFields: ["*"], opacity:.8, tileWidth:50, tileHeight:50, visible:false, maxScale:0, minScale:0,
          
        });
      
      var buildingsLayer = new esri.layers.FeatureLayer("http://gis1.co.frederick.va.us/ArcGIS/rest/services/GeoDoc/MapServer/13",{
          mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
          displayOnPan:false,outFields: ["*"], opacity:.8, tileWidth:50, tileHeight:50, visible:false, maxScale:0, minScale:0,
          infoTemplate: buildingInfo
        });
      
      var landuseLayer = new esri.layers.FeatureLayer("http://gis1.co.frederick.va.us/ArcGIS/rest/services/GeoDoc/MapServer/20",{
          mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
          displayOnPan:false,outFields: ["*"], opacity:.8, tileWidth:50, tileHeight:50, visible:false, maxScale:0, minScale:0,
          infoTemplate: landuseInfo
        });
      
      var zoningLayer = new esri.layers.FeatureLayer("http://gis1.co.frederick.va.us/ArcGIS/rest/services/GeoDoc/MapServer/17",{
          mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
          displayOnPan:false,outFields: ["*"], opacity:.8, tileWidth:50, tileHeight:50, visible:false, minScale:0,
          infoTemplate: zoningInfo
        });
      
      map.addLayer(parcelLayer);
      map.addLayer(streetsLayer);
      map.addLayer(buildingsLayer);
      map.addLayer(landuseLayer);
      map.addLayer(zoningLayer);
           
        
        map.infoWindow.resize(200,150);
        
      mapLayers.push(parcelLayer);
      mapLayers.push(streetsLayer);
      mapLayers.push(buildingsLayer);
      mapLayers.push(landuseLayer);
      mapLayers.push(zoningLayer);
      
      
      legendLayers.push({layer:parcelLayer,title:"Parcels"});
      legendLayers.push({layer:streetsLayer,title:"Streets"});
      legendLayers.push({layer:buildingsLayer,title:"Buildings"});
      legendLayers.push({layer:landuseLayer,title:"Future Land Use"});
      legendLayers.push({layer:zoningLayer,title:"Zoning"});
      
       
      dojo.connect(map,'onLayersAddResult',function(results){
          var legend = new esri.dijit.Legend({
            map:map,
            layerInfos:legendLayers
          },"legendDiv");
          legend.startup();
        });        
     }
    
      function layerVisibility(layer) {
        (layer.visible) ? layer.hide() : layer.show();
      }
       
       function extentHistoryChangeHandler() {
        dijit.byId("zoomprev").disabled = navToolbar.isFirstExtent();
        dijit.byId("zoomnext").disabled = navToolbar.isLastExtent();
      }
       
       function showExtent(ext){
      var s = "";
       s = "XMin: " + ext.xmin.toFixed(2) +
          " YMin: " + ext.ymin.toFixed(2) +
          " XMax: " + ext.xmax.toFixed(2) +
          " YMax: " + ext.ymax.toFixed(2);
      dojo.byId("onExtentChangeInfo").innerHTML = s;
          }
    
      dojo.addOnLoad(init);
     
     
0 Kudos
11 Replies
JohnGrayson
Esri Regular Contributor
Alex,
  my guess is that there are many, many features at your current extent that are in the GeoDoc 1,2,13,17,20 layers.  Every FeatureLayer in OnDemand mode basically retrieves all the features for the current extent and adds them as graphics to your map.  Browsers can't handle too many graphics so you're probably requesting many features and it's just taking a long time to get them back and shown in the browser.  Have you tried adding the GeoDoc map service as a DynamicMapServiceLayer and then use 'setVisibleLayers([1,2,13,17,20])' method before adding it t the map?  You can still control the visibility of these sub-layers by managing the array of visible layers of the DynamicMapServiceLayer.
0 Kudos
AlexGray
New Contributor
Alex,
  my guess is that there are many, many features at your current extent that are in the GeoDoc 1,2,13,17,20 layers.  Every FeatureLayer in OnDemand mode basically retrieves all the features for the current extent and adds them as graphics to your map.  Browsers can't handle too many graphics so you're probably requesting many features and it's just taking a long time to get them back and shown in the browser.  Have you tried adding the GeoDoc map service as a DynamicMapServiceLayer and then use 'setVisibleLayers([1,2,13,17,20])' method before adding it t the map?  You can still control the visibility of these sub-layers by managing the array of visible layers of the DynamicMapServiceLayer.


John,
Thanks for the information.. I was looking into what you mentioned but was unable to find any example code for the 'setVisibleLayers'.. You don't happen to have an example?
Alex
0 Kudos
JohnGrayson
Esri Regular Contributor
Alex,
  below is some untested code that should give you the general idea on how to manage the sub-layer visibility:

funciton Init() {
  //...
  var geoDocLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://gis1.co.frederick.va.us/ArcGIS/rest/services/GeoDoc/MapServer",{id:'GeoDoc'});
  geoDocLayer.setVisibleLayers([1,2,13,17,20]);
  map.addLayer(geoDocLayer);
  //...
}

//
// Usage: toggleSubLayer('GeoDoc', 17);
//
function toggleSubLayer(layerId, subLayerId) {
  var layer = map.getLayer(layerId);
  if(layer && layer.visibleLayers) {
    var visibleLayers = layer.visibleLayers;
    var layerIndex = dojo.indexOf(visibleLayers, subLayerId);
    if(layerIndex === -1) {
      visibleLayers.push(subLayerId);
    } else {
      visibleLayers.splice(layerIndex, 1);
    }
    visibleLayers = (visibleLayers.length > 0) ? visibleLayers : [-1];
    layer.setVisibleLayers(visibleLayers);
  }
}
0 Kudos
AlexGray
New Contributor
John,

Thanks.. that worked Great!! I really Appreciate it..

I've gone and modified it and then modified it again.. now I have another problem..
care to take a look?

I have added in the nav toolbar and the basemapGallery and then split out the js file..
now my DeBugger is telling me 'resizeMAP is Not Defined'..

I've looked at the code and looked at some other files where I have the  same code and it all looks the same and it works.. You can tell it doesn't work on this map because when you try to use the zoomin button and the extent changes the map is not refreshed..
Any ideas why this is happening?
It was adding layers on and off a lot faster too before..

here is the newmap6.js code..

   dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require("dijit.layout.AccordionContainer");
   dojo.require("dijit.dijit");
   dojo.require("esri.dijit.Legend"); 
      dojo.require("esri.map");
      dojo.require("esri.layers.FeatureLayer");
      dojo.require("dijit.form.Button");
      dojo.require("dijit.Dialog");
   dojo.require("esri.arcgis.utils");
   dojo.require("esri.toolbars.navigation");
   dojo.require("dijit.Toolbar");
   dojo.require("dojox.grid.DataGrid");
      dojo.require("dojo.data.ItemFileReadStore");
      dojo.require("esri.tasks.find");
   dojo.require("esri.virtualearth.VETiledLayer");
      dojo.require("dijit.TitlePane");
      dojo.require("esri.dijit.BasemapGallery");

      
      var map;
   var legendLayers = [];
   var navToolbar;
   var findTask, findParams;
   var grid, store;
   var visible = [];

      function init() {
        var initialExtent = new esri.geometry.Extent({"xmin":-8746396.760545,"ymin":4719239.393535,"xmax":-8683358.936355,"ymax":4791953.233965,"spatialReference":{"wkid":102113}});
        map = new esri.Map("map",{extent: initialExtent});
  
        
        //Add the terrain service to the map. View the ArcGIS Online site for services http://arcgisonline/home/search.html?t=content&f=typekeywords:service    
        var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer");
        map.addLayer(basemap);
  
        var patLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://gis.co.frederick.va.us/ArcGIS/rest/services/Planning/Planning_PAT/MapServer",{id:'PAT',disableClientCaching: false,opacity:.6});
        patLayer.setVisibleLayers([0,1,2,3,4,5,6,7,8]);  
  legendLayers.push({layer:patLayer,title:'PAT'});
        
        var fireLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://gis.co.frederick.va.us/ArcGIS/rest/services/Fire_and_Rescue/Fire_and_Rescue/MapServer",{id:'FireRescue'});
        fireLayer.setVisibleLayers([3,7,13]);
  legendLayers.push({layer:fireLayer,title:"Fire Rescue Layers"});
        
  dojo.connect(map,'onLayersAddResult',function(results){
          var legend = new esri.dijit.Legend({
            map:map,
            layerInfos:legendLayers
          },"legendDiv");
          legend.startup();
        });
        map.addLayers([fireLayer,patLayer]);

        //Add links to toggle the visibility of the map services, turning the service off will also remove it from the legend.
          dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',0)\">Address Points</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',1)\">Zoning</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',2)\">Agricultural & Forestal Districts</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',3)\">Buildings</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',4)\">Future Land Use</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',5)\">Parcels</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',6)\">Sewer & Water Service Area</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',7)\">Urban Development Area</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('PAT',8)\">County Boundary</A><br />";
          dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('FireRescue',3)\">Fire Stations</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('FireRescue',7)\">Hydrants</A><br />";
    dojo.byId("toggle").innerHTML += "<A href=\"JavaScript:toggleSubLayer('FireRescue',13)\">First Due Areas</A><br />";
        
  navToolbar = new esri.toolbars.Navigation(map);
        dojo.connect(navToolbar, "onExtentHistoryChange", extentHistoryChangeHandler);
        
  dojo.connect(map, "onExtentChange", showExtent);
  
  createBasemapGallery();
        dojo.connect(dijit.byId('map'),'resize',resizeMap());
  
  //resize the map when the browser resizes - view the 'Resizing and repositioning the map' section in 
        //the following help topic for more details http://help.esri.com/EN/webapi/javascript/arcgis/help/jshelp_start.htm#jshelp/inside_guidelines.htm
        var resizeTimer;
        dojo.connect(map, 'onLoad', function(theMap) {
          dojo.connect(dijit.byId('map'), 'resize', function() {  //resize the map if the div is resized
            clearTimeout(resizeTimer);
            resizeTimer = setTimeout( function() {
              map.resize();
              map.reposition();
            }, 500);
          });
        });
  
  function resizeMap() {
    //clear any existing resize timer
     clearTimeout(resizeTimer);
    //create new resize timer with delay of 500 milliseconds
     resizeTimer = setTimeout(function () {
        map.resize();
        map.reposition();
     }, 500);
  }

      }
   
    function extentHistoryChangeHandler() {
        dijit.byId("zoomprev").disabled = navToolbar.isFirstExtent();
        dijit.byId("zoomnext").disabled = navToolbar.isLastExtent();
      }
   
   function showExtent(ext){
      var s = "";
       s = "XMin: " + ext.xmin.toFixed(2) +
          " YMin: " + ext.ymin.toFixed(2) +
          " XMax: " + ext.xmax.toFixed(2) +
          " YMax: " + ext.ymax.toFixed(2);
      dojo.byId("onExtentChangeInfo").innerHTML = s;  
      }

       function toggle(id) {
        var layer = map.getLayer(id);
        if (layer.visible) {
          layer.hide();
        } else {
          layer.show();
        }
      }
   
     function createBasemapGallery() {

        var basemapGallery = new esri.dijit.BasemapGallery({
          showArcGISBasemaps: true,
          bingMapsKey: 'Av1bH4keF8rXBtxWOegklgWGCYYz8UGYvBhsWKuvc4Z15kT76xVFOERk8jkKEDvT',
          map: map
        }, "basemapGallery");

        basemapGallery.startup();
        
        dojo.connect(basemapGallery, "onError", function(msg) {console.log(msg)});
      }
      
   
   function toggleSubLayer(layerId, subLayerId) {
   var layer = map.getLayer(layerId);
    if(layer && layer.visibleLayers) {
   var visibleLayers = layer.visibleLayers;
   var layerIndex = dojo.indexOf(visibleLayers, subLayerId);
    if(layerIndex === -1) {
     visibleLayers.push(subLayerId);
    } else {
     visibleLayers.splice(layerIndex, 1);
    }
  visibleLayers = (visibleLayers.length > 0) ? visibleLayers : [-1];
  layer.setVisibleLayers(visibleLayers);
  }
}
      dojo.addOnLoad(init);
0 Kudos
AlexGray
New Contributor
John,

here is the HTML code too..


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 
    <meta http-equiv="X-UA-Compatible" content="IE=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>Updating the legend to display visible layers</title>
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.1/js/dojo/dijit/themes/claro/claro.css">
    <style>
      html, body { height: 98%; width: 98%; margin: 0; padding: 5px; }
      #rightPane{
        width:20%;
      }
      #legendPane{
        border: solid #97DCF2 1px;
      }
    
    </style>
    <script type="text/javascript">var djConfig = {parseOnLoad: true};</script>
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.1"></script>
 <script type="text/javascript" src="newmap6.js"></script>
    
  </head>
  
  <body class="claro">
   <div id="navToolbar" dojoType="dijit.Toolbar">
        <div dojoType="dijit.form.Button" id="zoomin" iconClass="zoominIcon" onClick="navToolbar.activate(esri.toolbars.Navigation.ZOOM_IN);">Zoom In</div>
        <div dojoType="dijit.form.Button" id="zoomout" iconClass="zoomoutIcon" onClick="navToolbar.activate(esri.toolbars.Navigation.ZOOM_OUT);">Zoom Out</div>
        <div dojoType="dijit.form.Button" id="zoomfullext" iconClass="zoomfullextIcon" onClick="navToolbar.zoomToFirstExtent();">Full Extent</div>
        <div dojoType="dijit.form.Button" id="zoomprev" iconClass="zoomprevIcon" onClick="navToolbar.zoomToPrevExtent();">Prev Extent</div>
        <div dojoType="dijit.form.Button" id="zoomnext" iconClass="zoomnextIcon" onClick="navToolbar.zoomToNextExtent();">Next Extent</div>
        <div dojoType="dijit.form.Button" id="pan" iconClass="panIcon" onClick="navToolbar.activate(esri.toolbars.Navigation.PAN);">Pan</div>
        <div dojoType="dijit.form.Button" id="deactivate" iconClass="deactivateIcon" onClick="navToolbar.deactivate()">Deactivate</div>
     </div>
    <div id="content" dojotype="dijit.layout.BorderContainer" design="headline" gutters="true" style="width: 100%; height: 100%; margin: 0;">
        <div style="position:absolute; right:20px; top:10px; z-Index:999;">
          <div dojoType="dijit.TitlePane" title="Switch Basemap" closable="false"  open="false">
            <div dojoType="dijit.layout.ContentPane" style="width:380px; height:280px; overflow:auto;">
            <div id="basemapGallery" ></div></div>
          </div>
         </div>
   <div id="rightPane" dojotype="dijit.layout.ContentPane" region="right">       
        <div dojoType="dijit.layout.AccordionContainer">         
          <div dojoType="dijit.layout.ContentPane" id="legendPane" title="Legend"  selected="false">
            <div id="legendDiv"></div>
          </div>
          <div dojoType="dijit.layout.ContentPane" title="Frederick County GIS Layers" selected="true">
            <span style="padding:10px 0;">Click to toggle the visibilty of the various Layers.</span>
            <div id="toggle" style="padding: 2px 2px; font-size:15px;"></div>
          </div>
        </div>
      </div>
      <div id="map" dojotype="dijit.layout.ContentPane" region="center" style="overflow:hidden;">
      </div>
    </div>
  </body>

</html>
0 Kudos
JohnGrayson
Esri Regular Contributor
Alex,
  it looks like you have two 'resize' events going on.  I would recommend you remove the following:

dojo.connect(dijit.byId('map'),'resize',resizeMap());


...and...

function resizeMap() {
    //clear any existing resize timer
    clearTimeout(resizeTimer);
    //create new resize timer with delay of 500 milliseconds
    resizeTimer = setTimeout(function () {
      map.resize();
      map.reposition();
     }, 500);
  }
0 Kudos
AlexGray
New Contributor
John,

Thank you for pointing that out to me. I've finally gotten it to a somewhat stable platform that works..
Although, it still needs a lot of work. Its amazing how frustrating it can be when your getting started in programming. I think it must be a lot like a foreign language, and I am only touching the tip of the iceberg.

Thanks again..

PS: Here is a link for what I have been working on.. its not done yet.. my search isn't working for some reason but that is another question for another time.. Thanks again..

http://www.co.frederick.va.us/planning/newmap1copy.html
0 Kudos
GlenRhea
New Contributor
Here is my two cents:


  • Don't load claro and tundra css files unless you absolutely need both

  • Since you are hosting your own services make sure you're using MSD (not mxd) based services

  • Don't display so much data on initial load, it's pretty busy and takes too long to load

  • Since you're using ESRI's basemap make sure your data is in the same projection or it will take forever to display since it has to be reprojected.

  • Clicking a link to turn a service on or off doesn't work well, use a check box or radio button


On a more positive note, it looks good, I like the layout you're using and you've done a great job for someone just starting out. Keep up the good work.

Glen
0 Kudos
AxelSchaefer
New Contributor II
My 1 cent: I don't use the "Pan" Button in the Navigation Toolbar. I rename the "Deactivate" to "Pan" because in most cases you will be in the standard map-navigation mode after navToolbar.deactivate(). Depends on the specific implementation but I guess in most cases, you are.

Otherwise the user doesn't understand the logic behind that "Deactivate" button. 😉
0 Kudos