wake-up-neo.net

Wie kann ich das Verschieben in Google Maps API V3 begrenzen?

In V2 gab es eine Möglichkeit, das Verschieben/Ziehen zu begrenzen, sodass die Karte innerhalb bestimmter Grenzen bleibt. Wie wird das in V3 gemacht? 

Sagen wir, ich möchte, dass die Benutzer nur Europa betrachten. Ich habe den Zoom bereits eingeschränkt, aber wenn ich das Ziehen erlaube (was ich in diesem Fall aus anderen Gründen tun muss), kann der Benutzer über den Bereich hinaus schwenken, den ich anzeigen möchte.

Bitte geben Sie ein Funktionsbeispiel oder einen Code-Ausschnitt - ich bin kein erfahrener Programmierer ... 

Vielen Dank!

73
E. Tal

Ich glaube, ich bin ein bisschen zu spät zur Party, aber da dies genau das war, was ich gerade brauchte UND ich es verbessert habe, dachte ich, ich würde sowieso eine Antwort posten.

Mit den beiden Antworten von Daniel Vassallo und brendo kann der Benutzer immer noch die Schwenksteuerung (falls aktiviert) verwenden, um sich vom gewünschten Bereich zu entfernen. Das Ding @ Yauhen.F erwähnte in einem Kommentar.

Anstatt das Dragend-Ereignis zu verwenden, verwende ich das Ereignis center_changed. Diese wird während des Ziehens ständig ausgelöst und jedes Mal, wenn jemand die Schwenksteuerung verwendet.

// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(70.33956792419954, 178.01171875), 
     new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();

google.maps.event.addListener(map, 'center_changed', function() {
    if (allowedBounds.contains(map.getCenter())) {
        // still within valid bounds, so save the last valid position
        lastValidCenter = map.getCenter();
        return; 
    }

    // not valid anymore => return to last valid position
    map.panTo(lastValidCenter);
});

Durch das fortlaufende Speichern der letzten gültigen Position während des Ziehens wird die Bewegung angehalten, sobald sie sich außerhalb der Grenzen befindet, anstatt nach dem Ende des Ziehens zurückzuziehen.

91
HenningJ

Der Trick besteht darin, das Ereignis dragend anzuhören. Wenn die Karte außerhalb der zulässigen Grenzen gezogen wird, verschieben Sie sie wieder hinein. Wenn Sie Ihre zulässigen Grenzen als LatLngBounds object definieren, können Sie die contains()-Methode verwenden, da sie true zurückgibt, wenn das angegebene lat/lng-Argument innerhalb der Grenzen liegt.

Es ist auch wichtig, die Zoomstufe zu begrenzen, aber es scheint, dass Sie dies bereits tun.

Daher möchten Sie das folgende Beispiel ausprobieren:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps JavaScript API v3 Example: Limit Panning</title> 
   <script type="text/javascript" 
           src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px;"></div> 

   <script type="text/javascript"> 

   var minZoomLevel = 5;

   var map = new google.maps.Map(document.getElementById('map'), {
      zoom: minZoomLevel,
      center: new google.maps.LatLng(38.50, -90.50),
      mapTypeId: google.maps.MapTypeId.ROADMAP
   });

   // Bounds for North America
   var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(28.70, -127.50), 
     new google.maps.LatLng(48.85, -55.90));

   // Listen for the dragend event
   google.maps.event.addListener(map, 'dragend', function() {
     if (allowedBounds.contains(map.getCenter())) return;

     // Out of bounds - Move the map back within the bounds

     var c = map.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = allowedBounds.getNorthEast().lng(),
         maxY = allowedBounds.getNorthEast().lat(),
         minX = allowedBounds.getSouthWest().lng(),
         minY = allowedBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     map.setCenter(new google.maps.LatLng(y, x));
   });

   // Limit the zoom level
   google.maps.event.addListener(map, 'zoom_changed', function() {
     if (map.getZoom() < minZoomLevel) map.setZoom(minZoomLevel);
   });

   </script> 
</body> 
</html>

Screenshot vom obigen Beispiel. Der Benutzer kann in diesem Fall nicht weiter nach Süden oder Fernost ziehen:

Google Maps JavaScript API v3 Example: Limit Panning

21
Daniel Vassallo

