Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

Background

Adding about 700 sites to an OpenLayers Map. Firefox 11 and Google Chrome display the sites just fine. IE8, which is the organization's standard and will not be upgraded for the foreseeable future, bogs down when all 700 sites are displayed.

Each site has a representative icon, from a set of 15 icons. Clicking on each site displays an informative popup. The popup window is loaded on a per-click basis. The HTML for the popup window is loaded into memory once (and only once) from a single template. Clicking the site reveals the popup, which dynamically loads JSON data and fills in the template on-the-fly (to reduce the memory footprint).

This application uses OpenLayers v2.12 (723 kb).

Code

The sites are being added to the "sites" layer as follows:

/**
 * Adds a site to the list of sites. 
 */
function addSite( sites, uuid, label, lon, lat, icon ) {
  sites.push(
    new OpenLayers.Feature.Vector(
      getPoint( lon, lat ),
      {
        uuid: uuid,
        siteType: icon,
        title: label
      }
    )
  );
}

/**
 * Fetches the list of all sites from the query service and adds them
 * to the site layer.
 * 
 * @param siteLayer - The site is added to this layer. 
 */
function addSites( siteLayer ) {
  $.ajax({
    url: MAP_SERVER_SERVICE + 'sites',
    type: 'GET',
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function( data ) {
      var sites = [];

      $.each( data, function( key, val ) {
        addSite(
          sites,
          val.uuid,
          val.label,
          val.longitude,
          val.latitude,
          val.site_classification );
      });

      siteLayer.addFeatures( sites );
    }
  });
}

About 100k of JSON data is returned from the map server service (i.e., the Ajax call).

Question

How would you load ~700 features into IE8 through OpenLayers without bogging it down?

The sites cannot be rendered on map tiles because the icon is dynamic (i.e., different search results will produce different tiles at the same location).

Ideas

Some ideas I have considered include:

  • Upgrade – Probably not feasible to ask everyone who will be using the application to upgrade to IE9.
  • Browser – Might not be feasible to ask people to download Chrome (or Firefox) just to view a web application.
  • Empty Map – This would make the map quite responsive initially, but would still bog down when showing a large number of sites. This is the most trivial of solutions.
  • Optimize – There is no guarantee that even after optimizing OpenLayers that the site will be more responsive.
  • Restrict Area – Define a region of “visibility” (like a rectangular section) and only display sites that fall within that region. This significantly reduces the usefulness of the tool.
  • Site Limits – Constrain the number of sites returned for any given search. This would produce misleading results.
  • Hide Overlapping Features - Hide sites that are partially hidden by other sites. This is probably produces optimal results. This is a type of cluster strategy.

What other possibilities are there to speed up IE8?

For what it's worth, the postDraw and createNode (30.25 seconds) methods of OpenLayers take up most of the application time, according to the IE8 debugger.

Update #1

To illustrate the amount of data:

There are sites that fall outside of the province, but they are literally few and far between.

Zoomed in view:

Update #2

I thought I could "hide" some of the features, but this does not help:

function hideFeatures( layer ) {
  var features = layer.features;

  for( var i = 0; i < features.length; i++ ) {
    features[i].style = { visibility: 'hidden' };
  }

  layer.redraw();
}

It looks like they'll actually have to be removed from the layer to be performant.

Related Links

Thank you!

share|improve this question
1  
if you have the possibility to use a WMS layer, by WMS server like mapserver or Geoserver, that's will be very fast. –  geogeek Aug 8 '12 at 0:04
1  
The Map Server uses a custom data set; the entire system cannot rely on external data sources. (It is not a public site.) –  Dave Jarvis Aug 8 '12 at 2:18
    
Yes, hiding the features won't help I'm afraid. OpenLayers creates a DOM object for each vector feature so in IE8 your DOM is too big and IE8 is struggling. –  CHenderson Aug 8 '12 at 9:51

3 Answers 3

up vote 3 down vote accepted

Use a Cluster Strategy in combination with a BBOX Strategy.

Perhaps you should come at this from a different angle. You are not far off with your Restrict Area idea. Don't dismiss this idea too soon as reducing the usefulness of the tool.

In your current approach you are loading all sites at once and then adding them to a vector layer. This means that at any one time there is the potential that the browser will contain more data than the user can see (depending on zoom level etc) as most data will be outside of their viewport bounds. You can utilise this fact to optimise the loading of the data into the user's browser by only requesting the data from the server that falls within the bounds of the user's current view.

You can implement a BBOX refresh strategy to your vector layer by adding a OpenLayers.Strategy.BBOX strategy object to your vector layer. When the view is invalidated (by a pan or zoom action) the BBOX strategy will cause the layer to request new data from the backend server. To implement this approach you will need to tweak your server side function to accept the additional parameters OpenLayers will add to the data request and you will also need to return the data in a format that can be read by OpenLayers. It is pretty straight forward to implement and you should notice a massive increase in performance across all browsers.

