Google Maps v3 fitBounds () Powiększ zbyt blisko dla pojedynczego znacznika

93

Czy istnieje sposób na ustawienie maksymalnego poziomu powiększenia fitBounds()? Mój problem polega na tym, że kiedy mapa jest zasilana tylko jedną lokalizacją, powiększa się tak daleko, jak to możliwe, co naprawdę usuwa mapę z kontekstu i czyni ją bezużyteczną. Może mam złe podejście?

Z góry dziękuję!

Codey W
źródło
2
stackoverflow.com/questions/4523023/… jest znacznie lepszym rozwiązaniem. Szczególna odpowiedź @Nequins
Kennet

Odpowiedzi:

139

Podoba mi się rozwiązanie mrt (szczególnie, gdy nie wiesz, do ilu punktów będziesz mapować lub dostosowywać), z wyjątkiem tego, że odrzuca znacznik, aby nie znajdował się już na środku mapy. Po prostu przedłużyłem ją o dodatkowy punkt odejmując 0,01 od szerokości i długości, tak aby znacznik był w środku. Działa świetnie, dzięki mrt!

// Pan & Zoom map to show all markers
function fitToMarkers(markers) {

    var bounds = new google.maps.LatLngBounds();

    // Create bounds from markers
    for( var index in markers ) {
        var latlng = markers[index].getPosition();
        bounds.extend(latlng);
    }

    // Don't zoom in too far on only one marker
    if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
       var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
       var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
       bounds.extend(extendPoint1);
       bounds.extend(extendPoint2);
    }

    map.fitBounds(bounds);

    // Adjusting zoom here doesn't work :/

}
Ryan
źródło
4
Dobry pomysł na zachowanie oryginalnego środka. Powodem, dla którego nie można wiarygodnie wyregulować poziomu powiększenia podczas korzystania z tej fitBounds()metody, jest to, że powiększanie odbywa się asynchronicznie: stackoverflow.com/questions/2989858/ ...
Metro Smurf
1
To działało świetnie dla mnie. Musiałem przekazać odniesienie do mapy do funkcji „function fitToMarkers (markers, map)” w wersji V3, ale po tym działa jak urok!
Shane,
4
Kocham to. Dobry @ryan. U mnie działało świetnie, ale 0,01 w moim przypadku zbytnio się oddalił, a 0,001 trafiło w najlepsze miejsce.
willdanceforfun
Dzięki. Podobnie jak @willdanceforfun ten sam przypadek, 001 strzałem w dziesiątkę.
Goran Jakovljevic
1
Poleciłbym
40

Możesz skonfigurować swoją mapę maxZoomw MapOptions (odwołanie do interfejsu API) w następujący sposób:

var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Dzięki temu mapa nie będzie powiększać się głębiej podczas używania, fitBounds()a nawet usunie poziomy powiększenia z elementu sterującego powiększeniem.

Flygenring
źródło
@candlejack Czyli dokładnie tak, jak opisano w mojej odpowiedzi?
Flygenring
8
Możesz ustawić maxZoomprzed dopasowaniem granic, a następnie usunąć je ponownie, używając map.setOptions({ maxZoom: undefined })na idlezdarzeniu wywołanym, zmieniając ograniczenia. Zapobiega to powiększaniu, pomniejszaniu efektu zamiast resetowania powiększenia idlezdarzenia.
El Yobo
29

Innym rozwiązaniem jest rozszerzenie granic, jeśli wykryjesz, że są zbyt małe przed wykonaniem fitBounds ():

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
   var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
   bounds.extend(extendPoint);
}
map.fitBounds(bounds);
mrt
źródło
19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Korzystanie z opcji MaxZoom działa najlepiej, gdy nie zbliżasz się do zaznaczonych znaków.

markvaneijk
źródło
Fantastyczny! Oszczędza życie!
Jaypee
18

Po dodaniu wszystkich rzeczywistych granic dodaj te linie

var offset = 0.002;     
var center = bounds.getCenter();                            
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));

