OpenLayers minimal zoom smaller than bounding box - javascript

I've got a problem with osm and openlayers.
first of all, my map object
var wgs84 = new OpenLayers.Projection("EPSG:4326");
var map = new OpenLayers.Map ('map',
{
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: wgs84,
maxExtent: new OpenLayers.Bounds(-180,-20, 180, 90),
controls: [
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.PanZoomBar(),
]
});
as you can see, my bounding box ends at -20, so the antarctis should be displayed.
but i'm able to zoom out so that i can see the whole world, and the map is smaller than the map-div (which is 900 * 500).
Is there any solution to fix it? you shouldn't be able to get a smaller map than the bounding box allows.

Have you implemented the restrictedExtent parameter?
(from the documentation)
restrictedExtent
{OpenLayers.Bounds} Limit map navigation to this extent where possible. If a non-null restrictedExtent is set, panning will be restricted to the given bounds. In addition, zooming to a resolution that displays more than the restricted extent will center the map on the restricted extent.
See an example here - This stops you panning beyond the bounds but does not restict the zoom levels. This seems to be a heavily reported missing feature that has not had many resolutions.
I believe this SO post has some workarounds for it thoughMin Max Zoom level in OpenLayers
Hope I have been some help.

Take a look at the sample I did at http://beta1234.com.sunflower.arvixe.com/maps/ (the server is a bit slow). It uses restrictedExtent and restricted zoom levels.

Related

Maximum latitude map panning with leaflet

I am new to leaflet and I want the restrict the panning of a world map horizontally and not vertically (longitude but not latitude) because this map will display pictures when I click on them and I cant see well the image when i restrict the panning horizontally AND vertically. The map by itself it not a picture, it's a real world map. But when I click on certain location, a small picture will appear on the map.
I try to play with maxBounds and setMaxbounds. The normal maxBounds (to view the world map) is :
maxBounds: [[-85, -180.0],[85, 180.0]],
When i try to put the latitude to
[[-150, -180.0],[150, 180.0]]
, the vertical panning is still restricted. Can somebody help please? Thank you.
This sounds similar to a (quite obscure) issue in the Leaflet issue tracker a
while back: see https://github.com/Leaflet/Leaflet/issues/3081
However, that issue was dealing with infinite horizontal bounds, not vertical bounds in a CRS that already has some preset limits.
If you set the map's maxBounds to a value larger than 85 (the value for MAX_LATITUDE of L.Projection.Spherical) and run a debugger, the call stack goes through the map's _panInsideMapBounds(), then panInsideBounds(), then _limitCenter(), then _getBoundsOffset, then project(), then through the map CRS's latLngToPoint, then untimately L.Projection.Spherical's project(). L.Projection.Spherical.project() projects the bounds' limits into pixel coordinates, and clamps the projected point to be inside the projection's limits.
There are a lot of reasons behind this, one of them being to prevent users from putting markers outside the area covered with tiles:
(This is particularly important when a user confuses lat-lng with lng-lat and tries to use a value outside the [-90,90] range for latitude, and the projection code starts returning Infinity values everywhere)
How to get around this? Well, we can always specify the map's CRS, and we can create a CRS with a hacked projection which enforces a different limit. Please be aware that this changes how the pixelOrigin works internally (as explained in the Leaflet tutorial about extending layers), so stuff (particularly plugins) might break.
So something like:
var hackedSphericalMercator = L.Util.extend(L.Projection.SphericalMercator, {
MAX_LATITUDE: 89.999
});
var hackedEPSG3857 = L.Util.extend(L.CRS.EPSG3857, {
projection: hackedSphericalMercator
});
var map = new L.Map('mapcontainer', {
crs: hackedEPSG3857,
});
Of course, then you can set up your own maxBounds:
var map = new L.Map('mapcontainer', {
crs: hackedEPSG3857,
maxBounds: [[-Infinity, -10], [Infinity, 10]]
});
In this case, the bounds' limits would still be clamped to hackedSphericalMercator.MAX_LATITUDE, but you should have enough wiggle room for your application.
As a side note: A radically different approach to this problem would be to use a different map projection. We're used to a spherical cylindrical projection, but that's not the only way to flatten the earth.
In particular, a Transverse Mercator projection (or pretty much any other transverse cylindrical projection, for that matter) works pretty much in the same way, but wraps vertically instead of horizontally, and it's the projected longitudes, not latitudes, the ones which approach infinity asymptotically when approaching the [-180, 180] range. Let me borrow an image from its wikipedia article:
This implies a different set of challenges (namely finding some raster tiles appropriate for your application, including which prime meridian to use, and making proj4leaflet play nice), but it's definitely doable.

