javascript - vectorielle - tutoriel svg




nombre maximal d'éléments svg pour le navigateur dans une carte (3)

Je crée une carte avec un dépliant et d3. Un grand nombre de cercles seront tracés sur une carte. En termes de compatibilité du navigateur, il y a une limite prévue du nombre d'éléments svg que le navigateur peut afficher. En termes d'expérience utilisateur, je préférerais que l'utilisateur puisse voir autant d'éléments sur la carte que possible (sinon l'utilisateur pourrait avoir besoin de zoomer et dézoomer constamment et devrait attendre que l'ajax renvoie des données). Il y aura une certaine optimisation que je dois prendre en compte (temps d'attente de l'utilisateur par rapport à la charge de la requête serveur par rapport à ce que le navigateur peut gérer).

Voir intrigue, il y a une limite en ce moment sur le nombre de points que le serveur retourne et donc seulement une partie de la carte est remplie.

Le navigateur ne peut pas gérer une carte entièrement remplie ici et l'utilisateur devrait également attendre trop longtemps la réponse du serveur.

Je suppose que le problème auquel je suis confronté doit être résolu en répondant à deux questions:

  • Existe-t-il une norme en termes de ce que le navigateur moyen peut gérer en termes de nombre de formes svg simples (cercles) sur une carte?
  • Quelle est la meilleure technique pour montrer autant de formes sur la carte que possible?

Je considère les points suivants, mais je ne sais pas si cela va aider;

  • utiliser des carrés au lieu de cercles
  • utiliser l'API de la brochure au lieu du D3

Je chargerais toutes les données à la fois mais dessiner seulement des cercles dans le port de vue qui sont assez grands. Lors du zoom ou du panoramique, supprimez les cercles qui ne doivent pas être affichés et vérifiez si des cercles précédemment cachés doivent être ajoutés.


Parlant en termes généraux, aucun des points que vous envisagez aidera. Dans les deux cas, la quantité de traitement à effectuer / d'informations à afficher par le navigateur sera approximativement la même.

En ce qui concerne votre première question, pas que je sache. Il existe d'énormes variations entre les navigateurs et les plates-formes (surtout si l'on considère aussi les appareils mobiles) et une moyenne serait presque insignifiante. De plus, cela change constamment. J'ai trouvé que jusqu'à environ 1000 formes simples ne sont généralement pas un problème.

Pour afficher autant de formes que possible sur la carte, je les pré-rendrais en mosaïques bitmap, puis j'utiliserais soit l'API de la feuille, soit quelque chose comme d3.geo.tile (exemple ici ) pour la superposer sur la carte réelle. De cette façon, vous pouvez facilement passer à des millions de points.


Bien que vous ne puissiez afficher que des éléments SVG ~ 2-5k avant de commencer à voir un ralentissement notable (selon la taille, l'utilisation de remplissages dégradés, etc.), vous pouvez stocker et manipuler des jeux de données beaucoup plus importants côté client. Vous pouvez souvent gérer des dizaines ou des centaines de milliers de points de données de manière efficace en SVG: l'astuce consiste à être très sélectif sur ce que vous réalisez réellement, et à utiliser des techniques telles que le redouncing pour redessiner uniquement si nécessaire.

(Pour les jeux de données très volumineux: oui, vous devrez agréger ou sous-échantillonner les points ou pré-rendre).

En gardant cela à l'esprit, une technique que j'ai utilisée pour les cartes d3 en particulier est d'utiliser d3.geom.quadtree() pour cueillir dynamiquement des points lorsque l'utilisateur panse / zoome. Plus précisément, j'évite de dessiner des points qui sont soit

  1. en dehors de la zone de délimitation de la carte actuelle (puisque celles-ci ne sont pas visibles du tout), ou
  2. trop près d'autres points (puisque ceux-ci ajoutent un fouillis visuel et sont difficiles à interagir de toute façon).

Dans le pseudo-code JS-ish, cela ressemblerait grosso modo à:

function getIndicesToDraw(data, r, bbox) {
  var indicesToDraw = [];
  var Q = d3.geom.quadtree();
  // set bounds in pixel space
  for (var i = 0; i < data.length; i++) {
    var d = data[i];
    var p = getPointForDatum(d);
    if (isInsideBoundingBox(bbox, p) && !hasPointWithinRadius(Q, r, p)) {
      Q.add(p); 
      indicesToDraw.push(i);
    }
  }
  return indicesToDraw;
}

function redraw(svg, data, r, bbox) {
  var indicesToDraw = getIndicesToDraw(data, r, bbox);
  var points = svg.selectAll('.data-point')
    .data(indicesToDraw, function(i) { return i; });

  // draw new points for points.enter()

  points.exit().remove();

  // update positions of points (or SVG transforms, etc.)
}




leaflet