studio - Relleno de fitBounds API 3 de Google Maps: asegúrese de que los marcadores no se vean opacados por los controles superpuestos
google maps marker size (6)
Actualizado
La API de Google Maps ahora admite un param nativo de "relleno" en el método fitBounds (a partir de la versión 3.32, fitBounds si antes).
Todavía no tuve oportunidad de probarlo, pero si puedes actualizarlo, recomendaría utilizarlo de forma nativa. Si está utilizando la versión <3.32 y no puede actualizar, mi solución es para usted.
Tomé la solución de trabajo de erzzo y la mejoré un poco.
Ejemplo
fitBoundsWithPadding(googleMapInstance, PolygonLatLngBounds, {left:250, bottom:10});
Descripción de los argumentos:
- gMap - instancia del mapa de google
- límites - google maps objeto LatLngBounds para adaptarse
- paddingXY - Object Literal: 2 formatos posibles:
- {x, y} - para almohadillas horizontales y verticales (x = izquierda = derecha, y = arriba = abajo)
- {izquierda, derecha, arriba, abajo}
lista de funciones para copiar
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);
}
}
Me gustaría poder agregar relleno a una vista de mapa después de llamar a map.fitBounds()
, por lo que todos los marcadores pueden ser visibles independientemente de los controles del mapa o de elementos deslizantes que cubran los marcadores cuando se abren. Leaftlet tiene una opción para agregar relleno a fitBounds , pero Google Maps no.
En ocasiones, los marcadores situados más al norte se ocultan parcialmente sobre la ventana gráfica. Los marcadores más hacia el oeste también suelen colocarse debajo del control deslizante del zoom. Con API 2 fue posible formar una ventana showBounds()
virtual al reducir los rellenos dados de la ventana showBounds()
del mapa y luego llamar al método showBounds()
para calcular y realizar un acercamiento y centrar en función de esa ventana virtual:
map.showBounds(bounds, {top:30,right:10,left:50});
Un ejemplo práctico de esto para la API 2 se puede encontrar here debajo del enlace de ejemplo showBounds ().
No puedo encontrar una funcionalidad similar en API V3, pero espero que haya otra manera de lograr esto. Tal vez podría tomar los puntos noreste y sudoeste, y luego agregar coordenadas falsas para extender los límites después de incluirlos.
ACTUALIZAR
( Codepen en caso de que el código siguiente no funcione)
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>
El problema es este:
Intenté agregar un control como está documentado en Controles personalizados , pero el mapa no es exactamente consciente de ello; vea este violín bifurcado en el ejemplo de control personalizado de Mapas . Uno de los marcadores todavía está oscurecido por el control.
A partir de junio de 2017, Maps JavaScript API admite el parámetro de relleno en el método fitBounds ().
fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)
Por favor, consulte la documentación para más detalles
https://developers.google.com/maps/documentation/javascript/reference#Map
Este es un tipo de solución de hackeo, pero después de los fitBounds
, puedes alejar un nivel para obtener suficiente espacio para tus marcadores.
Asume que la variable del map
es tu referencia al objeto del mapa;
map.setZoom(map.getZoom() - 1);
Otra forma de hacerlo sería ampliar sus límites con un punto LatLong adicional a una distancia calculada. El objeto google.maps.LatLngBounds () tiene funciones para obtener los puntos Sudoeste y Nordeste del cuadro delimitador, y que se pueden usar para calcular una distancia X millas Norte, Sur, Este u Oeste.
Por ejemplo, si intentas empujar tus marcadores hacia la derecha para contabilizar los elementos superpuestos en el lado izquierdo del mapa, puedes intentar lo siguiente:
// 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);
En el ejemplo anterior, al agregar un punto LatLong a los límites al restar .9 de la longitud del punto más occidental se mueve el límite unas 52 millas más hacia el oeste.
Un punto entero (pos.lng () - 1.0) es aproximadamente 58 millas, por lo que puede adivinar una buena distancia o utilizar algún otro método para calcular el desplazamiento longitudinal al determinar qué tipo de relleno necesita.
Proporcionaré una solución más genérica para este problema. Si tenemos una posición, por ejemplo, marker.getPosition()
, podemos encontrar una otra posición (x, y)
píxel de distancia usando esta función.
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)
}
Nota: positivo x está en la dirección correcta y positivo y está en dirección hacia abajo. Entonces, en un caso general, para tener un marcador a la vista, necesitamos pasar el valor negativo de y, por ejemplo, extendedLocation(marker.getPosition(), 4, -18)
Si tiene un control deslizante persistente o cualquier elemento de este tipo en la parte superior de su altura de 30 px, simplemente use el parámetro y
en la función como -30
.
Se puede crear una función más generalizada que devuelva una matriz de 4 puntos, cada uno (x, y)
píxeles lejos de la dirección dada hacia arriba, abajo, derecha e izquierda.
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
}
Resolví este problema extendiendo los límites del mapa para incluir un latlng que empujó suficientemente los marcadores a la vista.
En primer lugar, debe crear una vista de superposición
var overlayHelper = new google.maps.OverlayView();
overlayHelper.onAdd = function() {};
overlayHelper.onRemove = function() {};
overlayHelper.draw = function() {};
overlayHelper.setMap(map);
Una vez que tiene un ayudante de superposición, necesita obtener la proyección del mapa y realizar cálculos en función de eso.
Tenga en cuenta que el control que tengo en mi mapa es de 420 píxeles de ancho y 100% de altura en el extremo derecho del mapa. Obviamente tendrá que cambiar el código para acomodar sus controles.
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);
}
Si está haciendo esto cuando el mapa se carga por primera vez, deberá envolverlo en un evento de mapa para esperar que esté inactivo. Esto permite que la vista de superposición se inicialice. No incluya la creación de superposición de ayuda dentro de la devolución de llamada de evento.
google.maps.event.addListenerOnce(map, ''idle'', function() { <above code> });