Google Maps V3 drag Marker and update PolyLine - javascript

I'm trying to develop an application where the user draws around a property, it adds a marker and a poly line so they can clearly see what's happening. But I want to add the ability to drag the Marker (this is easy) and update the PolyLine's position (this is not so easy?)
Here is some of my code
This is the function that draws my poly lines.
the variable 'll' is an instance of google.maps.LatLng
// Shorter namespace
var _g = google.maps;
// Shorten the namespace, it's used
// a lot in this function
var s = SunMaps;
// If we've reached the max number
// of lines then exit early.
if (s.LINES >= 4) {
return;
}
// The defaults
var options = {
"strokeColor" : "green",
"strokeOpacity" : 1.0,
"strokeWeight" : 4
};
// If we don't have an instance of poly
// create one.
if (s.POLY == false) {
s.POLY = new _g.Polyline(options);
s.PATH = s.POLY.getPath();
}
// Push the new coords into the path object
s.PATH.push(ll);
// Set the map for the poly
s.POLY.setMap(s.instance);
// Add a marker
new s.Marker(ll);
// Increase the counter
s.LINES++;
Draws the markers at the same point (the s.Marker function used in the line code)
the variable 'll' is an instance of google.maps.LatLng
var _g = google.maps;
// Our custom marker
var marker = new _g.Marker({
"position" : ll,
"icon" : {
"path" : _g.SymbolPath.CIRCLE,
"scale": 10
},
"draggable": true,
"map" : SunMaps.instance,
"LineIndex": SunMaps.LINES
});
_g.event.addListener(marker, 'drag', function (e) {
console.log(marker.getPosition());
// Here is where I can't workout or find documentation
// on how to move the line.
});

The path property of the Polyline object is an MVCArray. See https://developers.google.com/maps/documentation/javascript/reference#MVCArray
So, to move the last point you should be able to do:
s.PATH.setAt(s.PATH.getLength() - 1, marker.getPosition());

Okay, So I figured it out. Using #Dave's method
Here is the code that updates the polyLine as you drag the marker
var _g = google.maps;
var _s = SunMaps;
// Our custom marker
var marker = new _g.Marker({
"position" : ll,
"icon" : {
"path" : _g.SymbolPath.CIRCLE,
"scale": 7
},
"draggable": true,
"map" : _s.instance,
// This is the last known index of a polyLine
"lineIndex": _s.LINES
});
// Listen to the drag event
_g.event.addListener(marker, 'drag', function (e) {
// Set the new position of the marker as it drags
this.setPosition(e.latLng);
// Update the path
_s.PATH.setAt(this.lineIndex, this.getPosition());
});

Related

how to remove previous routes in HERE JS API?

