newPosition = new CameraPosition(new LatLng(latitude, longitude), zoomLevel, tilt, currentBearing);
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(newPosition);
googleMap.animateCamera(cameraUpdate);
When I zoom in or move the camera to another point using animateCamera(), it takes a long time for it to refresh the map (it looks blurry). But if I tap the screen or slightly move the camera manually after animation ends, it immediately refreshes.
it looks like this after moving the camera
I want it to refresh and look like this after animation
I searched it in google maps documents but I didn't find a method for refreshing the map. Is there a way to refresh it programmatically?
I fixed this by calling moveCamera() when the animation ends. I am moving the camera to the same location just to make google maps load the map immediately. Couldn't find a better way.
CameraPosition newPosition = newCameraPosition(newLatLng(latitude,longitude), zoomLevel, tilt, currentBearing);
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(newPosition);
googleMap.animateCamera(cameraUpdate, new GoogleMap.CancelableCallback() {
#Override public void onCancel() {}
#Override
public void onFinish() {
googleMap.moveCamera(cameraUpdate);
}
});
I have a page(fragment) that shows google maps together with 1 marker icon. So now i would like to pass source and destination coordinates to this map so that it can show the shortest route together with the distance in Km. E.g i want the map to show the blue path in the image below :
Here is my code :
private void SetUpMap()
{
if (GMap == null)
{
ChildFragmentManager.FindFragmentById<MapFragment>(Resource.Id.googlemap).GetMapAsync(this);
}
}
public void OnMapReady(GoogleMap googleMap)
{
this.GMap = googleMap;
GMap.UiSettings.ZoomControlsEnabled = true;
LatLng latlng = new LatLng(Convert.ToDouble(gpsLatitude), Convert.ToDouble(gpsLongitude));
CameraUpdate camera = CameraUpdateFactory.NewLatLngZoom(latlng, 15);
GMap.MoveCamera(camera);
MarkerOptions options = new MarkerOptions()
.SetPosition(latlng)
.SetTitle("Chennai");
GMap.AddMarker(options);
}
I got my answer from this post :
Adding polyline between two locations google maps api v2
I converted the java code to C# and it worked fine.
I'd like to be able add padding to a map view after calling a map.fitBounds(), so all markers can be visible regardless of map controls or things like sliding panels that would cover markers when opened. Leaftlet has an option to add padding to fitBounds, but Google Maps does not.
Sometimes the northmost markers partially hide above the viewport. The westmost markers also often lay under the zoom slider. With API 2 it was possible to form a virtual viewport by reducing given paddings from the map viewport and then call the method showBounds() to calculate and perform zooming and centering based on that virtual viewport:
map.showBounds(bounds, {top:30,right:10,left:50});
A working example of this for API 2 can be found here under the showBounds() example link.
I cannot find similar functionality in API V3, but hopefully there is another way this can be accomplished. Maybe I could grab the northeast and southwest points, then add fake coordinates to extend the bounds further after including them?
UPDATE
(Codepen in case the code below doesn't work)
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
draggable: true,
streetViewControl: false,
zoomControl: false
});
var marker1 = new google.maps.Marker({
position: {lat: 37, lng: -121},
map: map,
});
var marker2 = new google.maps.Marker({
position: {lat: 39.3, lng: -122},
map: map,
});
var bounds = new google.maps.LatLngBounds();
bounds.extend(marker1.position);
bounds.extend(marker2.position);
map.fitBounds(bounds);
}
#map {
height: 640px;
width: 360px;
}
#overlays {
position: absolute;
height: 50px;
width: 340px;
background: white;
margin: -80px 10px;
text-align: center;
line-height: 50px;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Simple markers</title>
</head>
<body>
<div id="map"></div>
<div id="overlays">Controls / Order pizza / ETA / etc.</div>
<script async defer
src="https://maps.googleapis.com/maps/api/js?&callback=initMap">
</script>
</body>
</html>
The problem is this:
I've tried adding a control as documented at Custom controls, but the map isn't exactly aware of it - see this fiddle forked from the Maps custom control example. One of the markers is still obscured by the control.
This is some kind of a hack-ish solution, but after the fitBounds, you could zoom one level out, so you get enough padding for your markers.
Assume map variable is your reference to the map object;
map.setZoom(map.getZoom() - 1);
As of June 2017 the Maps JavaScript API is supporting the padding parameter in the fitBounds() method.
fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)
Please refer to the documentation for further details
https://developers.google.com/maps/documentation/javascript/reference#Map
You can use map.fitBounds() with API V3 with the same padding syntax as you mentioned with map.showBounds().
Simply using map.fitBounds(bounds, {top:30,right:10,left:50}); worked for me.
(this could be comment to xomena's or Roman86' post, I don't have enough reputation to comment)
I solved this problem by extended the map bounds to include a latlng that sufficiently pushed the markers into view.
Firstly you need to create an overlay view
var overlayHelper = new google.maps.OverlayView();
overlayHelper.onAdd = function() {};
overlayHelper.onRemove = function() {};
overlayHelper.draw = function() {};
overlayHelper.setMap(map);
Once you have an overlay helper you need to get the map projection and perform calcs based on that.
Note that the control that I have on my map is a 420 pixel wide, 100% height div on the far right of the map. You will obviously need to change the code to accomodate your controls.
var mapCanvas = $("#map_canvas"),
controlLeft = mapCanvas.width() - 420, // canvas width minus width of the overlayed control
projection = overlayHelper.getProjection(),
widestPoint = 0,
latlng,
point;
// the markers were created elsewhere and already extended the bounds on creation
map.fitBounds(mapBounds);
// check if any markers are hidden behind the overlayed control
for (var m in markers) {
point = projection.fromLatLngToContainerPixel(markers[m].getPosition());
if (point.x > controlLeft && point.x > widestPoint) {
widestPoint = point.x;
}
}
if (widestPoint > 0) {
point = new google.maps.Point(
mapCanvas.width() + (widestPoint - controlLeft),
mapCanvas.height() / 2); // middle of map height, since we only want to reposition bounds to the left and not up and down
latlng = projection.fromContainerPixelToLatLng(point);
mapBounds.extend(latlng);
map.fitBounds(mapBounds);
}
If you're doing this when the map loads for the first time, then you will need to wrap this in a map event to wait for idle. This allows the overlay view to initialize. Don't include the overlay helper creation within the event callback.
google.maps.event.addListenerOnce(map, 'idle', function() { <above code> });
Updated
Google Maps API now supports a native "padding" param in the fitBounds method (from version 3.32, correct me if earlier).
I had no chance yet to test it, but if you're able to upgrade - I would recommend to use a native way. If you're using version < 3.32 and can't upgrade - my solution is for you.
I took working solution by erzzo and improved it a little bit.
Example
fitBoundsWithPadding(googleMapInstance, PolygonLatLngBounds, {left:250, bottom:10});
Arguments description:
gMap - google map instance
bounds - google maps LatLngBounds object to fit
paddingXY - Object Literal: 2 possible formats:
{x, y} - for horizontal and vertical paddings (x=left=right, y=top=bottom)
{left, right, top, bottom}
function listing to copy
function fitBoundsWithPadding(gMap, bounds, paddingXY) {
var projection = gMap.getProjection();
if (projection) {
if (!$.isPlainObject(paddingXY))
paddingXY = {x: 0, y: 0};
var paddings = {
top: 0,
right: 0,
bottom: 0,
left: 0
};
if (paddingXY.left){
paddings.left = paddingXY.left;
} else if (paddingXY.x) {
paddings.left = paddingXY.x;
paddings.right = paddingXY.x;
}
if (paddingXY.right){
paddings.right = paddingXY.right;
}
if (paddingXY.top){
paddings.top = paddingXY.top;
} else if (paddingXY.y) {
paddings.top = paddingXY.y;
paddings.bottom = paddingXY.y;
}
if (paddingXY.bottom){
paddings.bottom = paddingXY.bottom;
}
// copying the bounds object, since we will extend it
bounds = new google.maps.LatLngBounds(bounds.getSouthWest(), bounds.getNorthEast());
// SW
var point1 = projection.fromLatLngToPoint(bounds.getSouthWest());
// we must call fitBounds 2 times - first is necessary to set up a projection with initial (actual) bounds
// and then calculate new bounds by adding our pixel-sized paddings to the resulting viewport
gMap.fitBounds(bounds);
var point2 = new google.maps.Point(
( (typeof(paddings.left) == 'number' ? paddings.left : 0) / Math.pow(2, gMap.getZoom()) ) || 0,
( (typeof(paddings.bottom) == 'number' ? paddings.bottom : 0) / Math.pow(2, gMap.getZoom()) ) || 0
);
var newPoint = projection.fromPointToLatLng(new google.maps.Point(
point1.x - point2.x,
point1.y + point2.y
));
bounds.extend(newPoint);
// NE
point1 = projection.fromLatLngToPoint(bounds.getNorthEast());
point2 = new google.maps.Point(
( (typeof(paddings.right) == 'number' ? paddings.right : 0) / Math.pow(2, gMap.getZoom()) ) || 0,
( (typeof(paddings.top) == 'number' ? paddings.top : 0) / Math.pow(2, gMap.getZoom()) ) || 0
);
newPoint = projection.fromPointToLatLng(new google.maps.Point(
point1.x + point2.x,
point1.y - point2.y
));
bounds.extend(newPoint);
gMap.fitBounds(bounds);
}
}
I will provide a more generic solution for this issue.
If we have a position e.g. marker.getPosition(), we can find a another position (x, y) pixel away from it using this function.
function extendedLocation(position, x, y) {
var projection = map.getProjection();
var newMarkerX = projection.fromLatLngToPoint(position).x + x/(Math.pow(2, map.getZoom()))
var newMarkerY = projection.fromLatLngToPoint(position).y + y/(Math.pow(2, map.getZoom()))
var newMarkerPoint = new google.maps.Point(newMarkerX, newMarkerY);
return projection.fromPointToLatLng(newMarkerPoint)
}
Note: positive x is in right direction and positive y is in down direction. So, in general case, to bring marker in view, we need to pass negative value of y e.g. extendedLocation(marker.getPosition(), 4, -18)
If you have a persistent slider or any such element at the top of suppose 30 px height, just use y parameter in the function as -30.
A more generalised function can be created which return array of 4 points, each (x, y) pixels away from the given pointing up, down, right and left direction.
function getAllExtendedPosition(position, x, y){
var positionArray = [];
postitionArray.push(extendedLocation(position, x, y);
postitionArray.push(extendedLocation(position, -x, -y);
postitionArray.push(extendedLocation(position, -x, y);
postitionArray.push(extendedLocation(position, x, -y);
return positionArray
}
The way I've done it seems pretty clean. E.g. Apply a 10% pad using a pixel coordinate basis on each side of the map. This is with Maps API v3.44:
map.fitBounds(bounds)
let mapDiv = map.getDiv()
let padding = {
bottom: mapDiv.offsetHeight * 0.1,
left: mapDiv.offsetWidth * 0.1,
right: mapDiv.offsetWidth * 0.1,
top: mapDiv.offsetHeight * 0.1,
}
map.fitBounds(bounds, padding);
Another way to do this would be to extend your boundaries with an additional LatLong point a calculated distance away. The google.maps.LatLngBounds() object has functions to get the SouthWest and NorthEast points of the bounding box, and that can be used to calculate a distance X miles North, South, East or West.
For example, if you were trying to push your markers to the right to account for overlay elements on the left side of the map, you might try the following:
// create your LatLngBounds object, like you're already probably doing
var bounds = new google.maps.LatLngBounds();
// for each marker call bounds.extend(pos) to extend the base boundaries
// once your loop is complete
// *** add a calculated LatLng point to the west of your boundary ***
bounds.extend(new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng() - .9));
// finally, center your map on the modified boundaries
map.fitBounds(bounds);
In the example above, adding a LatLong point to the bounds by subtracting .9 from the longitude of the western-most point moves the boundary about 52 miles further to the west.
A whole point (pos.lng() - 1.0) is about 58 miles, so you can either guess a good distance or use some other method to calculate that longitudinal offset when figuring out what kind of padding you need.
When overlay is a Google maps overlay and offsetx, offsety is the pixel distance from the maps center that I want to pan latlong to, the following works.
var projection = overlay.getProjection();
var pxlocation = projection.fromLatLngToContainerPixel(latlong);
map.panTo(projection.fromContainerPixelToLatLng(new google.maps.Point(pxlocation.x+offsetx,pxlocation.y+offsety)));
However, I don't always have an overlay on the map and map.getProjection() returns a projection, not a MapCanvasProjection which does not have the methods I need.
Is there a way to do this without making an overlay specificaly for it?
Since nobody has come up with a better way, here's my solution. Make an overlay with the sole job of giving me a MapCanvasProjection object.
var helper = new google.maps.OverlayView();
helper.setMap(map);
helper.draw = function () {
if (!this.ready) {
this.ready = true;
google.maps.event.trigger(this, 'ready');
}
};
var projection = helper.getProjection();
...
Hope this helps someone. Better suggestions welcome.
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);
}