jquery-ui-map fit bounds with a polyline? - google-maps

I'm working on a mobile app using jQuery Mobile. I also you the plugin "jquery-ui-map" to do my map (that helped alot with display issues using only GMap with jQM).
I'm able to add polyline on the map and it works just fine. But when I try to use the fitBounds method, it doesn't work. In fact, it zoom out alot. But not on my bounds.
Here is my code :
// Added some data, so you can understand the structure
// of variable "plan"
plan[0].lat_a = 45.4681; plan[0].lng_a = -73.7414;
plan[0].lat_b = 45.6797; plan[0].lng_b = -74.0386;
plan[1].lat_a = 45.6797; plan[1].lng_a = -74.0386;
plan[1].lat_b = 48.7753; plan[1].lng_b = -64.4786;
var polylinesCoords = new Array();
var bounds = new google.maps.LatLngBounds();
// Starting point
var LatLng = new google.maps.LatLng(plan[0].lat_a, plan[0].lng_a);
bounds.extend(LatLng);
// Building the polyline coords and bounds
for (var x=0; x<plan.length; x++) {
polylinesCoords.push(new google.maps.LatLng(plan[x].lat_a, plan[x].lng_a), new google.maps.LatLng(plan[x].lat_b, plan[x].lng_b));
LatLng = new google.maps.LatLng(plan[x].lat_b, plan[x].lng_b);
bounds.extend(LatLng);
}
// Drawing polyline on map
$('#map_canvas').gmap('addShape', 'Polyline', {
'path': polylinesCoords,
'strokeColor': '#c00',
'strokeThickness': 5
});
// «Focus» map on polyline with bounds
var map = $("#map_canvas").gmap("get", "map");
map.fitBounds(bounds);
Everything in this snippet seems to works fine, except for the very last line.
Any ideas ?

You might've missed to center the map to any of your pin. I got your code working with this line of code
$('#map_canvas').gmap('option', 'center', (new google.maps.LatLng(plan[0].lat_a,plan[0].lng_a)));

Related

Google Maps: scroll map programmatically of x pixels

Is there a simple way to scroll a google map programmatically of x pixels?
I can only think of using setCenter, but the problem is that I would have to compute the new location (lat/lng) depending on the zoom level...
Can you think of something else? Telling me that it's not possible with the Google Map API is a valid answer if you're pretty sure about it.
ps: I'm using Gmaps4rails, so if you can think of a way to do that with the gem, it'd be cool. (like adjusting the bounds to a subset of the map.)
Because in the end my goal is to prevent the menu from hidding some markers. I would need to change the viewport of the map, if that makes sense, so that it fits the markers into the orange area, not the full map.
Solution:
#Shane Best, great, the idea works perfectly, but I think your solution was for Google API v2, right? Here's how I did it for V3:
var point = map.getCenter();
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
var projection = overlay.getProjection();
var pixelpoint = projection.fromLatLngToDivPixel(point);
pixelpoint.x += my_value; # or .y
point = projection.fromDivPixelToLatLng(pixelpoint);
map.setCenter(point);
If anybody knows about a better solution with API v3, tell us about it.
Take a look at the projection object:
http://code.google.com/apis/maps/documentation/javascript/reference.html#Projection
First you would need to get the center of the map.
var point = map.getCenter();
Convert the latlng to a point value.
var pixelpoint = projection.fromLatLngToPoint(point);
Add yourvalue to the point values.
pixelpoint.x = pixelpoint.x + yourvalue;
//or
pixelpoint.y = pixelpoint.y + yourvalue;
Convert it back to a latLng.
var newpoint = projection.fromPointToLatLng(pixelpoint);
Set the new center with the new value.
map.setCenter(newpoint);
I haven't tested the above but it should work.
I believe you are looking for this:
var panListener = google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
map.panBy(0,-90);
});
setTimeout(function() {
google.maps.event.removeListener(panListener)
}, 2000);
In this case, it moves the map south by 90px.

Google Maps API 3 overlay, need to get the projection