Floating point zoom and setZoom in Google Maps

The Google Maps documentation says that .zoom and setZoom() expect numbers. Everything would seem to point to these numbers being integers. However, today I gave the latter a floating point value and it worked ... sort of.
var MAP;
function initialize() {
MAP = new google.maps.Map(document.getElementById('map-canvas'),
{
zoom : 5,
center : new google.maps.LatLng(-25.610111, 134.354806),
mapTypeId : google.maps.MapTypeId.ROADMAP
});
}
Using the above code, I was able to have debugger access to the MAP object.
Now in the case of continental Australia, if I have a zoom of 4, I get a slice of South East Asia, all of Papua New Guinea and New Zealand and, in the centre, the Great Southern Land. If I have a zoom of 5 I get the mainland but without Tasmania -- definitely a "bad thing". The optimal zoom, discovered using MAP.setZoom() interactively, is 4.3. This is great, except that nothing else works with that zoom. When I try to draw polygons or a heatmap, Maps throws errors like
GET https://khms0.google.com/kh?v=178&hl=en-US&x=0&y=0&z=0.2999999999999998&token=77820 404 (OK)
I imagine that the 'z' value above is what's causing the 404 -- khms0.google.com is not expecting a floating point 'z' value.
So how do I get a more appropriately zoomed homeland, with polygons, markers, heatmaps, KML layers and what have you?
By the way, I did try using fitBounds() but it didn't change anything with respect to the visible contents of the viewport apart from shifting the map around a new centre.
var se = new google.maps.LatLng(-44.999315, 156.971343); // Tasman Sea
var nw = new google.maps.LatLng(-9.063496, 106.346343); // Indian Ocean
var bs = new google.maps.LatLngBounds(nw,se);
MAP.fitBounds(bs);
The zoom level must be an integer (at least at present). It used to be documented, but I don't see it stated specifically anywhere.
If a integer zoom level doesn't work for you, either change the size of the <div> displaying the map or make your own custom tiles that have a different scale.

OpenLayers map wraps. Repeated map areas give invalid coordinates

I'm using OpenLayers to display a world map on my site. The map wraps to either side, and, in the repeated sections, the coordinates are bonkers.
The pins on the map can be moved. If we move them over to a repeated section, instead of getting the actual coordinates of that spot on the globe, we get an invalid coordinate set which makes that pin disappear from the map altogether.
Here's the code I'm using for the map:
this.maps.vectorSource = new ol.source.Vector({
});
this.maps.vectorLayer = new ol.layer.Vector({
source: self.maps.vectorSource
});
this.maps.rasterLayer = new ol.layer.Tile({
source: new ol.source.OSM({wrapDateLine: false})
});
this.maps.map = new ol.Map({
target: 'map',
interactions: ol.interaction.defaults({mouseWheelZoom:false}),
layers: [self.maps.rasterLayer, self.maps.vectorLayer],
view: new ol.View({
center: ol.proj.transform([-98.583333, 37.833333], 'EPSG:4326', 'EPSG:3857'),
zoom: 4
})
});
You can see I've tried setting the wrapDateLine option to false, but this doesn't have any effect best I can tell.
I'd like to solve this either by preventing the map from repeating or by ensuring the repeating sections report proper coordinates. At this point, I don't much care which. Any ideas how I can achieve one of these two results?
Depending on your version of OpenLayers, you may need to use different options to disable the horizonal repeat. Try adding the following options to your OSM source:
wrapX: false,
noWrap: true
I've made a jsFiddle with a slightly modified version of your code to illustrate:
https://jsfiddle.net/fg1oxpu0/
Anthony got me going in the right direction with his answer. We were using OL 3.1.1 which doesn't support wrapX. I updated to 3.2.0 and was able to turn off wrapping. However, this created a both a UX problem (the map now ends on either side and the user needs to manually move back to the other side) and a UI problem (our wide area for map display is now mostly empty).
I tried moving up to the latest version (3.7.0) which, I noticed, began wrapping the vector layer. (Vector wrapping was lost in the move to OL 3 but was restored later.) This allowed me to turn my map wrapping back on, and the pins are drawn on each repeat of the map. It also now reports the correct coordinates even on the repeated maps.