Meine Version basiert auf der von @HenningJ, jedoch mit etwas Modifikation von lastValidCenter, um sanftes Ziehen entlang der Kanten der Begrenzungen zu ermöglichen.

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            html { height: 100% }
            body { height: 100%; margin: 0; padding: 0 }
            #map-canvas { height: 100% }
        </style>
        <script type="text/javascript"
            src="http://maps.google.com/maps/api/js?sensor=false"></script>
        </script>
        <script type="text/javascript">
            function initialize() {
                var mapOptions = {
                    center: new google.maps.LatLng(28.70, -127.50),
                    zoom: 4,
                    mapTypeId: google.maps.MapTypeId.ROADMAP
                };
                var map = new google.maps.Map(document.getElementById("map-canvas"),
                        mapOptions);

                // bounds of the desired area
                var allowedBounds = new google.maps.LatLngBounds(
                  new google.maps.LatLng(28.70, -127.50),
                  new google.maps.LatLng(48.85, -55.90)
                );
                var boundLimits = {
                    maxLat : allowedBounds.getNorthEast().lat(),
                    maxLng : allowedBounds.getNorthEast().lng(),
                    minLat : allowedBounds.getSouthWest().lat(),
                    minLng : allowedBounds.getSouthWest().lng()
                };

                var lastValidCenter = map.getCenter();
                var newLat, newLng;
                google.maps.event.addListener(map, 'center_changed', function() {
                    center = map.getCenter();
                    if (allowedBounds.contains(center)) {
                        // still within valid bounds, so save the last valid position
                        lastValidCenter = map.getCenter();
                        return;
                    }
                    newLat = lastValidCenter.lat();
                    newLng = lastValidCenter.lng();
                    if(center.lng() > boundLimits.minLng && center.lng() < boundLimits.maxLng){
                        newLng = center.lng();
                    }
                    if(center.lat() > boundLimits.minLat && center.lat() < boundLimits.maxLat){
                        newLat = center.lat();
                    }
                    map.panTo(new google.maps.LatLng(newLat, newLng));
                });
            }
            google.maps.event.addDomListener(window, 'load', initialize);
        </script>
    </head>
    <body>
        <div id="map-canvas"/>
    </body>
</html>

Geige hier: http://jsfiddle.net/koenpunt/n7h6t/

9
Koen.

Die beste Methode zur Einschränkung ist, die Zoomstufe und den Mittelpunkt einzustellen und die Steuerelemente wie Zoomen, Scrollen usw. zu deaktivieren (siehe unten).

 var latlng = new google.maps.LatLng(18.283078,84.047556);
     var myOptions = {
          zoom: 12,

          center: latlng,
          zoomControl: false,
          mapTypeId: google.maps.MapTypeId.ROADMAP,
          scrollwheel: false,
        navigationControl: false,
        mapTypeControl: false,
        scaleControl: false,
        draggable: false,
        disableDoubleClickZoom: true,
        };
        map = new google.maps.Map(document.getElementById("map_canvas"),   myOptions);
3
AjayR

Hier ist eine Nice-Erweiterung zu der obigen , die den Mittelpunkt der Karte auf die letzte gültige Position zurücksetzt, indem das Dragstart-Ereignis abgehört wird.

// Limit panning
var lastCenter = map.getCenter();

google.maps.event.addListener(map, 'dragstart', function() {
    lastCenter = map.getCenter();
});

google.maps.event.addListener(map, 'dragend', function() {
    if(allowedBounds.contains(map.getCenter())) return;

    map.setCenter(lastCenter);
});
3
brendo

Hier ist eine Lösung, die sich aus Tom Andersens Antwort und der aktuell akzeptierten HenningJ-Antwort zusammenfügt. Dies hat den Vorteil, dass es 1) reibungsloseres Scrollen entlang der Kanten ermöglicht (wobei die Lösung von HenningJ unübersichtlich schien), und 2) keine Probleme hat, wenn man aus einem Bereich zoomt (wiederum schien die Antwort von HenningJ beim Zoomen zu brechen) und in der Nähe der Grenzen). 

Toms Antwort war beinahe für mich zu arbeiten, außer dass der gesperrte Bereich in der Mitte des Bildschirms positioniert wurde, was für die Anwendung, mit der ich arbeitete, nicht akzeptabel war.

// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(70.33956792419954, 178.01171875), 
     new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();

