I just want to clarify whether my way of understanding is correct. In my Google Maps app I would like to show to my users markers from particular continents.
Question: Am I right that a bound in Google Map API is an area made from NOT MORE AND NOT LESS than two points (markers)?
From math lessons, to draw 2D area I just need two points. Right? So to show to my users all markers from Europe should I just find two coordinates, one from Iceland (top, left) and second from let's say south-east Turkey? (For USA I would pick Seattle and Miami).
So, below JS code works perfectly. My question is - could you confirm that my way of understanding and the approach I've chosen is correct? Does it make any sense?
var bounds = new google.maps.LatLngBounds();
bounds.extend(new google.maps.LatLng('66.057878', '-22.579047')); // Iceland
bounds.extend(new google.maps.LatLng('37.961952', '43.878878')); // Turkey
this.map.fitBounds(bounds);
Yes, you are mostly correct. Except a 'bound' in Google maps case can include multiple points, for example if you had a point to the far right in the middle of the square in your image above and another at the bottom of the square in the middle you would still get an area the same as you have drawn above but with 3 points as in the edited map.
Obligatory link to the docs :)
https://developers.google.com/maps/documentation/javascript/reference?hl=en
You should not think about "top-left" and "bottom-right" but as south-west and north-east (so bottom-left and top-right if you like), as these are the coordinates used to create and/or retrieve the bounds object.
See the documentation and the getNorthEast and getSouthWest methods.
These two points are LatLng objects, and not markers. As an example, a marker is positioned on the map using a LatLng object.
I don't know your use case and your way of storing the data, but there might be a more precise way to display "Europe" markers. You could for example save the region along with each marker so that you can just query for "EU" markers and not others...
Related
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.
I need to zoom my OpenLayers map (which uses a Google Maps baselayer) to fit all of a given list of coordinates into the view.
I've stored the coordinates in an array of longitude and latitude pairs named pointsDecimal which looks like this:
pointsDecimal: Array[50]
0: 148.77638
1: -34.491728
2: 148.77896
3: -34.492302
4: 148.778090711323
...
Even-numbered indices (0, 2, 4 etc) are longitude, and odd-numbered indices (1, 3, 5 etc) are latitude.
This is the code I'm trying to use:
map.getView().fit(pointsDecimal, map.getSize());
But for some reason this puts me at maximum zoom level at the coordinates [0,0] - in the Gulf of Guinea, not in southeastern New South Wales where I'd like to be!
I know this would be much easier if I was using an OpenLayers source (e.g. source.getExtent()) in place of my pointsDecimal array, but this is not an option in this case for reasons I won't go into right now - I can only use the array.
Can anyone give me any hints please?
EDIT: I think I'm nearly there, thanks to Anupam. This is what I have now:
var extent = [pointsLongMin,pointsLatMin,pointsLongMax,pointsLatMax];
map.getView().fit(extent,map.getSize());
The values I'm passing to the array are as follows:
pointsLongMin: 148.771162
pointsLatMin: -34.5029736405108
pointsLongMax: 148.77896
pointsLatMax: -34.491728
But I'm still getting dumped out in the ocean at [0,0]. What am I doing wrong here?
In order to use map.getView().fit(extent,size).
extent denotes four points as [minx, miny, maxx,maxy].
It is actually a rectangle. try
var extent=[148.77638,-34.491728,148.77896,-34.492302];
map.getView().fit(extent,map.getSize());
most propable reason is that your map is projected on EPSG:3857while your extent EPSG:4326. So you need to transform your extent to your map projection.
var coordMin = ol.proj.fromLonLat([148.77638,-34.491728], 'EPSG:3857');
var coordMax = ol.proj.fromLonLat([148.77896,-34.492302], 'EPSG:3857');
var extent=[coordMin[0],coordMin[1],coordMax[0],coordMax[1]];
map.getView().fit(extent,map.getSize());
You may find a more elegand way to do the extent transformation. Unless you provide your full code we can only guess what is your map projection. I am just guessing is EPSG:3857 cause thats the default ol3 use.
I am having a hard time trying to figure out how to wrap a Lat/Lng point with a rectangle that is 20meters by 20meters.
Use-case:
> Click on a marker on the Google map
< Infowindow opens
> Click a button called 'Wrap' on the Infowindow
< Automatically create a 20x20m box with the marker dead center
I have no issue creating the rectangle (square rather) on the map I just need to know how to compute the border of the square in Lat/Lng.
On a normal grid I would get the NW and SE points by:
marker_nw_y = marker_y + 10 (meters)
marker_nw_x = marker_x - 10
marker_se_y = marker_y - 10
marker_se_x = marker_x + 10
From there I could create the graphic square etc.. But with Lat/Lng it gets more complicated because changing the degree between two points is different depending on where you are.
How could I do this? Manipulating the Haversine formula? Instead of solving for 'distance' I would need to rearrange and solve for one of the coordinates, but rearranging that formula is difficult and im not sure whether my results are even right.
I believe this question includes code that should let you accomplish what you're looking for.
I would use Mike Williams' eshapes library which I ported to the Google Maps API v3 to make squares with a "radius" of 20*sqrt(2)/2 meters.
example using my port of Mike Williams' eshapes library
The click listener would be:
google.maps.event.addListener(map, "click", function(evt) {
var marker = new google.maps.Marker({ position: evt.latLng, map: map});
var square = google.maps.Polyline.RegularPoly(evt.latLng,20*Math.sqrt(2)/2,4,0,"#ff0000",1,1);
square.setMap(map);
});
working example
Simpler working example based off alternate answer in link from Kelvin Mackay
I have a leaflet.js map that has points and linestrings on it that come from an external JSON file.
If I add:
map.setView(new L.LatLng(0,0), 10);
It will centre the map on the latitude and longitude 0,0. How can I set it so the map centre and zoom fit all of the points from the JSON on it?
You could add all of your layers to a FeatureGroup which has a getBounds method. So you should be able to just say myMap.fitBounds(myFeatureGroup.getBounds());
The getBounds method for L.FeatureGroup is only available in the master branch (not the latest version, 0.3.1), for now at least.
Similar case with me. I drawn all the markers from GeoJson data. So I written the function, which gets called repeatedly on button click. Just try if it suits your requirements.
function bestFitZoom()
{
// declaring the group variable
var group = new L.featureGroup;
// map._layers gives all the layers of the map including main container
// so looping in all those layers filtering those having feature
$.each(map._layers, function(ml){
// here we can be more specific to feature for point, line etc.
if(map._layers[].feature)
{
group.addLayer(this)
}
})
map.fitBounds(group.getBounds());
}
The best use of writing this function is that even state of map/markers changed, it will get latest/current state of markers/layers. Whenever this method gets called all the layers will be visible to modest zoom level.
I needed to do this when showing a user directions from his origin to a destination. I store my list of directions in an array of L.LatLng called directionLatLngs then you can simply call
map.fitBounds(directionLatLngs);
This works because map.fitBounds takes a L.LatLngBounds object which is just an array of L.LatLng
http://leafletjs.com/reference.html#latlngbounds
I have a latitude/longitude value and distance value. I need to calculate a bounding box with the given location as the center. so if the distance was 200 meters then the rectangle box should be 200 meters in front, behind, to left and right.
How do I go about doing this using JavaScript?
You need to translate your coordinate lat/long to a x/y-value in the map projection you are using, then you can calculate your bounding box.
I don't know the Google Maps API well, and I don't know exactly what you want to do with your box. But maybe GBounds, GMercatorProjection and GLatLngBounds can be helpful. And if Google Maps API doesn't support calculations for the map projection you are using, then it can be helpful to use Proj4js. And maybe you want to read up about Map projections. Google Maps is by default using Mercator projection.
Here are a number of useful javascript functions for working with latitude and longitude:
http://www.movable-type.co.uk/scripts/latlong.html
For bounding box around a point, a simple modification using the above javascript library might be:
LatLon.prototype.boundingBox = function (distance)
{
return [
this.destinationPoint(-90, distance)._lon,
this.destinationPoint(180, distance)._lat,
this.destinationPoint(90, distance)._lon,
this.destinationPoint(0, distance)._lat,
];
}
(This uses the "Destination point given distance and bearing from start point" calculation.)
If you're using the V3 API, you can make use of Rectangle and Circle. See this blogger's brief description and examples:
http://apitricks.blogspot.com/2010/02/rectangle-and-circle-of-v3.html