Restricting panning to one globe in Google Maps API - javascript

I have a map created using the Google Maps API, and I'd like to restrict panning to one globe; by default you can pan continuously east/west, the map repeats endlessly. I'm trying to use henningj's solution posted to this question
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(85, -180),
new google.maps.LatLng(-85, 180)
);
lastValidCenter = map.getCenter();
google.maps.event.addListener(map, "center_changed", function() {
if (allowedBounds.contains(map.getCenter())) {
lastValidCenter = map.getCenter();
return;
}
map.panTo(lastValidCenter);
});
What I have currently allows no panning whatsoever, the call to 'contains' always fails. If I log map.getCenter() it all looks sensible enough, I think(?!):
Object { A: 54.683366, F: 25.31663500000002 }
Can anyone see what I'm doing wrong?

You have your allowedBounds defined incorrectly. It should be (from the documentation):
LatLngBounds(sw?:LatLng, ne?:LatLng) Constructs a rectangle from the points at its south-west and north-east corners.
This:
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(85, -180),
new google.maps.LatLng(-85, 180)
);
Should be:
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-85, -180), //sw
new google.maps.LatLng(85, 180) //ne
);
(negative longitudes are west of positive ones, negative latitudes are south of positive ones)
proof of concept fiddle

You can setting a proper Zoom Level and resticting the min e max zoom level
var mapOptions = {
center: new google.maps.LatLng(50.431487, 30.539285),
zoom: 2,
minZoom: 2,
maxZomm:19,
mapTypeId: google.maps.MapTypeId.ROADMAP
}

Related

Google Maps with satellite base Map and imageMapType overlay increase zoom

I am displaying an ImageMapType as overlay over a satellite mapType base map.
The base map seems to be limiting the max zoom to 19 in my area, if I change to a Road mapType I get a a couple of more levels. I have high resolution imaginery which I am displaying in the overlay and I want to be able to zoom further. If I use the ImageMapType as base map I can zoom in all I need, but I would really like to display the satellite base map and then continue to zoom into the image even if there's no satellite imaginery available.
Is there any way of accomplishing this? The only thing I can think of is creating a custom base map.
Code is similar to this example https://developers.google.com/maps/documentation/javascript/examples/maptype-image-overlay
Thanks!
My code:
var mapMinZoom = 10;
var mapMaxZoom = 25;
var zoom = 20;
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(-34.567426059726316, -60.34467143006623),
zoom: zoom,
mapTypeId: google.maps.MapTypeId.SATELLITE,
panControl: false,
streetViewControl: false,
maxZoom: mapMaxZoom
});
createImageLayer('imaginery', 'images')
}
function createImageLayer(key, folder) {
var mapBounds = new google.maps.LatLngBounds(new google.maps.LatLng(-34.55771388565057, -60.367219001054764), new google.maps.LatLng(-34.55817334541287, -60.3209562599659));
var imageMapTypeLayer = new google.maps.ImageMapType({
minZoom: mapMinZoom,
maxZoom: mapMaxZoom,
name: key,
getTileUrl: function(coord, zoom) {
if ((zoom < mapMinZoom) || (zoom > mapMaxZoom)) {
return "http://www.maptiler.org/img/none.png";
}
var ymax = 1 << zoom;
var y = ymax - coord.y -1;
var tileBounds = new google.maps.LatLngBounds(
map.getProjection().fromPointToLatLng( new google.maps.Point( (coord.x), (coord.y) ) ),
map.getProjection().fromPointToLatLng( new google.maps.Point( (coord.x), (coord.y)))
);
// write a real condition here, so long this is always valid
if (tileBounds.intersects(tileBounds)) {
return "/static/ui/"+ folder + "/"+zoom+"/"+coord.x+"/"+y+".png";
} else {
return "http://www.maptiler.org/img/none.png";
}
},
tileSize: new google.maps.Size(256, 256)
});
map.overlayMapTypes.push(imageMapTypeLayer)
}
EDIT 1:
Up to now I have managed to overcome this by listening to the zoom_changed event and changing the base map to my imageMapType when the zoom reaches the maximum and back to satellite when the user zooms out. I wonder if there's a cleaner solution to this issue.

how to get uper-left and lower-right x y position of screen in openLayers map?