I'm trying to do an overlay on Google Maps. I have generated tiles of my image using maptiler, but the example generated by maptiler is in v2 and i want to use v3. The example generated by maptiler is also very complex and does some unnecessary opacity stuff. Now v3 of GM has changed a lot since v2 and i have some problems to generate the LatLng of a certain point on the screen. getProjection() keeps being undefined, whatever i do, any idea how to get the projection?
<script>
var mapBounds = new google.maps.LatLngBounds();
var mapMinZoom = 8;
var mapMaxZoom = 14;
var overlay;
var maptiler = new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
if ((zoom < mapMinZoom) || (zoom > mapMaxZoom)) {
return "none.png";
}
var ymax = 1 << zoom;
var y = ymax - coord.y -1;
var tileBounds = new google.maps.LatLngBounds(
overlay.getProjection().fromDivPixelToLatLng( new google.maps.Point( (coord.x)*256, (coord.y+1)*256 ) , zoom ),
overlay.getProjection().fromDivPixelToLatLng( new google.maps.Point( (coord.x+1)*256, (coord.y)*256 ) , zoom )
);
if (mapBounds.intersects(tileBounds)) {
return "" + zoom + "/" + coord.x + "/" + (Math.pow(2,zoom)-coord.y-1) + ".png";
} else {
return "none.png";
}
},
tileSize: new google.maps.Size(256, 256),
isPng: true
});
var map;
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"));
map.setZoom(11);
map.setMapTypeId('satellite');
mapBounds.extend(new google.maps.LatLng(50.9388615939, 3.80480816501));
mapBounds.extend(new google.maps.LatLng(51.4402541425, 4.73612507791));
map.fitBounds(mapBounds);
overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
map.overlayMapTypes.insertAt(0, maptiler);
}
</script>
the overlay part is a hack i found on the internet which supposed to get you to the projection. unfortunately it didn't work. Any idea's how to fix this? in V2 you could do something like this:
var mercator = new GMercatorProjection()
mercator.fromPixelToLatLng( new GPoint( (tile.x)*256, (tile.y+1)*256 ) , zoom )
But this isn't possible anymore in v3.
Anyone that can help?
The example generated by maptiler can be found here:
http://gmapsexample.staging1.kunstmaan.be/googlemapsv2.html
This is a simple example in v3 which works:
http://gmapsexample.staging1.kunstmaan.be/googlemapsv3_simple.html
but i want everything except the map to be a specific color, so this is the example i'm trying to get working:
http://gmapsexample.staging1.kunstmaan.be/googlemapsv3.html
thanks,
Daan
You do not need to worry about getting or setting the projection if you are using MapTiler
These two YouTube videos will walk you through (among other things) using MapTiler with Google Maps API v3 map styled to be a certain color which is (if I understand correctly) exactly what you're asking about:
http://www.youtube.com/watch?v=CeSFUSZLeao
http://www.youtube.com/watch?v=WqSOLca2xOc
Try this as your Mercator function:
function GMercatorProjection() {
this.pixelOrigin_ = new google.maps.Point(tileSize / 2, tileSize / 2);
this.pixelsPerLonDegree_ = tileSize / 360;
this.pixelsPerLonRadian_ = tileSize / (2 * Math.PI)
}
Check the documentation about custom overlays in API3
https://code.google.com/apis/maps/documentation/javascript/overlays.html#CustomOverlays

Google Maps v3 fitBounds() Zoom too close for single marker