google.maps.event.addListener(map, 'center_changed', function() {

    var mapBounds = map.getBounds();
    var mapNe = mapBounds.getNorthEast();
    var mapSw = mapBounds.getSouthWest();
    var center = map.getCenter();

    if( allowedBounds.contains(mapNe) && allowedBounds.contains(mapSw) ) {
        //the user is scrolling within the bounds.
        lastValidCenter = center;
        return;
    }

    //the user has scrolled beyond the Edge.

    var mapWidth = mapNe.lng() - mapSw.lng();
    var mapHeight = mapNe.lat() - mapSw.lat();

    var x = center.lng();
    var y = center.lat();

    var maxX = allowedBounds.getNorthEast().lng();
    var maxY = allowedBounds.getNorthEast().lat();
    var minX = allowedBounds.getSouthWest().lng();
    var minY = allowedBounds.getSouthWest().lat();

    //shift the min and max dimensions by 1/2 of the screen size, so the bounds remain at the Edge of the screen

    maxX -= (mapWidth / 2);
    minX += (mapWidth / 2);

    maxY -= (mapHeight / 2);
    minY += (mapHeight / 2);


    if (x < minX) {
        x = minX;
    }
    if (x > maxX) {
        x = maxX;
    }
    if (y < minY){
        y = minY;
    }
    if (y > maxY){
        y = maxY;
    }

    map.panTo(new google.maps.LatLng(y, x));

});
2
George Huber

Hier ist eine einfache Lösung, die mobil und Desktop funktioniert. Dadurch wird das Verschieben der Karte über den maximalen oder minimalen Breitengrad der Welt hinaus gestoppt und die Einstellung einer minimalen Zoomstufe ermöglicht, wodurch verhindert werden kann, dass graue Bereiche durch zu weites Zoomen sichtbar werden (abhängig von der für Ihre Karte festgelegten Größe):

(Ich empfehle Vorsicht, wenn Sie das center_changed -Ereignis verwenden, wie es in der akzeptierten Antwort von HenningJ vorgeschlagen wird. In meinem Fall verursacht die Anzahl der Ereignisse, die dadurch zu Stapelüberlauffehlern in Google Chrome verursacht werden. Stattdessen kann das 'dragend' -Ereignis verwendet werden, obwohl dies zulässig ist Wenn Sie den Benutzer außerhalb der Bereiche ziehen, wird er sofort auf einen gültigen Bereich der Karte zurückgesetzt.

var lastValidCenter;
var minZoomLevel = 2;

setOutOfBoundsListener();

function setOutOfBoundsListener() {
        google.maps.event.addListener(map, 'dragend', function () {
            checkLatitude(map);
        });
        google.maps.event.addListener(map, 'idle', function () {
            checkLatitude(map);
        });
        google.maps.event.addListener(map, 'zoom_changed', function () {
            checkLatitude(map);
        });
};

function checkLatitude(map) {
    if (this.minZoomLevel) {
        if (map.getZoom() < minZoomLevel) {
            map.setZoom(parseInt(minZoomLevel));
        }
    }

    var bounds = map.getBounds();
    var sLat = map.getBounds().getSouthWest().lat();
    var nLat = map.getBounds().getNorthEast().lat();
    if (sLat < -85 || nLat > 85) {
        //the map has gone beyone the world's max or min latitude - gray areas are visible
        //return to a valid position
        if (this.lastValidCenter) {
            map.setCenter(this.lastValidCenter);
        }
    }
    else {
        this.lastValidCenter = map.getCenter();
    }
}
1
Chris Halcrow

Ich habe die Antwort von HenningJ ausprobiert und die Karte würde nicht aufhören zu schwenken, bis sich das Zentrum in einer Ecke der Grenze befand, was nicht ideal war. Hier ist meine Lösung:

google.maps.event.addListener(map, 'center_changed', function() {
    var mapBounds = map.getBounds();
    if(allowedBounds.contains(mapBounds.getNorthEast()) && allowedBounds.contains(mapBounds.getSouthWest())) {
        lastCenter = map.getCenter();
        return;
    }

    map.panTo(lastCenter);
}, this));
1
Brandon Peters

Es gibt einen weiteren Thread zum Thema, das auch sehr gut ist. Das Problem, das ich lösen musste, bestand darin, dass ich, anstatt manuell Grenzen festzulegen und die Begrenzung der Mitte zu überprüfen, eine Begrenzung beim Laden der Seite festlegen wollte. Dann kann ich mit dem Ziehen zum Rand ziehen, wenn die Ansicht vergrößert wird.

Also setze ich Panning-Grenzen beim Laden der Karte einmal . Dann überprüfe ich, ob die Karte immer noch bei maximalem Zoom ist, und wenn ja, kehre die anfängliche Mitte ..__ zurück. Wenn eingezoomt, möchte ich an den Rand der anfänglichen Grenzen schwenken Überprüfen Sie nicht nur, ob CENTER enthalten ist, da dies die erlaubte Verschiebung um die Hälfte des Ansichtsfensters erweitern würde.