My problem is that when my map is loaded at that time I want to get X and Y cordinates of all four corners of screen as per resolution. My code:
map = new OpenLayers.Map("mapdiv", {
controls: [new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar()
],
numZoomLevels: 10
});
map.addLayer(new OpenLayers.Layer.OSM("OpenCycleMap"));
epsg4326 = new OpenLayers.Projection("EPSG:4326");
epsg900913 = new OpenLayers.Projection("EPSG:900913");
var lonLat = new OpenLayers.LonLat(72.58, 23.03).transform(epsg4326, epsg900913);
console.log(lonLat);
var zoom = 15;
var markers = new OpenLayers.Layer.Markers("Markers");
map.addLayer(markers);
map.events.register("click", map, function (e) {
var lonlat = map.getLonLatFromViewPortPx(e.xy);
alert(lonlat);
});
markers.addMarker(new OpenLayers.Marker(lonLat));
var polygonLayer = new OpenLayers.Layer.Vector("Polygon Layer");
map.addLayer(polygonLayer);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.addControl(new OpenLayers.Control.MousePosition());
map.setCenter(lonLat, zoom);
You should try to post a fiddle when you can. Assuming you're using OpenLayers v2.
If you meant to ask how to get the corners of the viewport, try:
map.getViewport().getClientRects()[0]
If you meant the extent of the map in coordinates:
map.getExtent()

Google maps V3: prevent marker scaling

I have a google map, and an marker on it.
I need the marker to be a fixed size of, for example, 10x10 pixels, and remail the same even if i zoom in or zoom out.
This is what i have right now (and is not workig):
var marker = new google.maps.Marker({
position: circleCenter,
map: googleMap,
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillOpacity: 0.5,
fillColor: 'ff0000',
strokeWeight: 10,
size: 5
}
});
Is this possible to block the marker of scaling it's size when the map zoom is changed?
Google does not have a out-of-box way to stop markers from scaling.
You could use a Ground Overlay to set a fixed area on the map and then attach an image. The trick with ground overlays is you have to know the coordinates of the bounds object and you probably will have to come up with some way of calculating the bounds. In this example I just expand a center point into a rectangle.
You would also loose other marker capabilities since this method doesn't use a marker object (e.g. dragging, animations, etc.), but the overlays do have click events.
Here is a proof of concept: http://jsfiddle.net/bryan_weaver/4rxqQ/
relevant code:
function initialize() {
var map;
var centerPosition = new google.maps.LatLng(38.713107, -90.42984);
var options = {
zoom: 9,
center: centerPosition,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map($('#map')[0], options);
var icon = 'https://www.google.com/mapfiles/marker_black.png';
var iconBounds = constructBounds(38.713107, -90.42984);
var staticOverlay = new google.maps.GroundOverlay(icon, iconBounds);
staticOverlay.setMap(map);
}
function constructBounds(lat, lng){
var sw = new google.maps.LatLng(lat - .03, lng - .025)
var ne = new google.maps.LatLng(lat + .03, lng + .025)
return new google.maps.LatLngBounds(sw, ne);
}

Google maps - add road directions, circle, postal code areas

I got a basic map running using google maps v3
Next features that I would like to add include:
draw line as road directions instead of direct point to point polyline
draw a circle 75 km circle around from a specific point
highlight the postal code of a specific point.
I Would appreciate people's thoughts on these topics
var geocoder;
var map;
function fnPresentMap()
{
geocoder = new google.maps.Geocoder();
var locationArray = new Array();
locationArray[0] = new Array();
locationArray[1] = new Array();
locationArray[0][0] = document.getElementById('LAT_OUT_1').innerHTML;
locationArray[0][1] = document.getElementById('LON_OUT_1').innerHTML;
locationArray[1][0] = document.getElementById('LAT_OUT_2').innerHTML;
locationArray[1][1] = document.getElementById('LON_OUT_2').innerHTML;
var latlng = new google.maps.LatLng(44, -75);
var myOptions = {
zoom: 8,
center: latlng,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
navigationControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
var myLatlng;
var image_name;
for (var count = 0; count < locationArray.length; ++count){
image_name = "img/marker_"+(count+1)+".png";
myLatlng = new google.maps.LatLng(locationArray[count][0],locationArray[count][1]);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
icon: image_name
});
}
// re-center
var centerLocation = new google.maps.LatLng(locationArray[0][0],locationArray[0][1]);
map.setCenter(centerLocation);
// show line
var points = [
new google.maps.LatLng(locationArray[0][0],locationArray[0][1]),
new google.maps.LatLng(locationArray[1][0],locationArray[1][1])
];
var line = new google.maps.Polyline({
map: map,
path: points,
strokeColor: "#FF0000",
strokeWeight: 2,
strokeOpacity: 1.0
});
}
To render road directions between two specific points, you need to use the Google Maps API directions service. If you check out the documentation you will find pretty straightforward examples to make a directions request and render the results on a map as a line between the two points.
I think the best approach for drawing a circle around a point is to draw a polygon with enough points to approximate a circle. You can find a good example of this here.
To highlight the postcode at a specific point, I suggest you use the Google Maps API reverse geocoding service (convert from a latitude/longitude to a human readable address). You can extract the postcode from the JSON response you get back and then display it on the map using a infoWindow or some other kind of overlay.

