2017-02-15 1 views
1

Contexte:
Je travaille sur une application de cartographie basée sur le Web pour la randonnée. Ainsi, la carte basée sur la brochure offre des itinéraires sur les sentiers de randonnée qui sont étiquetés. Comme n'importe quel sentier de randonnée peut faire partie de plusieurs itinéraires, les itinéraires - respectivement les polylignes correspondantes représentant les itinéraires - peuvent se chevaucher.Fascicule - infobulles pour les chevauchements de polylignes

Problème:
Chaque itinéraire a son infobulle (déclenchée par mouseover, {collant: true}) montrant l'étiquette qui fonctionne comme prévu pour les polylignes ne se chevauchent pas, mais dès que deux ou plusieurs routes se chevauchent que la polyligne "sur le dessus" obtient son info-bulle ouverte. Ce comportement n'est pas mauvais en soi mais comme toutes les routes sont également importantes je voudrais montrer toutes les étiquettes des routes à l'emplacement du pointeur (ou quelque chose comme un maximum de 5 étiquettes + x plus). Je n'ai pas pu trouver de problème lié à ce sujet.

Ce que j'ai essayé:
- Création d'un groupe de fonctionnalité pour tous les itinéraires, lier l'info-bulle au groupe, en espérant que la fonction infobulle fournit un tableau de tous polylignes traversant la position du pointeur.
- J'ai essayé la même chose avec un événement mousemove sur la carte, sans succès
- Comparer les coordonnées layerPoint du pointeur avec les _ _rings des routes & _parts tableaux layPoint pour trouver les correspondances layerPoints, mais le taux de réussite n'est que d'environ 5% car ces layerPoints ne couvrent que les points réels de la polyligne mais pas la connexion entre deux points. De plus, il y a une marge autour de chaque polyligne qui déclenche le péage avant même que le pointeur ne touche la polyligne (trop améliorer l'action tactile, je suppose)
- Une solution au problème de marge est d'ajouter des marges positives et négatives à chaque point de polyligne avant en le comparant aux coordonnées du pointeur, ce qui améliore le résultat mais ne résout pas le problème principal.

Sidenote:
- Tous les itinéraires sont attirés dans une seule toile

Longue histoire courte, je besoin d'aide extérieure pour atteindre l'objectif. Peut-être que certains d'entre vous ont une idée ou peuvent fournir une solution. Toute contribution est appréciée.

** MISE À JOUR: **
Un travail mais solution assez inefficace est la suivante

Approche:
Calculer la distance la plus courte du pointeur sur toutes les routes en vue. Si la distance entre le pointeur et un itinéraire est inférieure à un certain seuil, ajoutez-les au tableau des étiquettes d'itinéraire à afficher.

Étapes:
1.) lier une info-bulle vide à un groupe d'entités contenant tous les itinéraires de
2.) se lient événement mousemove au groupe d'entités avec la fonction follwing

var routesFeatureGroup = L.featureGroup(routesGroup) 
    .bindTooltip('', {sticky: true}) 
    .on('mousemove', function(e){ 
     var routeLabels = [e.layer.options.label]; // add triggering route's label by default 
     var mouseCoordAbs = el.$map.project(e.latlng); 

     $.each(vars.objectsInViewport.routes, function(i, v){ 
      if (e.layer.options.id != el.$routes[i].options.id && el.$routes[i]._pxBounds.contains(e.layerPoint)){ 
       var nearestLatlngOnPolyline = getNearestPolylinePoint(e.latlng, el.$routes[i]); 
       var polyPointCoordAbs = el.$map.project(nearestLatlngOnPolyline); 

       var distToMouseX = polyPointCoordAbs.x - mouseCoordAbs.x; 
       var distToMouseY = polyPointCoordAbs.y - mouseCoordAbs.y; 
       var distToMouse = Math.sqrt(distToMouseX*distToMouseX + distToMouseY*distToMouseY); 

       if (distToMouse < 15) { 
        routeLabels.push(el.$routes[i].options.label); 
       } 
      } 
     }) 

     var routesFeatureGroup.setTooltipContent(routeLabels.join('<br>')); 
    }) 

