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