I want to remove route from previous calculation in HERE Maps, in my code bellow, if i do two times calculation, the new routes overlay the previous routes.
................................................................................................................................................................
function addRouteShapeToMap(route)
{
// map.removeObject(route.shape);
var strip = new H.geo.Strip(),
routeShape = route.shape,
polyline;
routeShape.forEach(function(point)
{
var parts = point.split(',');
strip.pushLatLngAlt(parts[0], parts[1]);
});
polyline = new H.map.Polyline(strip,
{
style:
{
lineWidth: 4,
strokeColor: 'rgba(0, 128, 255, 0.7)'
}
});
// Add the polyline to the map
map.addObject(polyline);
// And zoom to its bounding rectangle
map.setViewBounds(polyline.getBounds(), true);
}
and this is code for add maneuvers symbol :
function addManueversToMap(route)
{
var svgMarkup = '<svg width="18" height="18" ' +
'xmlns="http://www.w3.org/2000/svg">' +
'<circle cx="8" cy="8" r="8" ' +
'fill="#1b468d" stroke="white" stroke-width="1" />' +
'</svg>',
dotIcon = new H.map.Icon(svgMarkup,
{
anchor:
{
x: 8,
y: 8
}
}),
group = new H.map.Group(), i, j;
// Add a marker for each maneuver
for (i = 0; i < route.leg.length; i += 1)
{
for (j = 0; j < route.leg[i].maneuver.length; j += 1)
{
// Get the next maneuver.
maneuver = route.leg[i].maneuver[j];
// Add a marker to the maneuvers group
var marker = new H.map.Marker({
lat: maneuver.position.latitude,
lng: maneuver.position.longitude
},
{
icon: dotIcon
});
marker.instruction = maneuver.instruction;
group.addObject(marker);
}
}
group.addEventListener('tap', function(evt)
{
map.setCenter(evt.target.getPosition());
openBubble(
evt.target.getPosition(), evt.target.instruction);
}, false);
// Add the maneuvers group to the map
map.addObject(group);
}
than if the route success, where can i place code map.removeObject(route); in this function?
function onSuccess(result)
{
var route = result.response.route[0];
addRouteShapeToMap(route);
addManueversToMap(route);
addWaypointsToPanel(route.waypoint);
addManueversToPanel(route);
addSummaryToPanel(route.summary);
}
help me to solve my code..
This might not be the best solution, but it works for me.
Make sure to provide the same id name both for polyline and group.
Before you map.addObject(polyline), give a name for id:
polyline.id = "route";
// Add the polyline to the map
map.addObject(polyline);
Also the same do for map.addObject(group):
group.id = "route";
// Add the maneuvers group to the map
map.addObject(group);
Finally create a new function as follows:
function removeObjectById(id){
for (object of map.getObjects()){
if (object.id===id){
map.removeObject(object);
}
}
}
When you execute the function by providing id, e.g in your console browser, it will remove both polyline and maneuvers:
removeObjectById("route");
It looks like you are using this example as the basis for your code.
map.removeObject(route) won't work, because route is not an object on the map. The objects you want to remove are the group and polyline objects. To do so you probably want to change the scope of those variables by declaring them outside of the addRouteShapeToMap and addManueversToMap functions. If you declare them at the top of your code:
polyline = new H.map.Polyline(strip, {
style: {
lineWidth: 4,
strokeColor: 'rgba(0, 128, 255, 0.7)'
}
});
var group = new H.map.Group();
you can then use
map.removeObject(polyline);
map.removeObject(group);
to remove the line and markers from the map later on (for example when start another route calculation). Note that onSuccess is not the right place to add this, as the objects would be removed right after adding them, thus preventing them from ever being visible.
Make sure that before map.removeObject(polyline); polyline is set as an object when map.addObject is used.
Instead of adding the route to the map instance, add it to a group.
So here should be the steps that you should follow:
1. Create a group, and have a reference to it.
2. When you add a route, add it to the group (like this)
this.group.addObject(new this.H.map.Polyline(
lineString, { style: { lineWidth: 4 } }
));
When you want to clear the map, you can clear the group (like this)
this.group.removeAll();
I have tested this logic. it is working fine!

Google Maps v3 fitBounds inconsistent zoom

