5 votos

Respuesta lenta de IE8 con OpenLayers y muchas funciones

Antecedentes

Añadir unos 700 sitios a un mapa de OpenLayers. Firefox 11 y Google Chrome muestran los sitios sin problemas. IE8, que es el estándar de la organización y no se actualizará en un futuro próximo, se atasca cuando se muestran los 700 sitios.

Cada sitio tiene un icono representativo, de un conjunto de 15 iconos. Al hacer clic en cada sitio, aparece una ventana emergente informativa. La ventana emergente se carga por cada clic. El HTML de la ventana emergente se carga en la memoria una vez (y sólo una vez) desde una única plantilla. Al hacer clic en el sitio se muestra la ventana emergente, que carga dinámicamente los datos JSON y rellena la plantilla sobre la marcha (para reducir el consumo de memoria).

Esta aplicación utiliza OpenLayers v2.12 (723 kb).

Código

Los sitios se añaden a la capa "sitios" de la siguiente manera:

/**
 * 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 );
    }
  });
}

Se devuelven unos 100k de datos JSON desde el servicio del servidor de mapas (es decir, la llamada Ajax).

Pregunta

¿Cómo se pueden cargar ~700 funciones en IE8 a través de OpenLayers sin atascarlo?

Los sitios no pueden representarse en azulejos de mapa porque el icono es dinámico (es decir, diferentes resultados de búsqueda producirán diferentes azulejos en la misma ubicación).

Ideas

Algunas ideas que he considerado son:

  • Actualizar - Probablemente no sea factible pedir a todos los que vayan a utilizar la aplicación que se actualicen a IE9.
  • Navegador - Puede que no sea factible pedir a la gente que se descargue Chrome (o Firefox) sólo para ver una aplicación web.
  • Mapa vacío - Esto haría que el mapa respondiera bastante bien al principio, pero todavía se atascaría cuando mostrara un gran número de sitios. Esta es la más trivial de las soluciones.
  • Optimizar - No hay garantía de que, incluso después de optimizar OpenLayers, el sitio sea más receptivo.
  • Zona restringida - Define una región de "visibilidad" (como una sección rectangular) y sólo muestra los sitios que están dentro de esa región. Esto reduce significativamente la utilidad de la herramienta.
  • Límites del sitio - Limitar el número de sitios devueltos para una búsqueda determinada. Esto produciría resultados engañosos.
  • Ocultar características superpuestas - Ocultar sitios que están parcialmente ocultos por otros sitios. Esto es probablemente produce resultados óptimos. Este es un tipo de estrategia de clústeres .

¿Qué otras posibilidades hay para acelerar IE8?

Por si sirve de algo, el postDraw y createNode (30,25 segundos) de OpenLayers ocupan la mayor parte del tiempo de la aplicación, según el depurador de IE8.

Actualización nº 1

Para ilustrar la cantidad de datos:

Hay sitios que quedan fuera de la provincia, pero son literalmente escasos.

Vista ampliada:

Actualización #2

Pensé que podría "ocultar" algunas de las características, pero esto no ayuda:

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

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

  layer.redraw();
}

Parece que en realidad tendrán que ser removidos de la capa para ser performantes.

Enlaces relacionados

Gracias.

3voto

xnyhps Puntos 206

Con la esperanza de que pueda ser útil...

Definir el estilo

Haga que la característica más importante (icono) represente al grupo.

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;
    }
  }  
});

Definir la superposición de iconos

Determina el umbral, en píxeles, que cuantifica la superposición de dos iconos.

  // 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 );

Definir la estrategia

Ocultar los sitios que están detrás de otros sitios utilizando la estrategia de Cluster.

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

Aplicar la estrategia

Crear una capa para mostrar los iconos del sitio.

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

Describa la prioridad de las características

Crear una característica.

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

Hallazgos

Esto reduce el número de sitios de ~700 a bastante menos de 400. IE8 sigue siendo ligeramente lento, pero ya no es inutilizable.

3voto

mblsha Puntos 305

Utilice un Estrategia de clústeres en combinación con un Estrategia de BBOX .

Tal vez debas enfocar esto desde un ángulo diferente. No estás muy lejos con tu Zona restringida idea. No descartes esta idea antes de tiempo porque reduce la utilidad de la herramienta.

En su enfoque actual está cargando todos los sitios a la vez y luego los añade a una capa vectorial. Esto significa que en cualquier momento existe la posibilidad de que el navegador contenga más datos de los que el usuario puede ver (dependiendo del nivel de zoom, etc.), ya que la mayoría de los datos estarán fuera de los límites de la ventana gráfica. Puede utilizar este hecho para optimizar la carga de los datos en el navegador del usuario solicitando al servidor sólo los datos que se encuentran dentro de los límites de la vista actual del usuario.

Puedes implementar una estrategia de actualización de BBOX a tu capa vectorial añadiendo un OpenLayers.Strategy.BBOX a su capa vectorial. Cuando la vista es invalidada (por una acción de paneo o zoom) la estrategia BBOX hará que la capa solicite nuevos datos del servidor backend. Para implementar este enfoque tendrás que ajustar tu función del lado del servidor para aceptar los parámetros adicionales que OpenLayers añadirá a la solicitud de datos y también tendrás que devolver los datos en un formato que pueda ser leído por OpenLayers. Es bastante sencillo de implementar y debería notar un aumento masivo en el rendimiento en todos los navegadores.

Hay un ejemplo en el sitio web de OpenLayers de implementar la estrategia BBOX. También podría considerar la posibilidad de añadir una estrategia de Cluster para escalas pequeñas cuando hay potencialmente grandes volúmenes de características devueltas de una solicitud, o implementar alguna representación dependiente de la escala de la capa.

2voto

Celso Puntos 66

Además de implementar el filtrado de BBOX según la respuesta de @CHenderson, tengo otra sugerencia: utilizar el navegador olfateando y cuando detecte IE8 descargue/añada sólo un número limitado de funciones (tendrá que experimentar para saber cuántas puede manejar IE8) y luego pida al usuario que se acerque para que se muestren menos funciones.

Los usuarios que no sean de IE no se verán afectados y los usuarios de IE seguirán teniendo el sitio para trabajar dentro de las capacidades de su navegador.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X