Google maps zoom level migration v2 to v3

I'm migrating a piece of google maps code in javascript from v2 to v3
The following v2 piece shows a map with the center zoomed in, so you can see street names and specific details
var mapG = new GMap(document.getElementById("gmmap"));
var point = new GLatLng(52.6461049, 6.5583690);
mapG.centerAndZoom(point, 3);
I've tried migrating this to the following
var point = new google.maps.LatLng(52.6461049, 6.5583690);
var mapOptions = {
center: point,
zoom: 3,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("gmmap"), mapOptions);
The map is centered at the exact same location but the zoom is way off. Is there a difference between the zoom values in v2 and v3? Or did I migrate it the wrong way?
If I change 3 to 15, the zooming is about equal. But since I'm migrating a client environment, I want it to look exactly the same
V2 documentation:
https://developers.google.com/maps/documentation/javascript/v2/introduction#LoadingMap
Each map also contains a zoom level, which defines the resolution of the current view. Zoom levels between 0 (the lowest zoom level, in which the entire world can be seen on one map) to 19 (the highest zoom level, down to individual buildings) are possible within the normal maps view. Zoom levels vary depending on where in the world you're looking, as data in some parts of the globe is more defined than in others. Zoom levels up to 20 are possible within satellite view.
V3 documentation:
https://developers.google.com/maps/documentation/javascript/tutorial#MapOptions
The initial resolution at which to display the map is set by the zoom property, where zoom 0 corresponds to a map of the Earth fully zoomed out, and higher zoom levels zoom in at a higher resolution.
and also https://developers.google.com/maps/documentation/javascript/maxzoom?hl=en
Most roadmap imagery is available from zoom levels 0 to 18, for example.
So they should be about the same. Could it be something else wrong with your code, e.g. are you doing fitBounds() anywhere or another method that could adjust the zoom level?

Erratic overlay behavior with custom projection, Google Maps API v3

I want to browse a single image with the Google Maps API, for which I've defined my own projection. I wanted to use a GroundOverlay instead of several image tiles, because I only have one small-resolution image, but I wanted it to still be zoomable. However, I get some erratic behavior when trying to work with this projection:
No overlays show up at all at zoom level 0.
At zoom level 1 and higher, Markers show up, but GroundOverlays still don't.
However, I can get GroundOverlays to show up very briefly, if I zoom out from any level. It will only show while it's zooming out and disappear again immediately. Also, while it does show up shortly, it does not show up at the right coordinates, but the Markers do.
I'm rather new to the API, so I would not be surprised if it was a simple oversight on my part, but I just can't see what could cause this. Here is the code for my projection, which just maps the lat/lng linearly to map coordinates:
function EvenMapProjection() {
var xPerLng = 512/360;
var yPerLat = 512/180;
this.fromLatLngToPoint = function(latlng) {
var x = (latlng.lng()+180)*xPerLng;
var y = (latlng.lat()+90)*yPerLat;
console.log('Lng', latlng.lng(), 'Lat', latlng.lat(), '-> Point', x, y);
return new google.maps.Point(x, y);
};
this.fromPointToLatLng = function(point) {
var lat = point.y/yPerLat-90;
var lng = point.x/xPerLng-180;
console.log('Point', point.x, point.y, '-> Lng', lng, lat);
return new google.maps.LatLng(lat, lng);
};
}
An example of what I'm trying to do without the projection (using the default Mercator projection):
http://95.156.209.71/tmp/a.html
The same example with the projection as defined above:
http://95.156.209.71/tmp/b.html
And finally an example using the projection but without the GroundOverlay, and instead just using tiled images (always the same image):
http://95.156.209.71/tmp/c.html
The last link also shows the Marker at LatLng(0, 0) appear at zoom level 1 (or higher), but not at level 0.
Is there something I'm just missing, or some buggy code, or is this actually a problem in the API?
I just found out that my mistake was in the definition of the ground overlay. I was at zoom level 0, which meant that I set the bounds for the overlay from (-90,-180) to (90,180), but the API seems to have issues with these levels, because they wrap longitude, hence I got weird errors. I adjusted it to be at level 1 for minimum zoom, and set the overlay from (-45,-90) to (45,90), and now it all works fine.

Categories