having a very strange problem.
A: One method of my map works fine. User sets start point and end point and map is created and the fitBounds.extend(bounds) sets zoom level appropriately to encompass the start/end markers on the map.
B: The second method is if the user sets a start point but not and end point, but based on other user interests I get retrieve and end point for them and plot it on the map using the same functions as method A. However, upon fitBounds.extend(bounds) it sets the zoom level way out at 4 (country level). Then I have to force set the zoom.
It doesn't matter when at any point the user does method A (before or after method B)...when its method A, the zoom level is correct. When its method B its always to zoom level 4.
...but all using the same functions.
Both methods accurately put the markers on the map and accurately draw the route between the markers. Just on method A, the auto zoom is correct and on method B the zoom is always set to 4.
If user does A, its right...then B happens, its zooms out...does B again it stays zoomed out...does A again it goes back to proper zoom.
Driving me nuts here!
My map object is "setMap", it is a global var
function setMapBounds(start,end) {
mapBounds = new google.maps.LatLngBounds();
mapBounds.extend(start.position);
mapBounds.extend(end.position) ;
setMap.fitBounds(mapBounds) ;
}
function addMarkers(newMarkers) { // an array of map points.
var tempMarkers = [] ;
for (var x=0;x<newMarkers.length;x++) {
var tempLatlon = new google.maps.LatLng(newMarkers[x].lat,newMarkers[x].lon) ;
var tempMarker = createMarker(tempLatlon,newMarkers[x].img,newMarkers[x].title) ;
tempMarkers.push(tempMarker) ;
}
return tempMarkers ;
}
function createMarker(latlon,img,title) {
var marker = new google.maps.Marker({
map:setMap,
position:latlon,
icon: img,
title:title
}) ;
return marker ;
}
// This is Method A - it ALWAYS sets the zoom properly
function setDropoff(dropoffLoc) { //called from: index.js/setPickup(), tab-map.html
geoCoder.geocode({'address': dropoffLoc}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
endLocation = dropoffLoc ;
endLat = results[0].geometry.location.lat() ;
endLon = results[0].geometry.location.lng() ;
// first clear any existing END Markers only.
while(markersArray.length) {
markersArray.pop().setMap(null);
}
endPointSet = 1 ;
endLatlon = new google.maps.LatLng(endLat,endLon) ;
var endMarker = createMarker(endLatlon,'img/red-pin.png','Drop off') ;
markersArray.push(endMarker) ;
setMapBounds(userMarker,endMarker) ;
if (startPointSet == 1) {
drawRoute("DRIVING",startLocation,endLocation) ;
}
}
} else {
error = "Address not found."
}
});
}
// This is method B, it ALWAYS pushees the zoom out to 4. It is pulled out of another function that tests to see if the user manually set and end point...if so, then add wayPoints between user set start/end points. If not, then set map to user start point to a single end point of interest
if (endPointSet == 1) { // draw Pickup to START to wayPoints to END
var markers = [
{lat:interests[0].shub_lat,lon:interests[0].shub_lon,img:interests[0].img,title:"Pickup"},
{lat:interests[1].ehub_lat,lon:interests[1].ehub_lon,img:interests[1].img,title:"Dropoff"}
] ;
var points = [interests.shub_address,interests.ehub_address] ;
extraMarkers = addMarkers(markers) ;
drawRoute("BICYCLING",startLocation,endLocation,points) ;
} else {
var markers = [
{lat:interests[0].shub_lat,lon:interests[0].shub_lon,img:interests[0].img,title:"Dropoff"}
] ;
extraMarkers = addMarkers(markers) ;
setMapBounds(userMarker,extraMarkers[0]) ;
drawRoute("WALKING",startLocation,interests[0].shub_address) ;
}
}
Here is are the objects passed into setMapBounds from the else within Method B. Start point is set by User...but no end point is set, I am picking one for them. The first Object is start, the second object is end.
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 563, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.49799999999999
k: 27.873196
...
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 602, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.47631678090198
k: 27.9374560148825
...
And here are the objects passed into setMapBounds from Method A where the user is setting both the same start and end points. you can see the start point is the same for both Method A and B.
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 563, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.49799999999999
k: 27.873196
...
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 703, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.45717760000002
k: 27.950575
...
I am making a similar application, and the code that I am using is:
var start;
var end;
function updateMap(name, obj){ //obj is a form input i.e. <input type="text">
var marker = (name==='start')?start:end;
geocoder.geocode({address:obj.value}, function(results, status){
//get coords/check if is valid place
if(status === google.maps.GeocoderStatus.OK){
//get info, store in new marker
marker.setPosition(results[0].geometry.location);
marker.setTitle(obj.value);
//if both markers present
if(start.getPosition() && end.getPosition()){
map.fitBounds(new google.maps.LatLngBounds(start.getPosition(), end.getPosition()));
}else{
//otherwise, if one marker
map.setCenter(marker.getPosition());
map.setZoom(15);
}
marker.setMap(map);
}else if(status === google.maps.GeocoderStatus.ZERO_RESULTS){
alert('There is an issue with address. Please refer to the "Help" link.');
}else{
setTimeout(function(){
updateMap(marker, obj);
}, 200);
}
});
}
What this does is take an argument from a text input, geocode it, and place a marker on the map. The function is triggered by an onchange event on the form element. This can be easily adapted for your own usage. If there was only one point, I just settled for a default zoom value (usually pretty close to the street, though you can adjust this however you want).
As for your question of why it is not working, I can formulate a better guess with the entire code. For now, I would think it has something to do with region-biasing, or that it is simply a bug. It is probably just best to work around it.

Setting a Google Maps viewport to automatically fit pane for locations of (n) markers of various locations