uzyskuje środek rzeczywistych granic, a następnie dodaje dwa dodatkowe punkty, jeden na północny wschód i jeden na południowy zachód od środka

To skutecznie ustawia minimalne powiększenie, zmienia wartość przesunięcia, aby zwiększyć lub zmniejszyć powiększenie

PWHIT
źródło
12

Jeśli dotyczy to jednej lokalizacji, można zamiast tego użyć setCenter () i setZoom ().

CrazyEnigma
źródło
najłatwiejsze rozwiązanie
Alberto M
11

możesz użyć

map.setOptions({
    maxZoom: [what u want],
    minZoom: [what u want]
});

w ten sposób ustawiasz właściwości mapy po zainicjowaniu mapy ... możesz ustawić je tyle razy, ile chcesz ... ale w twoim przypadku ... możesz ustawić je przed fitBounds ()

powodzenia, rarutu

Wowzaaa
źródło
7

Sposobem, w jaki zapobiegam powiększaniu mapy zbyt daleko, jest dodanie tego wiersza kodu:

var zoomOverride = map.getZoom();
        if(zoomOverride > 15) {
        zoomOverride = 15;
        }
      map.setZoom(zoomOverride);

Bezpośrednio po tym wierszu:

map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));

Możesz dowolnie zmienić poziom powiększenia na dowolny poziom, na który mapa nie ma być powiększana.

Jeśli masz jakieś problemy lub pytania, zostaw mi komentarz do wpisu na blogu, który napisałem o tym na http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the- map-from-zooming-in-too-close-on-a-marker

TheLibzter
źródło
1
Podoba mi się to rozwiązanie, ale wstawiam setzoom do środka, jeśli nie chcę go wywoływać za każdym razem. Może również wystąpić efekt uboczny czasu, który zwraca wartość „undefined” z funkcji getzoom (). Rozwiązanie: zoom = map.getZoom (); if (typeof zoom! == 'undefined' && zoom> 8) map.setZoom (8);
Le Droid
5

Naprawdę podoba mi się rozwiązanie mrt i działa idealnie, jeśli zawsze masz tylko jeden punkt do pracy. Zauważyłem jednak, że jeśli obwiednia nie była oparta na jednym punkcie, ale punkty były bardzo blisko siebie, nadal mogło to spowodować zbyt duże powiększenie mapy.

Oto sposób, aby najpierw sprawdzić, czy punkty znajdują się w określonej odległości od siebie, a następnie, jeśli są mniejsze niż ta minimalna odległość, wydłuż granice o tę minimalną odległość:

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like

// ...

var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();

if((sumA < minDistance && sumA > -minDistance) 
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
    var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
    bounds.extend(extendPoint1);
    bounds.extend(extendPoint2);
}

Mam nadzieję, że to komuś pomoże!

Pakage
źródło
3

Daje to bezpośrednią kontrolę nad maksymalnym dozwolonym powiększeniem przy dopasowywaniu granic.

var fitToMarkers = function(map, markers, maxZoom) {
    if (typeof maxZoom == 'undefined') maxZoom = 15;

    google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
        if (this.getZoom() > maxZoom) {
            this.setZoom(maxZoom);
        }
    });

    var bounds = new google.maps.LatLngBounds();
    for (var m = 0; m < markers.length; m++) {
        var marker = markers[m];
        var latlng = marker.getPosition();
        bounds.extend(latlng);
    }

    map.fitBounds(bounds);
};
klimat
źródło
3

Jeśli chodzi o mnie, rozwiązuję to, tworząc zdarzenie bezczynności po fitBounds. Działa idealnie. To chyba jedno z najczystszych rozwiązań

var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) { 
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10
  });
  .... create markers, etc.
}
....
map.fitBounds(bounds);  
google.maps.event.addListenerOnce(map, 'idle', function() {
  if (locations.length == 1) {
    map.setZoom(11);
  }
});
Vitali Protosovitski
źródło
2

Rozwiązałem z tym fragmentem, ponieważ Mapy Google V3 są sterowane zdarzeniami:

możesz powiedzieć interfejsowi API, aby ustawił powiększenie na odpowiednią wartość, gdy wyzwala zdarzenie zoom_changed :

var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
    if (intial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         intial = false;
       }
    }
}); 

Użyłem początkowo, aby mapa nie powiększała się zbyt mocno wczytywania, gdy ewentualne dopasowanieBounds uległo zmianie, bez niego żadne zdarzenie powiększenia powyżej 11 byłoby niemożliwe dla użytkownika.

dostrojony
źródło
1

Po wywołaniu fitBounds()metody spróbuj ponownie ustawić poziom powiększenia. Zmusi to mapę do osiągnięcia tego poziomu powiększenia i wyśrodkowania we właściwym miejscu.

moneszchary
źródło
0

Mam soulution opartą na ograniczaniu maksymalnego zoomu podczas dopasowywania granic. U mnie działa (testowane na Win 7 - IE 9, FF 13, Chrome 19):

// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..

// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;


// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
    // set max zoom only when fitting bounds
    if (window.fittingBounds && map.getZoom() > 16) {
        this.setZoom(16);
    }
});
muffir
źródło
0

I… oto kolejny.
Taki sam pomysł jak pan i Ryan, ale

  • działa również, jeśli rozmiar granic nie jest dokładnie równy zero (*)
  • zapobiega zniekształceniom w pobliżu biegunów
  • używa getCenter () zamiast getNorthEast ()

(*) Uwaga: jeśli pudełko jest już wystarczająco duże, dodanie tych dwóch dodatkowych punktów nie powinno przynieść żadnego efektu. Nie potrzebujemy więc dalszych sprawdzeń.

function calcBounds(markers) {
  // bounds that contain all markers
  var bounds = new google.maps.LatLngBounds();
  // Using an underscore _.each(). Feel free to replace with standard for()
  _.each(markers, function(marker) {
    bounds.extend(marker.getPosition());
  });
  // prevent lat/lng distortion at the poles
  var lng0 = bounds.getNorthEast().lng();
  var lng1 = bounds.getSouthWest().lng();
  if (lng0 * lng1 < 0) {
    // Take the cos at the equator.
    var cos = 1;
  }
  else {
    var cos0 = Math.cos(lng0);
    var cos1 = Math.cos(lng1);
    // Prevent division by zero if the marker is exactly at the pole.
    var cos_safe = Math.max(cos0, cos1, 0.0001);
  }
  var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
  var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
  // "radius" in either direction.
  // 0.0006 seems to be an ok value for a typical city.
  // Feel free to make this value a function argument.
  var rLat = 0.0006;
  var rLng = rLat / cos_safe;
  // expand the bounds to a minimum width and height
  var center = bounds.getCenter();
  var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
  var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
  bounds.extend(p0);
  bounds.extend(p1);
  return bounds;
}

EDYCJA: Nie jestem do końca pewien, czy moje obliczenia współczynnika są prawidłowe, biorąc pod uwagę, że mamy odwzorowanie Mercatora. Mogę to ponownie edytować ...

Don Kichot
źródło
-1

Oto moje rozwiązanie, które działa również, gdy dwa znaczniki są bardzo blisko. Efektywny maksymalny poziom powiększenia jest taki sam w obu sytuacjach. Więc nie kończymy niepotrzebnie powiększania, gdy jest więcej niż jeden znacznik

Efektem jest znowu zapewnienie maksymalnego zoomu bez użycia opcji maxZoom, co ma prawdopodobnie niepożądany efekt uniemożliwiający użytkownikowi powiększenie powyżej poziomu maxZoom za pomocą regulacji zoomu

Wcześniej obliczyłem maxLat, minLat, maxLng i minLng ...

var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
  // ensures that we do not zoom in too much
  var delta = (minLatSpan - (maxLat - minLat)) / 2;
  maxLat += delta;
  minLat -= delta;
}

map.fitBounds({
  east: maxLng,
  west: minLng,
  north: maxLat,
  south: minLat,
});
rosell.dk
źródło