web-dev-qa-db-fra.com

Comment zoomer en douceur sur un marqueur dans Google Maps?

J'aimerais pouvoir effectuer un zoom avant en douceur sur un marqueur dans Google Maps. Si vous ne définissez que le zoom en double-clic, la carte se trouve soudainement à ce niveau de zoom, sans aucune transition en douceur. 

En ne zoomant que d'un niveau par rapport au niveau actuel, Google Maps affiche une transition en douceur. Il doit donc être possible de zoomer en douceur sur plusieurs niveaux, mais comment?

34
PeanutButterJelly

Comme par hasard, je voulais obtenir le même effet récemment et j'ai trouvé une solution que j'ai faite un post à propos de. Fondamentalement, il ne suffit pas de définir un délai d'attente pour chaque transition, car cela pourrait facilement donner lieu à un type de zoom «début-arrêt» si l'effet de zoom de Google n'est pas encore terminé ou a été prolongé. 

Comme Martin l'a mentionné, cela présente des inconvénients que je ne répéterai pas. Que vous l'utilisiez au bout du compte, c'est votre choix et cela dépend en grande partie de la puissance du processeur et/ou du navigateur de vos utilisateurs. C'est un bel effet cependant, et vous en impressionnerez certains, si vous l'utilisez judicieusement.

Ma solution était la suivante:

// example marker:
var marker = new google.maps.Marker({
    map: map, 
    position: new google.maps.LatLng(-20.3,30.3)
});


// add the double-click event listener
google.maps.event.addListener(marker, 'dblclick', function(event){
    map = marker.getMap();    
    map.setCenter(overlay.getPosition()); // set map center to marker position
    smoothZoom(map, 12, map.getZoom()); // call smoothZoom, parameters map, final zoomLevel, and starting zoom level
});


// the smooth zoom function
function smoothZoom (map, max, cnt) {
    if (cnt >= max) {
        return;
    }
    else {
        z = google.maps.event.addListener(map, 'zoom_changed', function(event){
            google.maps.event.removeListener(z);
            smoothZoom(map, max, cnt + 1);
        });
        setTimeout(function(){map.setZoom(cnt)}, 80); // 80ms is what I found to work well on my system -- it might not work well on all systems
    }
}  

En gros, il s’agit d’ajuster le niveau de zoom d’une unité, d’écouter l’événement zoom_changed, d’attendre 80 ms avant de régler de nouveau le niveau de zoom, etc. Ce qui est bien, c’est que l’événement zoom_changed semble être appelé après le lissage transition fournie par Google Maps, mais avant, les images réelles sont chargées, afin de ne pas gaspiller trop de bande passante.

Le délai d'attente de 80 ms est également un chiffre magique que j'ai proposé: vous seriez bien avisé de faire un test plus approfondi et de voir ce qui fonctionne sur différents systèmes et navigateurs, et peut-être modifier légèrement l'algorithme en fonction de vos résultats. systèmes.

Il n'est probablement pas non plus nécessaire d'ajouter et de retirer l'auditeur à chaque fois, mais vous pouvez apporter cette petite amélioration vous-même si vous le souhaitez.

54
Herman Schaaf

Celui-ci a bien fonctionné pour moi:

function animateMapZoomTo(map, targetZoom) {
    var currentZoom = arguments[2] || map.getZoom();
    if (currentZoom != targetZoom) {
        google.maps.event.addListenerOnce(map, 'zoom_changed', function (event) {
            animateMapZoomTo(map, targetZoom, currentZoom + (targetZoom > currentZoom ? 1 : -1));
        });
        setTimeout(function(){ map.setZoom(currentZoom) }, 80);
    }
}
8
Igor Mukhin

Vous pouvez essayer d'utiliser setInterval pour effectuer un zoom avant sur un niveau et l'effacer lorsque vous atteignez le niveau souhaité.

Le problème, c’est que l’intervalle qui le fera fonctionner dépend entièrement du processeur et de la bande passante de la machine de l’utilisateur (à quelle vitesse peut-il charger et afficher le nouvel ensemble de mosaïques d’image).

Tbh, je ne suis pas sûr que cela puisse être fait pour que cela fonctionne bien dans toutes les situations, mais un petit intervalle entre les niveaux de zoom pourrait aider un peu.

Quelques points à garder à l'esprit cependant:

  1. cela mettra beaucoup plus de stress sur les processeurs et la bande passante des utilisateurs que d'aller directement au niveau de zoom choisi
  2. l'utilisateur devra attendre jusqu'à ce que cela soit fait pour commencer à interagir avec la carte, ce qui pourrait facilement devenir une très mauvaise expérience utilisateur.

Ces deux raisons et probablement d’autres raisons expliquent pourquoi Google n'a pas intégré le type de zoom souhaité aux cartes, car c’est une mauvaise idée ...

3
Martin Jespersen

@ Herman Schaaf Votre solution est excellente, mais lorsque vous double-cliquez dessus, elle saute quelques zooms. édité le code de JesseDobbelaere à partir de jsfiddle.net C'est un mélange du vôtre et du code de Jesse.

function smoothZoom(map, level, cnt, mode)
{
    if(mode == true)
    {
        if (cnt >= level) {
            return;
        }
        else
        {
            if((maxZoomOut + 2) <= cnt)
            {
                var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
                {
                    google.maps.event.removeListener(z);
                    map.setCenter(marker.getPosition());
                    smoothZoom(map, level, cnt + 1, true);
                });
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
            else
            {
                map.setZoom(cnt);
                smoothZoom(map, level, cnt + 1, true);
            }
        }
    }
    else 
    {
        if (cnt < level) {
            return;
        }
        else
        {
            var z = google.maps.event.addListener(map, 'zoom_changed', function(event)
            {
                google.maps.event.removeListener(z);
                map.setCenter(marker.getPosition());
                smoothZoom(map, level, cnt - 1, false);
            });
            if(maxZoomIn - 2 <= cnt)
            {
                map.setZoom(cnt);
            }
            else
            {
                setTimeout(function(){map.setZoom(cnt);}, timeOut);
            }
        }
    }
}    

J'ai fait quelques variables supplémentaires comme timeOut et maxZoomIn Out ... Vous pouvez trouver le code complet sur jsfiddle http://jsfiddle.net/dexy86/9afy9/

2
Dexy86

J'ai essayé les alternatives proposées ci-dessus, cependant, chaque fois que je visualise la transition dans un navigateur Web ou une application mobile, tout se produit instantanément, ou du moins, dans un laps de temps imperceptible à l'oeil du fait du temps qui s'écoule entre eux. Itération de boucle, au moins sur le matériel sur lequel je l’ai testée.

J'ai utilisé la même boucle que les autres méthodes, mais j'ai modifié le délai d'attente de sorte que le zoom se produise plus rapidement lorsque le niveau de zoom est élevé et plus lentement lorsqu'il est inférieur afin que les résultats soient plus visibles. 

Au lieu d'utiliser un délai d'attente fixe, je règle le premier délai d'attente à 0, puis les délais suivants à l'équation rapide et sale suivante

((1+ currentZoom) / maxZoom) * 500;

Dans le code, je supposais que le zoom maximum était de 18, mais vous pouvez utiliser maxZoom pour savoir quel est le niveau de zoom pour un lat/long donné. Mon code est:

timeout = (1+map.getZoom() / 18) * 500;
0
Debs