The approach I took thus far has been:
function addMarker( query ) {
var geocoder = new google.maps.Geocoder();
var afterGeocode = $.Deferred();
// Geocode 'query' which is the address of a location.
geocoder.geocode(
{ address: query },
function( results, status ){
if( status === 'OK' ){
afterGeocode.resolve( results ); // Activate deferred.
}
}
);
afterGeocode.then( function( results ){
var mOptions = {
position: results[0].geometry.location,
map: map
}
// Create and drop in marker.
var marker = new google.maps.Marker( mOptions );
marker.setAnimation( google.maps.Animation.DROP );
var current_bounds = map.getBounds(); // Get current bounds of map
// use the extend() function of the latlngbounds object
// to incorporate the location of the marker
var new_bounds = current_bounds.extend( results[0].geometry.location );
map.fitBounds( new_bounds ); // fit the map to those bounds
});
}
The problem I'm running into is that the map inexplicably zooms out by some amount, no matter if the new marker fits within the current viewport or not.
What am I doing wrong?
ADDENDUM
I added logs and an additional variable to capture the map bounds after the transition was made (new_new_bounds)
current_bounds = // Map bounds before anything is done.
{-112.39575760000002, 33.60691883366427},
{-112.39295444655761, 33.639099}
new_bounds = // From after the extend
{-112.39295444655761, 33.60691883366427},
{-112.39575760000002, 33.639099}
new_new_bounds = // From after the fitbounds
{-112.33942438265382, 33.588697452015374},
{-112.44928766390382, 33.657309727063996}
OK, so after much wrangling, it turns out that the problem was a map's bounds are not the same as a map's bounds after fitBounds(). What happens (I presume), is Google takes the bounds you give it in the fitBounds() method, and then pads them. Every time you send the current bounds to fitBounds(), You're not going to fit bounds(x,y), you're going to fit bounds(x+m,y+m) where m = the arbitrary margin.
That said, the best approach was this:
var current_bounds = map.getBounds();
var marker_pos = marker.getPosition();
if( !current_bounds.contains( marker_pos ) ){
var new_bounds = current_bounds.extend( marker_pos );
map.fitBounds( new_bounds );
}
So, the map will only fit bounds if a marker placed falls outside the current map bounds. Hope this helps anyone else who hits this problem.
A possible explanation is that you randomly placed your new marker into the gap of the z-curve. A z-curve recursivley subdivide the map into 4 smaller tiles but that's also the reason why there are gaps between the tiles. A better way would be to use a hilbert curve or a moore curve for map applications. There is a patented search algorithm covering this issue, I think it is called multidimensional range query in quadtrees. You want to look for Nick's hilbert curce quadtree spatial index blog.

Openlayers - arrary of info into popupmarker