Explication :
Je rassemble déjà tous les objets (routes et marqueurs) dans la fenêtre courante pour une autre partie de l'application.Toutes les routes actuellement visibles sont stockées dans vars.objectsInViewport.routes (respectivement leur identifiant), donc je n'ai pas à parcourir toutes les routes. La couche qui a déclenché l'événement mousemove est ajoutée par défaut. Je vérifie ensuite pour chacune des routes actuellement visibles si:
- leur id est différent de la couche qui déclenche l'événement mousemove (comme cette étiquette est ajoutée par défaut) - si leurs limites (en coordonnées cartésiennes: "_pxBounds") contient le layerPoint cartésien de l'événement mousemove (pour une approche grossière afin d'exclure les routes qui ne se croisent pas)

Si ces conditions sont remplies pour un itinéraire, calculez le point de liaison le plus proche du pointeur vers la route. Je le fais avec une fonction personnalisée, ce qui est un peu long à poster dans ce contexte. (Je si quelqu'un demande pour elle)

La position de la souris et le point latlng sur la polyligne/itinéraire sont ensuite converties en coordonnées absolues en utilisant la méthode carte projet http://leafletjs.com/reference.html#map-project

Enfin, la distance entre ces aux points est calculé en utilisant pythagoras. Il est basé sur les pixels, de sorte que le niveau de zoom n'est pas un facteur. Si la distance est inférieure à un certain seuil (15px), elles sont suffisamment proches du pointeur pour être considérées comme planantes (avec les marges par défaut autour d'une polyligne), de sorte que l'étiquette de la route est ajoutée au tableau d'étiquettes.

Enfin, l'info-bulle du groupe de fonctions est remplie avec toutes les étiquettes.

Les résultats sont plutôt prometteurs, même si l'opération est très coûteuse. J'ai ajouté un délai d'attente de 50 ms pour réduire la fonction appel un peu:

var tooltipTimeout; 
var routesFeatureGroup = L.featureGroup(routesGroup) 
    .bindTooltip('', {sticky: true}) 
    .on('mousemove', function(e){ 
     clearTimeout(tooltipTimeout); 

     tooltipTimeout = setTimeout(function(){ 
      // collect labels 
      // ... 
     },50); 
    .on('mouseout', function(){ 
     clearTimeout(tooltipTimeout); 
    }) 

Répondre

0

Je peux vous donner une idée de la façon de le faire, mais je ne suis pas sûr à 100% qu'il fera le travail. Il y a un plugin for Leaflet (Mapbox) qui peut vous dire si un point est dans un polygone et il retourne tous les polygones qui contiennent ce point. Si ce plugin ne fonctionne pas pour les polylignes, vous pouvez créer un polygone à partir d'une polyligne en revenant simplement du dernier point au premier et en fermant la ligne (je ne sais pas si cela vous convient). Par exemple si vous avez une polyligne des points connectés de [0, 1, 2, .... n-1, n] vous revenez alors avec la connexion [n avec n-1, n-1 avec n-2,. .. 1 avec 0]. De cette façon, vous aurez la même forme de la polyligne mais ce sera un polygone. Ce n'est pas la solution la plus optimisée, c'est une solution rapide qui utilise un plugin connu et disponible. Une fois que vous obtenez toutes les info-bulles, vous pouvez les ouvrir toutes en même temps pour chaque polygone/polyligne. Ou peut-être ouvrir une info-bulle d'aide où l'utilisateur peut sélectionner celui qu'il veut ouvrir.

J'espère que cela aide! Si vous trouvez une meilleure solution (ou trouvez un plugin qui fait le travail), veuillez le poster ici.

+0

J'ai vu le dépliant pip-plugin (point en polygone) mais je m'attends au problème suivant avec cette approche: en reliant le dernier point au premier, le polygone couvre une zone beaucoup plus grande que la polyligne avec un "poids". Imaginez une route longue (début = fin), tous les points de la route correspondent à ce scénario, peu importe si le curseur est à 2px ou à 400px de cette route. J'ai ajouté une solution possible mais coûteuse à la publication originale qui fonctionne. –

+0

Non, je ne voulais pas dire que vous connectez le dernier point avec le premier mais par exemple si vous avez [0,1,2,3,4 ... n-1, n] points qui représentent votre polyligne, alors vous allez vers l'arrière et relier [n avec n-1, n-1 avec n-2, ... 1 avec 0]. Je sais que ce n'est pas une solution optimisée mais c'est une solution rapide qui utilise un plugin connu. –

+1

ah, merci pour la clarification.Cela fonctionnerait probablement à l'exception du "problème" que cette approche ne prend pas en compte la marge/poids des polylignes qui déclenche l'info-bulle pour rendre cette fonctionnalité plus utilisable. –