There is an example on the OpenLayers website of implementing the BBOX strategy. You could also consider adding a Cluster strategy for small scales when there is potentially large volumes of features returned from a request, or implement some scale dependent rendering of the layer.

share|improve this answer
    
I like this idea. Most of the data falls within the visible bounds. You're right though, it should be possible to hide icons that overlap by more than a given percentage. –  Dave Jarvis Aug 8 '12 at 2:31
    
For that, checkout the cluster strategy. It will reduce the number of actual features being drawn. I use that from time to time. That should help with the slow rendering engine of IE8. Also Chrome frame is supposedly installable without admin rights. Never tried that though. –  Crischan Aug 8 '12 at 10:38
    
There are some environments where you simply cannot say to 100 users, "Go ahead and install Chrome." The IT support team would not approve. –  Dave Jarvis Aug 8 '12 at 17:13
    
@DaveJarvis I feel your pain brother. We've only just been upgraded from IE6 :O –  Rob Quincey Aug 9 '12 at 14:08

In addition to implementing BBOX filtering as per @CHenderson answer I have another suggestion: use browser sniffing and when you detect IE8 download/add only a limited number of features (you will have to experiment to find out how many IE8 can handle) and then prompt the user asking him/her to zoom in so that less features are displayed.

Non-IE users will be unaffected and IE users still get the site to work within the capatibilities of their browser.

share|improve this answer
    
I cannot do this. I have to display all the sites. They want to see all the sites. The software was requested for development specifically so that they can see all the sites at the provincial level. They won't actually be zooming in all that often. They'll be filtering what they see with a dialog box of search options (you can see the part of the filter in the second image). I like the idea of using a BBOX when zoomed in. That is perfect. But when zoomed out... –  Dave Jarvis Aug 8 '12 at 7:40
1  
It's just and idea and needs work specifically for IE8, but have you seen this: gis.stackexchange.com/questions/18572/… ? –  unicoletti Aug 8 '12 at 7:43
    
That's cool; I mentioned the idea in the question -- clustering the sites. I will probably have to do that. The images aren't SVG, but perhaps IE8 will still be able to render them with the SVG renderer? –  Dave Jarvis Aug 8 '12 at 7:53
    
@DaveJarvis there are workarounds that allow you to use canvas in IE8: stackoverflow.com/questions/1332501/… –  unicoletti Aug 8 '12 at 9:19
    
I wouldn't have thought that a second layer of abstraction would make IE more responsive. I'll look into it. Thank you! –  Dave Jarvis Aug 8 '12 at 17:30

In the hopes that it might prove useful...

Define Style

Make the most important feature (icon) represent the cluster.

var siteStyle = new OpenLayers.Style(
  {
    graphicWidth: ICON_SIZE_WIDTH,
    graphicHeight: ICON_SIZE_HEIGHT,
    graphicXOffset: -(ICON_SIZE_WIDTH / 2),
    graphicYOffset: -(ICON_SIZE_HEIGHT),
    externalGraphic: '${icon}',
  },
  { context: {
    icon: function( feature ) {
      if( feature.cluster ) {
        var maxImportance = 0;
        var mainFeature = 0;

        for( var c = 0; c < feature.cluster.length; c++ ) {
          var i = feature.cluster[c].attributes.importance;

          if( i > maxImportance ) {
            maxImportance = i;
            mainFeature = c;
          }
        }

        feature.attributes = feature.cluster[mainFeature].attributes;
      }

      return feature.attributes.icon;
    }
  }  
});

Define Icon Overlap

Determine the threshold, in pixels, that quantifies two icons overlapping.

  // At least 35% of the icon must be visible.
  var overlapDistance = Math.round( Math.sqrt( 
    Math.pow( ICON_SIZE_WIDTH, 2) +
    Math.pow( ICON_SIZE_HEIGHT, 2) ) * 0.35 );

Define Strategy

Hide sites that are behind other sites using the Cluster strategy.

  var strategy = new OpenLayers.Strategy.Cluster(
    { distance: overlapDistance, threshold: 2 }
  );

Apply Strategy

Create a layer to show the site icons.

  var siteLayer = new OpenLayers.Layer.Vector( 'Sites', {
    strategies: [strategy],
    styleMap: new OpenLayers.StyleMap( siteStyle )
  });

Describe Feature Priority

Create a feature.

  var feature = new OpenLayers.Feature.Vector(
    getPoint( lon, lat ),
    {
      uuid: uuid,
      icon: getIconPath( classification, MAP_ICON_SUFFIX ),
      siteType: classification,
      title: label,
      importance: priority
    }
  );

Findings

This reduces the number of sites from ~700 to well below 400. IE8 remains slightly sluggish, but is no longer unusable.

share|improve this answer
    
Excellent work! –  CHenderson Aug 9 '12 at 1:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.