I have a connection to a database(db). I am getting the lon, lat and name from the db and stroing them:
while ($row_ChartRS = mysql_fetch_array($sql1))
{
$latitude=$row_ChartRS['latitude'];
$longitude=$row_ChartRS['longitude'];
$bus_name =$row_ChartRS['short_name'];
//echo $latitude.'--'.$longitude.'<br>';
echo $bus_name;
I then create a map to display the data. The markers are working fine for all lat, lon locations. Code:
function init()
{
projLonLat = new OpenLayers.Projection("EPSG:4326"); // WGS 1984
projMercator = new OpenLayers.Projection("EPSG:900913"); // Spherical Mercator
overviewMap = new OpenLayers.Control.OverviewMap();
//adding scale ruler
scale = new OpenLayers.Control.ScaleLine();
scale.geodesic = true; // get the scale projection right, at least on small
map = new OpenLayers.Map('demoMap',
{ controls: [ new OpenLayers.Control.Navigation(), // direct panning via mouse drag
new OpenLayers.Control.Attribution(), // attribution text
new OpenLayers.Control.MousePosition(), // where am i?
new OpenLayers.Control.LayerSwitcher(), // switch between layers
new OpenLayers.Control.PanZoomBar(), // larger navigation control
scale,
overviewMap // overview map
]
}
);
map.addLayer(new OpenLayers.Layer.OSM.Mapnik("Mapnik"));
map.addLayer(new OpenLayers.Layer.OSM.Osmarender("Osmarender"));
//Create an explicit OverviewMap object and maximize its size after adding it to the map so that it shows
//as activated by default.
overviewMap.maximizeControl();
//Adding a marker
markers = new OpenLayers.Layer.Markers("Vehicles");
map.addLayer(markers);
vectorLayer = new OpenLayers.Layer.Vector('Routes');
map.addLayer(vectorLayer);
for (k in Locations)
{
//adding a popup for the marker
var feature = new OpenLayers.Feature(markers, new OpenLayers.LonLat(Locations[k].lon, Locations[k].lat).transform(projLonLat,projMercator));
//true to close the box
feature.closeBox = true;
feature.popupClass = new OpenLayers.Class(OpenLayers.Popup.AnchoredBubble,
{
//create the size of the box
'autoSize': true,
'maxSize': new OpenLayers.Size(100,100)
});
//add info into box
for (z in names)
{
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
//puts a scroll button on box to scroll down to txt
//feature.data.overflow = "auto";
marker = feature.createMarker();
marker.display(true);
markerClick = function (evt) {
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;
OpenLayers.Event.stop(evt);
};
marker.events.register("mousedown", feature, markerClick);
markers.addMarker(marker);
map.setCenter(new OpenLayers.LonLat(Locations[k].lon, Locations[k].lat).transform(projLonLat,projMercator), zoom);
var lonLat1 = new OpenLayers.LonLat(Locations[k].lon,Locations[k].lat).transform(new OpenLayers.Projection('EPSG:4326'), map.getProjectionObject());
var pos2=new OpenLayers.Geometry.Point(lonLat1.lon,lonLat1.lat);
points1.push(pos2);
//Uncomment to put boxes in when map opens
//feature.popup = feature.createPopup(feature.closeBox);
//map.addPopup(feature.popup);
//feature.popup.show()
}
var lineString = new OpenLayers.Geometry.LineString(points1);
var lineFeature = new OpenLayers.Feature.Vector(lineString,'',style_green);
vectorLayer.addFeatures([lineFeature]);
map.setCenter(lonLat1,zoom);
} //function
However the name in the popup marker is the same for all markers. i.e. the last name pulled from the db. Can anyone please help with this - I have spent 3 full days trying to fix it!
Thanks in advance!
A few comments:
The PHP code you’ve posted is completely irrelevant, since it’s not seen to be used anywhere.
The objects names and Locations aren’t declared anywhere in the code you posted. What do they contain?
In the code quoted below, you’re creating multiple new Feature objects, but you assign them all to the same property (thereby overwriting that property each time). Is that intentional?
//add info into box
for (z in names) {
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
Edit:
This does appear to be where it’s going wrong. You should remove the for...z loop, and replace it with the following code:
//add info into box
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[k]).transform(projLonLat,projMercator));
Since in PHP, you’re using the same index ($v) to fill both arrays, it makes sense to use the same index to read them in javascript...
Aside from that, using the for...in loop on Javascript arrays is not considered good practice, for a number of reasons. It’s better to use the following:
for (k = 0; k < Locations.length; k += 1) {
// your code
}
i had the same problem , and i solve it ...
the problem is overwrite
you don't have to loop inside your function , do the loop for function for example:
function init(z)
{
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
for (z in names)
{
init(z)
}

Google Maps v3: Enforcing min. zoom level when using fitBounds

I'm drawing a series of markers on a map (using v3 of the maps api).
In v2, I had the following code:
bounds = new GLatLngBounds();
... loop thru and put markers on map ...
bounds.extend(point);
... end looping
map.setCenter(bounds.getCenter());
var level = map.getBoundsZoomLevel(bounds);
if ( level == 1 )
level = 5;
map.setZoom(level > 6 ? 6 : level);
And that work fine to ensure that there was always an appropriate level of detail displayed on the map.
I'm trying to duplicate this functionality in v3, but the setZoom and fitBounds don't seem to be cooperating:
... loop thru and put markers on the map
var ll = new google.maps.LatLng(p.lat,p.lng);
bounds.extend(ll);
... end loop
var zoom = map.getZoom();
map.setZoom(zoom > 6 ? 6 : zoom);
map.fitBounds(bounds);
I've tried different permutation (moving the fitBounds before the setZoom, for example) but nothing I do with setZoom seems to affect the map. Am I missing something? Is there a way to do this?
At this discussion on Google Groups I discovered that basically when you do a fitBounds, the zoom happens asynchronously so you need to capture the zoom and bounds change event. The code in the final post worked for me with a small modification... as it stands it stops you zooming greater than 15 completely, so used the idea from the fourth post to have a flag set to only do it the first time.
// Do other stuff to set up map
var map = new google.maps.Map(mapElement, myOptions);
// This is needed to set the zoom after fitbounds,
google.maps.event.addListener(map, 'zoom_changed', function() {
zoomChangeBoundsListener =
google.maps.event.addListener(map, 'bounds_changed', function(event) {
if (this.getZoom() > 15 && this.initialZoom == true) {
// Change max/min zoom here
this.setZoom(15);
this.initialZoom = false;
}
google.maps.event.removeListener(zoomChangeBoundsListener);
});
});
map.initialZoom = true;
map.fitBounds(bounds);
Anthony.
Without trying it, I'd say you should be able to do it just by having fitBounds() before you get the zoom level, i.e.
map.fitBounds(bounds);
var zoom = map.getZoom();
map.setZoom(zoom > 6 ? 6 : zoom);
If you did try that and it didn't work, you can setup your map with minZoom in the MapOptions (api-reference) like this:
var map = new google.maps.Map(document.getElementById("map"), { minZoom: 6 });
This would keep the map from zooming any further out when using fitBounds().
Anthony's solution is very nice. I only needed to fix the zoom for the inital page load (ensuring that you weren't too far zoomed in to start with) and this did the trick for me:
var zoomChangeBoundsListener =
google.maps.event.addListener(map, 'bounds_changed', function(event) {
google.maps.event.removeListener(zoomChangeBoundsListener);
map.setZoom( Math.min( 15, map.getZoom() ) );
});
map.fitBounds( zoomBounds );
You can also set the maxZoom option just before calling fitBounds() and reset the value afterwards:
if(!bounds.isEmpty()) {
var originalMaxZoom = map.maxZoom;
map.setOptions({maxZoom: 18});
map.fitBounds(bounds);
map.setOptions({maxZoom: originalMaxZoom});
}
When you call map.fitBounds() on one item - the map may zoom in too closely. To fix this, simply add 'maxZoom' to mapOptions...
var mapOptions = {
maxZoom: 15
};
In my case, I simply wanted to set the zoom level to one less than what google maps chose for me during fitBounds. The purpose was to use fitBounds, but also ensure no markers were under any map tools, etc.
My map is created early and then a number of other dynamic components of the page have an opportunity to add markers, calling fitBounds after each addition.
This is in the initial block where the map object is originally created...
var mapZoom = null;
Then this is added to each block where a marker is added, right before the map.fitBounds is called...
google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
if (mapZoom != map.getZoom()) {
mapZoom = (map.getZoom() - 1);
map.setZoom(mapZoom);
}
});
When using 'bounds_changed' without the check in place, the map zoomed out once for every marker regardless of whether it needed it or not. Conversely, when I used 'zoom_changed', I would sometimes have markers under map tools because the zoom didn't actually change. Now it is always triggered, but the check ensures that it only zooms out once and only when needed.
Hope this helps.
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 (initial == true){
if (map.getZoom() > 11) {
map.setZoom(11);
initial = false;
}
}
});
I used initial to make the map not zooming too much when the eventual fitBounds is permorfed, but to let the user zoom as much as he/she wants. Without the condition any zoom event over 11 would be possible for the user.
I found the following to work quite nicely. It is a variant on Ryan's answer to https://stackoverflow.com/questions/3334729/.... It guarantees to show an area of at least two times the value of offset in degrees.
const center = bounds.getCenter()
const offset = 0.01
const northEast = new google.maps.LatLng(
center.lat() + offset,
center.lng() + offset
)
const southWest = new google.maps.LatLng(
center.lat() - offset,
center.lng() - offset
)
const minBounds = new google.maps.LatLngBounds(southWest, northEast)
map.fitBounds(bounds.union(minBounds))
I just had the same task to solve and used a simple function to solve it.
it doesn't care how many Markers are in the bounds - if there are a lot and the zoom is already far away, this zooms a little bit out, but when there is only one marker (or a lot very close to each other), then the zoomout is significant (customizable with the extendBy variable):
var extendBounds = function() {
// Extends the Bounds so that the Zoom Level on fitBounds() is a bit farer away
var extendBy = 0.005;
var point1 = new google.maps.LatLng(
bounds.getNorthEast().lat() + extendBy,
bounds.getNorthEast().lng() + extendBy
)
var point2 = new google.maps.LatLng(
bounds.getSouthWest().lat() - extendBy,
bounds.getSouthWest().lng() - extendBy
)
bounds.extend(point1);
bounds.extend(point2);
}
To use it, I use an own function to do the fitBounds():
map is my GoogleMap Object
var refreshBounds = function() {
extendBounds();
map.fitBounds(bounds);
}

Categories

Resources