Google Maps API V3: Limit Map Borders

I'm trying to set boundaries where you can drag and drop a map using the Google Maps API V3. Here is a solution for V2 http://econym.org.uk/gmap/example_range.htm that works very well.

However, this is not so good with the V3 API: when you use the same checkbounds () function, the map twitches when you reach the binding, while map.setCenter () changes the center of the map.

How to fix it? What is the solution for V3 API?

+11
google-maps google-maps-api-3
Oct. 10 2018-10-10
source share
7 answers

I had the same problem, but it had to figure it out (this is the same function, the event for listening changes from "move" or "drag" to "center_changed", it works like a charm !:

google.maps.event.addListener(map,'center_changed',function() { checkBounds(); }); function checkBounds() { if(! allowedBounds.contains(map.getCenter())) { var C = map.getCenter(); var X = C.lng(); var Y = C.lat(); var AmaxX = allowedBounds.getNorthEast().lng(); var AmaxY = allowedBounds.getNorthEast().lat(); var AminX = allowedBounds.getSouthWest().lng(); var AminY = allowedBounds.getSouthWest().lat(); if (X < AminX) {X = AminX;} if (X > AmaxX) {X = AmaxX;} if (Y < AminY) {Y = AminY;} if (Y > AmaxY) {Y = AmaxY;} map.setCenter(new google.maps.LatLng(Y,X)); } } 
+19
Dec 26 '10 at 7:35
source share

You may also need to consider wrapping coordinates, distorting curves, and centering on related dimensions if the map resizes or zooms in / out. This is especially necessary if your borders occupy a large percentage of the entire map (for example, like a continent).

One of the problems with checkBounds () is that it does not take into account latitude values ​​close to the north / south poles, which have non-linear distortion, which limit the accuracy limits (I use approximate magic number factors that will not work in all situations) . By right, you must first convert the borders to linear 2d coordinates of the world to see how far from the borders it is in terms of world coordinates, than to compare the actual target center point in the world coordinate with the target actual latitude location. For longitude values ​​this does not seem like a big problem, and the linear clipping approach seems quite accurate, the main problem is related to wrapping the longitude coordinates, which is taken into account (somewhat) in the code below.

 // Persitant variables var allowedBounds; // assign something here var lastValidCenter; // initialize this using map.getCenter() function checkBounds() { // when bounds changes due to resizing or zooming in/out var currentBounds = map.getBounds(); if (currentBounds == null) return; var allowed_ne_lng = allowedBounds.getNorthEast().lng(); var allowed_ne_lat = allowedBounds.getNorthEast().lat(); var allowed_sw_lng = allowedBounds.getSouthWest().lng(); var allowed_sw_lat = allowedBounds.getSouthWest().lat(); var wrap; var cc = map.getCenter(); var centerH = false; var centerV = false; // Check horizontal wraps and offsets if ( currentBounds.toSpan().lng() > allowedBounds.toSpan().lng() ) { centerH = true; } else { // test positive and negative wrap respectively wrap = currentBounds.getNorthEast().lng() < cc.lng(); var current_ne_lng = !wrap ? currentBounds.getNorthEast().lng() : allowed_ne_lng +(currentBounds.getNorthEast().lng() + 180 ) + (180 - allowed_ne_lng); wrap = currentBounds.getSouthWest().lng() > cc.lng(); var current_sw_lng = !wrap ? currentBounds.getSouthWest().lng() : allowed_sw_lng - (180-currentBounds.getSouthWest().lng()) - (allowed_sw_lng+180); } // Check vertical wraps and offsets if ( currentBounds.toSpan().lat() > allowedBounds.toSpan().lat() ) { centerV = true; } else { // test positive and negative wrap respectively wrap = currentBounds.getNorthEast().lat() < cc.lat(); if (wrap) { alert("WRAp detected top") } // else alert("no wrap:"+currentBounds); wrap = false; var current_ne_lat = !wrap ? currentBounds.getNorthEast().lat() : allowed_ne_lat + (currentBounds.getNorthEast().lat() +90) + (90 - allowed_ne_lat); wrap = currentBounds.getSouthWest().lat() > cc.lat(); if (wrap) { alert("WRAp detected btm") } //alert("no wrap:"+currentBounds); var current_sw_lat = !wrap ? currentBounds.getSouthWest().lat() : allowed_sw_lat - (90-currentBounds.getSouthWest().lat()) - (allowed_sw_lat+90); } // Finalise positions var centerX = cc.lng(); var centerY = cc.lat(); if (!centerH) { if (current_ne_lng > allowed_ne_lng) centerX -= current_ne_lng-allowed_ne_lng; if (current_sw_lng < allowed_sw_lng) centerX += allowed_sw_lng-current_sw_lng; } else { centerX = allowedBounds.getCenter().lng(); } if (!centerV) { if (current_ne_lat > allowed_ne_lat) { centerY -= (current_ne_lat-allowed_ne_lat) * 3; // approximation magic numbeer. Adjust as u see fit, or use a more accruate pixel measurement. } if (current_sw_lat < allowed_sw_lat) { centerY += (allowed_sw_lat-current_sw_lat)*2.8; // approximation magic number } } else { centerY = allowedBounds.getCenter().lat(); } map.setCenter(lastValidCenter = new google.maps.LatLng(centerY,centerX)); } function limitBound(bound) // Occurs during dragging, pass allowedBounds to this function in most cases. Requires persistant 'lastValidCenter=map.getCenter()' var reference. { var mapBounds = map.getBounds(); if ( mapBounds.getNorthEast().lng() >= mapBounds.getSouthWest().lng() && mapBounds.getNorthEast().lat() >= mapBounds.getSouthWest().lat() // ensure no left/right, top/bottom wrapping && bound.getNorthEast().lat() > mapBounds.getNorthEast().lat() // top && bound.getNorthEast().lng() > mapBounds.getNorthEast().lng() // right && bound.getSouthWest().lat() < mapBounds.getSouthWest().lat() // bottom && bound.getSouthWest().lng() < mapBounds.getSouthWest().lng()) // left { lastValidCenter=map.getCenter(); // valid case, set up new valid center location } // if (bound.contains(map.getCenter())) // { map.panTo(lastValidCenter); // } } // Google map listeners google.maps.event.addListener(map, 'zoom_changed', function() { //var zoom = map.getZoom(); checkBounds(); }); google.maps.event.addListener(map, "bounds_changed", function() { checkBounds(); }); google.maps.event.addListener(map, 'center_changed', function() { limitBound(allowedBounds); }); 

ps For checkBounds (), to get the correct 2d world coordinate from the center of the map, given 2 lat / lng values, use map.getProjection (). fromLatLngToPoint (). Compare 2 points, find the linear difference between them and compare the difference in world coordinates back with lat / lng using map.getProjection (). FromPointToLatLng (). This will give you exact clip offsets in lat / lng units.

+6
Oct 08
source share

This script gets initial grades ( allowedBounds ) and limits the boundaries to drag and zoom_changed . Also, zoom is limited to <7.

 var allowedBounds = false; google.maps.event.addListener(map, 'idle', function() { if (!allowedBounds) { allowedBounds = map.getBounds(); } }); google.maps.event.addListener(map, 'drag', checkBounds); google.maps.event.addListener(map, 'zoom_changed', checkBounds); function checkBounds() { if (map.getZoom() < 7) map.setZoom(7); if (allowedBounds) { var allowed_ne_lng = allowedBounds.getNorthEast().lng(); var allowed_ne_lat = allowedBounds.getNorthEast().lat(); var allowed_sw_lng = allowedBounds.getSouthWest().lng(); var allowed_sw_lat = allowedBounds.getSouthWest().lat(); var currentBounds = map.getBounds(); var current_ne_lng = currentBounds.getNorthEast().lng(); var current_ne_lat = currentBounds.getNorthEast().lat(); var current_sw_lng = currentBounds.getSouthWest().lng(); var current_sw_lat = currentBounds.getSouthWest().lat(); var currentCenter = map.getCenter(); var centerX = currentCenter.lng(); var centerY = currentCenter.lat(); if (current_ne_lng > allowed_ne_lng) centerX = centerX-(current_ne_lng-allowed_ne_lng); if (current_ne_lat > allowed_ne_lat) centerY = centerY-(current_ne_lat-allowed_ne_lat); if (current_sw_lng < allowed_sw_lng) centerX = centerX+(allowed_sw_lng-current_sw_lng); if (current_sw_lat < allowed_sw_lat) centerY = centerY+(allowed_sw_lat-current_sw_lat); map.setCenter(new google.maps.LatLng(centerY,centerX)); } } 
+4
Jan 19 '11 at 10:24
source share

Thanks @sairafi. Your answer got me very close. I was getting an error where getBounds was undefined, so I wrapped it in another listener to make sure the map was fully loaded first.

 google.maps.event.addListenerOnce(map, 'tilesloaded', function() { allowedBounds = map.getBounds(); google.maps.event.addListener(map,'center_changed',function() { checkBounds(allowedBounds); }); }); // Limit map area function checkBounds(allowedBounds) { if(!allowedBounds.contains(map.getCenter())) { var C = map.getCenter(); var X = C.lng(); var Y = C.lat(); var AmaxX = allowedBounds.getNorthEast().lng(); var AmaxY = allowedBounds.getNorthEast().lat(); var AminX = allowedBounds.getSouthWest().lng(); var AminY = allowedBounds.getSouthWest().lat(); if (X < AminX) {X = AminX;} if (X > AmaxX) {X = AmaxX;} if (Y < AminY) {Y = AminY;} if (Y > AmaxY) {Y = AmaxY;} map.setCenter(new google.maps.LatLng(Y,X)); } } 
+1
Feb 16 '11 at 19:41
source share
 southWest = new google.maps.LatLng(48.59475380744011,22.247364044189453); northEast = new google.maps.LatLng(48.655344320891444,22.352420806884766); var limBound = new google.maps.LatLngBounds(southWest,northEast); var lastCenter; var option = {zoom:15, center: limBound.getCenter(), mapTypeId: google.maps.MapTypeId.ROADMAP}; var map = new google.maps.Map(document.getElementById('divMap'),option); google.maps.event.addListener(map,'zoom_changed', function() { minZoom(15); }); google.maps.event.addListener(map,'drag',function(e){ limitBound(limBound); }); function minZoom(minZoom){ if (map.getZoom()<minZoom) {map.setZoom(minZoom);} }; function limitBound(bound) { if (bound.getNorthEast().lat() > map.getBounds().getNorthEast().lat() && bound.getNorthEast().lng() > map.getBounds().getNorthEast().lng() && bound.getSouthWest().lat() < map.getBounds().getSouthWest().lat() && bound.getSouthWest().lng() < map.getBounds().getSouthWest().lng()) { lastCenter=map.getCenter(); $('#divText').text(lastCenter.toString()); } if (bound.contains(map.getCenter())) { map.setCenter(lastCenter); } } 
0
Jun 22 2018-11-22T00:
source share

pls check this google maps api v3 API: can i install zoom after fitBounds?

map.fitBounds (mapBounds);

0
Jun 27 2018-11-11T00:
source share

@sairafi and @devin

thank you for your responses. I could not get this to work in Chrome / Windows 7 because the .comtains () check is checked both true and false as soon as you hit the border.

So, I changed setCenter () at the bottom to panTo ()

The second problem was that if you set the boundaries of the bootstrap, you need to use the google.maps.event.addListenerOnce (map, 'idle' ...) event, otherwise it will restore the borders to the current map being viewed,

Finally, I use the drag event for tracking centers, for some reason it works more smoothly.

The result is the following code:

  google.maps.event.addListenerOnce(map,'idle',function() { allowedBounds = map.getBounds(); }); google.maps.event.addListener(map,'drag',function() { checkBounds(); }); function checkBounds() { if(! allowedBounds.contains(map.getCenter())) { var C = map.getCenter(); var X = C.lng(); var Y = C.lat(); var AmaxX = allowedBounds.getNorthEast().lng(); var AmaxY = allowedBounds.getNorthEast().lat(); var AminX = allowedBounds.getSouthWest().lng(); var AminY = allowedBounds.getSouthWest().lat(); if (X < AminX) {X = AminX;} if (X > AmaxX) {X = AmaxX;} if (Y < AminY) {Y = AminY;} if (Y > AmaxY) {Y = AmaxY;} map.panTo(new google.maps.LatLng(Y,X)); } } 
0
Jan 13 2018-12-12T00:
source share



All Articles