Google Maps v3 - limit viewable area and zoom level

is it possible to limit Google map v3 to a certain area? I want to allow displaying only some area (e.g. a country) and disallow the user to slide elsewhere. Also I want to restrict the zoom level - e.g. only between levels 6 and 9. And I want to use all the base map types.
Is there any way to achieve this?
I had a partial success with limiting zoom level by using StyledMap, but I succeeded only with restricting ROADMAP, I wasn't able to limit zoom on other basic types this way.
Thanks for any help
Better way to restrict zoom level might be to use the minZoom/maxZoom options rather than reacting to events?
var opt = { minZoom: 6, maxZoom: 9 };
map.setOptions(opt);
Or the options can be specified during map initialization, e.g.:
var map = new google.maps.Map(document.getElementById('map-canvas'), opt);
See: Google Maps JavaScript API V3 Reference
You can listen to the dragend event, and if the map is dragged outside the allowed bounds, move it back inside. You can define your allowed bounds in a LatLngBounds object and then use the contains() method to check if the new lat/lng center is within the bounds.
You can also limit the zoom level very easily.
Consider the following example: Fiddle Demo
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps JavaScript API v3 Example: Limit Panning and Zoom</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">
// This is the minimum zoom level that we'll allow
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 strictBounds = 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 (strictBounds.contains(map.getCenter())) return;
// We're out of bounds - Move the map back within the bounds
var c = map.getCenter(),
x = c.lng(),
y = c.lat(),
maxX = strictBounds.getNorthEast().lng(),
maxY = strictBounds.getNorthEast().lat(),
minX = strictBounds.getSouthWest().lng(),
minY = strictBounds.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 from the above example. The user will not be able to drag further south or far east in this case:
Good news. Starting from the version 3.35 of Maps JavaScript API, that was launched on February 14, 2019, you can use new restriction option in order to limit the viewport of the map.
According to the documentation
MapRestriction interface
A restriction that can be applied to the Map. The map's viewport will not exceed these restrictions.
source: https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction
So, now you just add restriction option during a map initialization and that it. Have a look at the following example that limits viewport to Switzerland
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 46.818188, lng: 8.227512},
minZoom: 7,
maxZoom: 14,
zoom: 7,
restriction: {
latLngBounds: {
east: 10.49234,
north: 47.808455,
south: 45.81792,
west: 5.95608
},
strictBounds: true
},
});
}
#map {
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&callback=initMap" async defer></script>
I hope this helps!
To limit the zoom on v.3+.
in your map setting add default zoom level and minZoom or maxZoom (or both if required)
zoom levels are 0 to 19.
You must declare deafult zoom level if limitation is required. all are case sensitive!
function initialize() {
var mapOptions = {
maxZoom:17,
minZoom:15,
zoom:15,
....
Much better way to limit the range... used the contains logic from above poster.
var dragStartCenter;
google.maps.event.addListener(map, 'dragstart', function(){
dragStartCenter = map.getCenter();
});
google.maps.event.addListener(this.googleMap, 'dragend', function(){
if (mapBounds.contains(map.getCenter())) return;
map.setCenter(this.dragStart);
});
This can be used to re-center the map to a specific location. Which is what I needed.
var MapBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(35.676263, 13.949096),
new google.maps.LatLng(36.204391, 14.89038));
google.maps.event.addListener(GoogleMap, 'dragend', function ()
{
if (MapBounds.contains(GoogleMap.getCenter()))
{
return;
}
else
{
GoogleMap.setCenter(new google.maps.LatLng(35.920242, 14.428825));
}
});
myOptions = {
center: myLatlng,
minZoom: 6,
maxZoom: 9,
styles: customStyles,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
Here's my variant to solve the problem of viewable area's limitation.
google.maps.event.addListener(this.map, 'idle', function() {
var minLat = strictBounds.getSouthWest().lat();
var minLon = strictBounds.getSouthWest().lng();
var maxLat = strictBounds.getNorthEast().lat();
var maxLon = strictBounds.getNorthEast().lng();
var cBounds = self.map.getBounds();
var cMinLat = cBounds.getSouthWest().lat();
var cMinLon = cBounds.getSouthWest().lng();
var cMaxLat = cBounds.getNorthEast().lat();
var cMaxLon = cBounds.getNorthEast().lng();
var centerLat = self.map.getCenter().lat();
var centerLon = self.map.getCenter().lng();
if((cMaxLat - cMinLat > maxLat - minLat) || (cMaxLon - cMinLon > maxLon - minLon))
{ //We can't position the canvas to strict borders with a current zoom level
self.map.setZoomLevel(self.map.getZoomLevel()+1);
return;
}
if(cMinLat < minLat)
var newCenterLat = minLat + ((cMaxLat-cMinLat) / 2);
else if(cMaxLat > maxLat)
var newCenterLat = maxLat - ((cMaxLat-cMinLat) / 2);
else
var newCenterLat = centerLat;
if(cMinLon < minLon)
var newCenterLon = minLon + ((cMaxLon-cMinLon) / 2);
else if(cMaxLon > maxLon)
var newCenterLon = maxLon - ((cMaxLon-cMinLon) / 2);
else
var newCenterLon = centerLon;
if(newCenterLat != centerLat || newCenterLon != centerLon)
self.map.setCenter(new google.maps.LatLng(newCenterLat, newCenterLon));
});
strictBounds is an object of new google.maps.LatLngBounds() type. self.gmap stores a Google Map object (new google.maps.Map()).
It really works but don't only forget to take into account the haemorrhoids with crossing 0th meridians and parallels if your bounds cover them.
For some reason
if (strictBounds.contains(map.getCenter())) return;
didnt work for me (maybe a southern hemisphere issue). I had to change it to:
function checkBounds() {
var c = map.getCenter(),
x = c.lng(),
y = c.lat(),
maxX = strictBounds.getNorthEast().lng(),
maxY = strictBounds.getNorthEast().lat(),
minX = strictBounds.getSouthWest().lng(),
minY = strictBounds.getSouthWest().lat();
if(x < minX || x > maxX || y < minY || y > maxY) {
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));
}
}
Hope it will help someone.
One solution is like, If you know the specific lat/lng.
google.maps.event.addListener(map, 'idle', function() {
map.setCenter(new google.maps.LatLng(latitude, longitude));
map.setZoom(8);
});
If don't have specific lat/lng
google.maps.event.addListener(map, 'idle', function() {
map.setCenter(map.getCenter());
map.setZoom(8);
});
or
google.maps.event.addListener(map, 'idle', function() {
var bounds = new google.maps.LatLngBounds();
map.setCenter(bounds.getCenter());
map.setZoom(8);
});
As of middle 2016, there is no official way to restrict viewable area. Most of ad-hoc solutions to restrict the bounds have a flaw though, because they don't restrict the bounds exactly to fit the map view, they only restrict it if the center of the map is out of the specified bounds. If you want to restrict the bounds to overlaying image like me, this can result in a behavior like illustrated below, where the underlaying map is visible under our image overlay:
To tackle this issue, I have created a library, which successfully restrict the bounds so you cannot pan out of the overlay.
However, as other existing solutions, it has a "vibrating" issue. When the user pans the map aggressively enough, after they release the left mouse button, the map still continues panning by itself, gradually slowing. I always return the map back to the bounds, but that results in kind of vibrating. This panning effect cannot be stopped with any means provided by the Js API at the moment. It seems that until google adds support for something like map.stopPanningAnimation() we won't be able to create a smooth experience.
Example using the mentioned library, the smoothest strict bounds experience I was able to get:
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:400px; width:500px;"></div>
<script type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>
The library is also able to calculate the minimum zoom restriction automatically. It then restricts the zoom level using minZoom map's attribute.
Hopefully this helps someone who wants a solution which fully respect the given boundaries and doesn't want to allow panning out of them.
This may be helpful.
var myOptions = {
center: new google.maps.LatLng($lat,$lang),
zoom: 7,
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
The Zoom level can be customizable according to the requirement.

Categories

Resources