Is there a way to set a max zoom level for fitBounds()?
My problem is that when the map is only fed one location, it zooms in as far as it can go, which really takes the map out of context and renders it useless. Perhaps I am taking the wrong approach?
I like mrt's solution (especially when you don't know how many points you will be mapping or adjusting for), except it throws the marker off so that it isn't in the center of the map anymore. I simply extended it by an additional point subtracting .01 from the lat and lng as well, so it keeps the marker in the center. Works great, thanks mrt!
// Pan & Zoom map to show all markers
function fitToMarkers(markers) {
var bounds = new google.maps.LatLngBounds();
// Create bounds from markers
for( var index in markers ) {
var latlng = markers[index].getPosition();
bounds.extend(latlng);
}
// Don't zoom in too far on only one marker
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
bounds.extend(extendPoint1);
bounds.extend(extendPoint2);
}
map.fitBounds(bounds);
// Adjusting zoom here doesn't work :/
}
You can setup your map with maxZoom in the MapOptions (api-reference) like this:
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });
This would keep the map from zooming any deeper when using fitBounds() and even removes the zoom levels from the zoom control.
Another solution is to expand bounds if you detect they are too small before you execute fitBounds():
var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
bounds.extend(extendPoint);
}
map.fitBounds(bounds);
Once you've added all of the real bounds add these lines
var offset = 0.002;
var center = bounds.getCenter();
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));
it get the center of the real bounds then adds two additional points one to the northeast and one to the southwest of you center
This effectively sets the minimum zoom, change the value of offset to increase or decrease the zoom
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });
Using the MaxZoom option works best for not zooming to close on to the marks you have.
If it is for a single location, you can use setCenter() and setZoom() instead.
u can use
map.setOptions({
maxZoom: [what u want],
minZoom: [what u want]
});
this way u set the properties of the map after the map has been initialized .... u can set them as many times as u want ... but in ur case ... u can set them before fitBounds()
good luck,
rarutu
The way I prevent the map from zooming in to far is by adding this line of code:
var zoomOverride = map.getZoom();
if(zoomOverride > 15) {
zoomOverride = 15;
}
map.setZoom(zoomOverride);
Directly after this line:
map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
Feel free to change the zoom level to whatever level you don’t want the map to zoom past.
If you have any problems or questions, just leave me a comment on the blog post I wrote about this at http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the-map-from-zooming-in-too-close-on-a-single-marker
I really like mrt's solution and it works perfectly if you've always only have one point to work with. I did however find that if the bounding box was not based on one point, but the points were very close together, this could still cause the map to be zoomed in too far.
Here's a way to first check if the points are within a defined distance of each other, then if they are smaller than that minimum distance, extend the bounds by that minimum distance:
var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();
if((sumA < minDistance && sumA > -minDistance)
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
bounds.extend(extendPoint1);
bounds.extend(extendPoint2);
}
Hope this helps someone!
As for me guys i solve it by creating an idle event after fitBounds. Working perfectly. Guess that's one of the most clean solutions here
var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10
});
.... create markers, etc.
}
....
map.fitBounds(bounds);
google.maps.event.addListenerOnce(map, 'idle', function() {
if (locations.length == 1) {
map.setZoom(11);
}
});
This gives you a direct control upon max allowed zoom on bounds fitting.
var fitToMarkers = function(map, markers, maxZoom) {
if (typeof maxZoom == 'undefined') maxZoom = 15;
google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
if (this.getZoom() > maxZoom) {
this.setZoom(maxZoom);
}
});
var bounds = new google.maps.LatLngBounds();
for (var m = 0; m < markers.length; m++) {
var marker = markers[m];
var latlng = marker.getPosition();
bounds.extend(latlng);
}
map.fitBounds(bounds);
};
I solved with this chunk, since Google Maps V3 is event driven:
you can tell the API to set back the zoom to a proper amount when the zoom_changed event triggers:
var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
if (intial == true){
if (map.getZoom() > 11) {
map.setZoom(11);
intial = false;
}
}
});
I used intial make the map not zooming too much loading when the eventual fitBounds permorfed, without it any zoom event over 11 would be impossible for the user.
After calling fitBounds() method, try to setup zoom level again. It will force the map to be at that zoom level whilst being centered at the right place.
I have soulution based on limiting max zoom when fitting bounds. Works for me (tested on Win 7 - IE 9, FF 13, Chrome 19):
// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..
// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;
// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
// set max zoom only when fitting bounds
if (window.fittingBounds && map.getZoom() > 16) {
this.setZoom(16);
}
});
And .. here is another one.
Same idea as mrt and Ryan, but
also works if bounds size is not exactly zero (*)
prevents distortion near the poles
uses getCenter() instead of getNorthEast()
(*) Note: If the box is already big enough, then adding those two extra points should have no effect. So we don't need any further checking.
function calcBounds(markers) {
// bounds that contain all markers
var bounds = new google.maps.LatLngBounds();
// Using an underscore _.each(). Feel free to replace with standard for()
_.each(markers, function(marker) {
bounds.extend(marker.getPosition());
});
// prevent lat/lng distortion at the poles
var lng0 = bounds.getNorthEast().lng();
var lng1 = bounds.getSouthWest().lng();
if (lng0 * lng1 < 0) {
// Take the cos at the equator.
var cos = 1;
}
else {
var cos0 = Math.cos(lng0);
var cos1 = Math.cos(lng1);
// Prevent division by zero if the marker is exactly at the pole.
var cos_safe = Math.max(cos0, cos1, 0.0001);
}
var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
// "radius" in either direction.
// 0.0006 seems to be an ok value for a typical city.
// Feel free to make this value a function argument.
var rLat = 0.0006;
var rLng = rLat / cos_safe;
// expand the bounds to a minimum width and height
var center = bounds.getCenter();
var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
bounds.extend(p0);
bounds.extend(p1);
return bounds;
}
EDIT: I am not exactly sure if my ratio calculation correctly, considering we have a Mercator projection. I might re-edit this..
Its already answered here Google Maps v3: Enforcing min. zoom level when using fitBounds it works as expected :) so now if after fit bounds zoom is less then lets say 13 then you can set new zoom which you preffer
Here is my go at a solution, which also works when two markers are very close. The effective maximum zoom level is the same in both situations. So we do not end up zooming unneccesarily out, when there are more than one marker
The effect, again is ensuring a maximum zoom, without using the maxZoom option, which has the probably unwanted effect of making it impossible for the user to zoom further than the maxZoom level with the zoom control
I have calculated maxLat, minLat, maxLng and minLng beforehand...
var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
// ensures that we do not zoom in too much
var delta = (minLatSpan - (maxLat - minLat)) / 2;
maxLat += delta;
minLat -= delta;
}
map.fitBounds({
east: maxLng,
west: minLng,
north: maxLat,
south: minLat,
});