Obwohl dies die Arbeit erledigt und beim langsamen Panieren gut funktioniert, ist es leider etwas ruckartig, wenn Sie schnell schwenken.

Wenn Sie Vorschläge haben, wie dies vermieden werden kann, wäre ich Ihnen dankbar.

    map = new google.maps.Map( // defaults
        document.getElementById("map22"),
        {
            disableDefaultUI        : true,
            zoomControl             : true,
            zoom                    : 7,
            minZoom                 : 7,
            maxZoom                 : 10,
            center                  : new google.maps.LatLng(
                64.99473104134819,
                -19.22332763671875
            ),
            mapTypeId               : google.maps.MapTypeId.ROADMAP
        }
    );



    function borders(){
        return {
            maxLat : map.getBounds().getNorthEast().lat(),
            maxLng : map.getBounds().getNorthEast().lng(),
            minLat : map.getBounds().getSouthWest().lat(),
            minLng : map.getBounds().getSouthWest().lng(),
            center : map.getCenter()
        }
    }

    google.maps.event.addListenerOnce(map,'idle',function() {
        limit = borders();
    });

    google.maps.event.addListener(map,'drag',function() {
        if(map.getZoom() == 7) return map.setCenter(limit.center);
        current = borders();
        if( current.maxLng < limit.maxLng && current.minLng > limit.minLng ) activeCenterLng = current.center.lng();
        if( current.maxLat < limit.maxLat && current.minLat > limit.minLat ) activeCenterLat = current.center.lat();
        map.setCenter(
            new google.maps.LatLng(
                activeCenterLat,
                activeCenterLng
            )
        );
    });
1
tim

Ich werde meine Antwort posten, falls jemand interessiert ist, weil ich mit keiner der anderen hier angebotenen Lösungen das erreichen konnte, was ich brauchte.

Was ich brauchte, war, die vertikalen Grenzen (Breitengrad) der Karte einzuschränken, so dass der Benutzer nicht über die Breitengrade der Erde (~ +/- 85 Grad) hinaus schwenken konnte, aber auch andere Grenzen würden funktionieren.

Dieser Ansatz verwendet dasselbe center_changed -Ereignis wie an anderer Stelle beschrieben und legt einfach das Zentrum fest, falls Teile der verbotenen Grenzen angezeigt werden.

Dieser Mechanismus funktioniert nur, wenn der minimale Zoom der Karte so eingestellt ist, dass beim Herauszoomen nie mehr Fläche als innerhalb der zulässigen Grenzen angezeigt werden kann.

Arbeitsbeispiel: http://jsbin.com/vizihe

function initMap() {
  // sample bounds, can be anything and goes hand in hand with minZoom
  var northBoundary = 40
  var southBoundary = -40

  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 0, lng: 0},
    zoom: 4,
    // it's important to set this to a large enough value
    // so that zooming out does not show an area larger than allowed
    minZoom: 4 
  })

  map.addListener('center_changed', function () {
    var bounds = map.getBounds();
    var ne = bounds.getNorthEast()
    var sw = bounds.getSouthWest()
    var center = map.getCenter()

    if(ne.lat() > northBoundary) {
      map.setCenter({lat: center.lat() - (ne.lat() - northBoundary), lng: center.lng()})
    }

    if(sw.lat() < southBoundary) {
      map.setCenter({lat: center.lat() - (sw.lat() - southBoundary), lng: center.lng()})
    }   
  })
}
html, body, #map {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>
  <head>
<meta name="description" content="limit google map panning">
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
  </head>
  <body>
    <div id="map"></div>
    <script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
    async defer></script>
  </body>
</html>
0
Simone

Wenn ich Drag oder Dragend oder ähnliches verwende, springt die Karte in die zulässigen Grenzen zurück, anstatt die überfließende Bewegung einzuschränken. Ändern Sie einfach das Ereignis in 'center_changed', um zu verhindern, dass es so herumspringt.

Modifizierte jsfiddle: http://jsfiddle.net/Vjdde/1/

Edit: Nicht sicher, warum die Geige keinen Stack-Overflow erzeugt, sollte aber, da setCenter erneut center_changed aufruft 

0
johanj

Ich weiß, dass ich zur Party etwas spät komme, aber ab Mitte 2016 scheint es keine offizielle Möglichkeit zu geben, den sichtbaren Bereich einzuschränken. 

Es gibt einige Lösungen, um die Grenzen einzuschränken (einige davon in dieser Frage), aber für mich gibt es einen Fehler, da sie die Grenzen nicht genau auf die Kartenansicht einschränken, sondern nur die Mitte der Karte in der angegebene Grenzen. Wenn Sie die Grenzen auf ein überlagerndes Bild wie ich beschränken möchten, kann dies zu einem Verhalten wie unten dargestellt führen, bei dem die darunterliegende Karte unter unserer Bildüberlagerung sichtbar ist:

 enter image description here

Um dieses Problem anzugehen, habe ich eine library erstellt, die die Grenzen erfolgreich einschränkt, sodass Sie nicht aus der Überlagerung heraus schwenken können.

Bei anderen bestehenden Lösungen besteht jedoch ein "vibrierendes" Problem. Wenn der Benutzer die Karte aggressiv genug schwenkt, nachdem er die linke Maustaste losgelassen hat, schwenkt die Karte immer noch von selbst und verlangsamt sich allmählich. Ich kehre die Karte immer wieder an die Grenzen zurück, aber das führt zu einer Art Vibrieren, die sich nach einem Moment festsetzt. Dieser Panning-Effekt kann derzeit nicht mit Mitteln der Js-API gestoppt werden. Es scheint, dass, bis Google Unterstützung für etwas wie map.stopPanningAnimation () hinzufügt, wir keine reibungslose Benutzererfahrung schaffen können.

Beispiel für die Verwendung der erwähnten Bibliothek, die glatteste Erfahrung mit strengen Grenzen, die ich erhalten konnte:

function initialise(){
  
  var myOptions = {
     zoom: 5,
     center: new google.maps.LatLng(0,0),
     mapTypeId: google.maps.MapTypeId.ROADMAP,
  };
  var map = new google.maps.Map(document.getElementById('map'), myOptions);
  
  addStrictBoundsImage(map);
}

function addStrictBoundsImage(map){
	var bounds = new google.maps.LatLngBounds(
		new google.maps.LatLng(62.281819, -150.287132),
		new google.maps.LatLng(62.400471, -150.005608));

	var image_src = 'https://developers.google.com/maps/documentation/' +
		'javascript/examples/full/images/talkeetna.png';

	var strict_bounds_image = new StrictBoundsImage(bounds, image_src, map);
}
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
    google.load("maps", "3",{other_params:"sensor=false"});
</script>
<body style="margin:0px; padding:0px;" onload="initialise()">
	 <div id="map" style="height:500px; width:1000px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>

0
Matej P.

Die Lösungen hier ließen mich mit 2 Problemen. Wenn Sie die Pfeiltaste gedrückt halten, damit das Panning schnell beginnt, und wenn Sie den Edge treffen, würde es nicht den ganzen Weg zum Edge gehen, da aufgrund der Panning-Beschleunigung große "Schritte" erforderlich sind. Schritt "wäre außerhalb der Grenzen gegangen, so dass der letzte" Schritt "nicht erforderlich ist. Sobald es aufgehört hat, können Sie die Pfeiltaste loslassen und dann erneut drücken, und es wird nur ein wenig weiter geschwenkt. Zweitens enthielten diese Lösungen das Panning nach einer Zoomänderung nicht richtig. Ich habe beides gelöst und meine Lösung gepostet in einem anderen Thread , aber ich dachte, ich würde sie hier verlinken, da dies der Thread war, der mich zuerst in die richtige Richtung gebracht hat.

0
qwertymodo

Dies ist HenningJ - aber HenningJ auf ios verwendet lastValidCentre - was nicht so gut ist wie das alte, also klemme ich, was es auf iOS besser macht.

var mapObject = plugin_map.gmap3('get');
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(41.3957556, -88.4345472), 
     new google.maps.LatLng(49.4010417, -78.4286389)
);
google.maps.event.addListener(mapObject, 'center_changed', function() {
    if (allowedBounds.contains(mapObject.getCenter())) {
        // still within valid bounds, so save the last valid position
        return; 
    }

    // not valid anymore => return to last valid position
     var c = mapObject.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = allowedBounds.getNorthEast().lng(),
         maxY = allowedBounds.getNorthEast().lat(),
         minX = allowedBounds.getSouthWest().lng(),
         minY = allowedBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     //mapObject.setCenter(new google.maps.LatLng(y, x));
     mapObject.panTo(new google.maps.LatLng(y, x));
});
0
Tom Andersen