set zoom level when marker is removed

using javascript google-maps api
I currently have it setup to remove a maker I set it up when I am adding a location like so
function addLocation(map,location) {
var point = new GLatLng(location.lat, location.lon);
var marker = new GMarker(point);
map.addOverlay(marker);
bounds.extend(marker.getPoint());
$('<a href="#" class="closebutton">').click(function(e){
e.preventDefault();
$(this).parent().remove();
map.removeOverlay(marker);
map.closeInfoWindow();
}).prependTo($('<li>'+location.label+'</li>').click(function() {
showMessage(marker, location.label,map);
}).appendTo("#list"));
GEvent.addListener(marker, "click", function() {
showMessage(marker, location.label,map);
});
}
then I have a function that sets the zoom level
function zoomToBounds(map) {
map.setCenter(bounds.getCenter());
map.setZoom(map.getBoundsZoomLevel(bounds) - 1);
}
this is called after my addLocations function and does what I want it do and sets the zoom level so I can see all the makers.
Now if I put a call to zoomToBounds right after
map.removeOverlay(marker);
then it doesn't move it just stays at the same zoom level
so what I want to know is if there is a way for me to set the zoom level after I remove a marker ??
Hey there - this is definitely something you can accomplish using Google Maps API.
One important thing that you need to make sure you do is update the GLatLngBounds object before attempting to have the GMap2 object recalculate it's position and zoom level.
To do this, I would suggest keeping some sort of data store of all the points the GMarkers are using.
Using GEvent Listeners you can also tie the zoomToBounds function to an event, when a GMarker is removed.
Here is a code snippet of what I am talking about:
var bounds = new GLatLngBounds();
var points = {};
function createMarker(location)
{
/*Create Our Marker*/
var point = new GLatLng(location.lat,location.lon);
var marker = new GMarker(point);
/*Add an additional identifier to the Marker*/
marker.myMarkerName = 'uniqueNameToIDMarkerPointLater';
/*Store the point used by this Marker in the points object*/
points[marker.myMarkerName] = point;
/*Create an event that triggers after the marker is removed to call zoomToBounds*/
GEvent.addListener(marker,"remove",function()
{
/*Passes the marker's ID to zoomToBounds*/
zoomToBounds(this.myMarkerName);
};
/*Add the new point to the existing bounds calculation*/
bounds.extend(point);
/*Draws the Marker on the Map*/
map.addOverlay(marker);
}
function zoomToBounds(name)
{
/*Remove the Point from the Point Data Store*/
points[name]=null;
/*Create a new Bounds object*/
bounds = new GLatLngBounds();
/*Iterate through all our points and build our new GLatLngBounds object*/
for (var point in points)
{
if (points[point]!=null)
{
bounds.extend(points[point]);
}
}
/*Calculate the Position and Zoom of the Map*/
map.setCenter(bounds.getCenter());
map.setZoom(map.getBoundsZoomLevel(bounds)-1);
}
The GLatLngBounds object does not store all of the points that it used to calculate it's maximum and minimum bounds - so a new object needs to be created to redefine the bounds of the rectangle.
I also created a functioning example of this located
here.
Feel free to use the source code to whatever you need - let me know how you make out with it, or if you have any other questions!
Here is the code without any comments:
var bounds = new GLatLngBounds();
var points = {};
function createMarker(location)
{
var point = new GLatLng(location.lat,location.lon);
var marker = new GMarker(point);
marker.myMarkerName = 'uniqueNameToIDMarkerPointLater';
points[marker.myMarkerName] = point;
GEvent.addListener(marker,"remove",function()
{
zoomToBounds(this.myMarkerName);
};
bounds.extend(point);
map.addOverlay(marker);
}
function zoomToBounds(name)
{
points[name]=null;
bounds = new GLatLngBounds();
for (var point in points)
{
if (points[point]!=null)
{
bounds.extend(points[point]);
}
}
map.setCenter(bounds.getCenter());
map.setZoom(map.getBoundsZoomLevel(bounds)-1);
}

How to set google map custom zoom level dynamically?

I am working with google map. According to requirements i need to set different zoom level that is dependent to my search query.If there are multiple location on the map in country then map should focus the country. Other scenario is , if there are different locations marked in a city then map should be focused to city level.
var geoCoder = new GClientGeocoder();
geoCoder.setViewport(map.getBounds());
geoCoder.getLocations('searchquery', function(latlng) {
if( latlng.Placemark.length > 0 ) {
var box = latlng.Placemark[0].ExtendedData.LatLonBox;
var bounds = new GLatLngBounds(new GLatLng(box.south, box.west), new GLatLng(box.north, box.east));
var center = new GLatLng(box.Placemark[0].Point.coordinates[1], latlng.Placemark[0].Point.coordinates[0]);
var zoom = oMap.getBoundsZoomLevel(bounds);
map.setCenter(center, zoom);
}
});
I think the key part of this for you is
//box is a LatLonBox with the size of your resultquery. You can create this yourself as well
var box = latlng.Placemark[0].ExtendedData.LatLonBox;
//bounds are the bounds of the box
var bounds = new GLatLngBounds(new GLatLng(box.south, box.west), new GLatLng(box.north, box.east));
//center is the center of the box, you want this as the center of your screen
var center = new GLatLng(box.Placemark[0].Point.coordinates[1], latlng.Placemark[0].Point.coordinates[0]);
//zoom is the zoomlevel you need for all this
var zoom = oMap.getBoundsZoomLevel(bounds);
//the actual action
map.setCenter(center, zoom);
After you perform the search, once you have the locations, you can use bounds.extend and map.fitBounds so the map automatically zooms to show all the pins returned by your search, like this:
//places is an array that contains the search result
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
//pass the location of each place to bounds.extend
bounds.extend(place.geometry.location);
}
//tell your map to sets the viewport to contain all the places.
map.fitBounds(bounds);
On the other hand, if you do a search for a zone like zip code, city or country using the geo coder, you can also use map.fitBounds to set the viewport to show the entire specific zone that was returned by the geo coder, like this:
//response is the geocoder's response
map.fitBounds(response[0].geometry.viewport);
Here's a codepen with the geocoder example https://codepen.io/jaireina/pen/gLjEqY
I found following article very helpful. using code sample code I can able to achieveenter link description here this.
I tried the code in drupal and it is working.