javascript - georreferenciación - Cómo compensar el punto central en Google maps api V3
google maps marker label (9)
Tengo un mapa de Google con un panel semitransparente que cubre una parte del área. Me gustaría ajustar el punto central del mapa para tener en cuenta la porción del mapa que está parcialmente oscurecida. Ver la imagen a continuación. Idealmente, donde se colocan el punto de mira y el alfiler sería el punto central del mapa.
Espero que tenga sentido.
La razón es simple: cuando hace zoom, necesita centrar el mapa sobre la cruz en lugar de hacerlo al 50% al 50%. Además, trazaré marcadores en el mapa y los moveré en secuencia. Cuando el mapa se centra en ellos, también deben estar en la posición de desplazamiento.
¡Gracias por adelantado!
Acabo de encontrar otra solución más simple. En caso de que esté utilizando el método fitBounds, puede pasar un segundo argumento opcional a su. Este argumento es relleno, que se tendrá en cuenta al ajustar los límites.
// pass single side:
map.fitBounds(bounds, { left: 1000 })
// OR use Number:
map.fitBounds(bounds, 20)
Lectura adicional: documentos oficiales .
Andrew es la respuesta. Sin embargo, en mi caso, map.getBounds () sigue volviendo indefinido. Lo arreglé esperando el evento bounds_changed y luego llamé a la función para compensar el centro. Al igual que:
var center_moved = false;
google.maps.event.addListener(map, ''bounds_changed'', function() {
if(!center_moved){
offsetCenter(map.getCenter(), 250, -200);
center_moved = true;
}
});
Aquí hay un ejemplo de panBy()
resolver el problema utilizando el método panBy()
de la API de mapas: http://jsfiddle.net/upsidown/2wej9smf/
Aquí hay un método más simple que podría ser más útil en el diseño receptivo, ya que puede usar porcentajes en lugar de píxeles. ¡Sin coordenadas mundiales, sin Latitudes a Puntos!
var center; // a latLng
var offsetX = 0.25; // move center one quarter map width left
var offsetY = 0.25; // move center one quarter map height down
var span = map.getBounds().toSpan(); // a latLng - # of deg map spans
var newCenter = {
lat: center.lat() + span.lat()*offsetY,
lng: center.lng() + span.lng()*offsetX
};
map.panTo(newCenter); // or map.setCenter(newCenter);
Después de una extensa búsqueda no pude encontrar una manera de hacer esto que también incluye el zoom. Afortunadamente, un tipo inteligente lo ha descubierto. También hay un violín aquí
''use strict'';
const TILE_SIZE = {
height: 256,
width: 256
}; // google World tile size, as of v3.22
const ZOOM_MAX = 21; // max google maps zoom level, as of v3.22
const BUFFER = 15; // edge buffer for fitting markers within viewport bounds
const mapOptions = {
zoom: 14,
center: {
lat: 34.075328,
lng: -118.330432
},
options: {
mapTypeControl: false
}
};
const markers = [];
const mapDimensions = {};
const mapOffset = {
x: 0,
y: 0
};
const mapEl = document.getElementById(''gmap'');
const overlayEl = document.getElementById(''overlay'');
const gmap = new google.maps.Map(mapEl, mapOptions);
const updateMapDimensions = () => {
mapDimensions.height = mapEl.offsetHeight;
mapDimensions.width = mapEl.offsetWidth;
};
const getBoundsZoomLevel = (bounds, dimensions) => {
const latRadian = lat => {
let sin = Math.sin(lat * Math.PI / 180);
let radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
};
const zoom = (mapPx, worldPx, fraction) => {
return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
};
const ne = bounds.getNorthEast();
const sw = bounds.getSouthWest();
const latFraction = (latRadian(ne.lat()) - latRadian(sw.lat())) / Math.PI;
const lngDiff = ne.lng() - sw.lng();
const lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
const latZoom = zoom(dimensions.height, TILE_SIZE.height, latFraction);
const lngZoom = zoom(dimensions.width, TILE_SIZE.width, lngFraction);
return Math.min(latZoom, lngZoom, ZOOM_MAX);
};
const getBounds = locations => {
let northeastLat;
let northeastLong;
let southwestLat;
let southwestLong;
locations.forEach(function(location) {
if (!northeastLat) {
northeastLat = southwestLat = location.lat;
southwestLong = northeastLong = location.lng;
return;
}
if (location.lat > northeastLat) northeastLat = location.lat;
else if (location.lat < southwestLat) southwestLat = location.lat;
if (location.lng < northeastLong) northeastLong = location.lng;
else if (location.lng > southwestLong) southwestLong = location.lng;
});
const northeast = new google.maps.LatLng(northeastLat, northeastLong);
const southwest = new google.maps.LatLng(southwestLat, southwestLong);
const bounds = new google.maps.LatLngBounds();
bounds.extend(northeast);
bounds.extend(southwest);
return bounds;
};
const zoomWithOffset = shouldZoom => {
const currentzoom = gmap.getZoom();
const newzoom = shouldZoom ? currentzoom + 1 : currentzoom - 1;
const offset = {
x: shouldZoom ? -mapOffset.x / 4 : mapOffset.x / 2,
y: shouldZoom ? -mapOffset.y / 4 : mapOffset.y / 2
};
const newCenter = offsetLatLng(gmap.getCenter(), offset.x, offset.y);
if (shouldZoom) {
gmap.setZoom(newzoom);
gmap.panTo(newCenter);
} else {
gmap.setCenter(newCenter);
gmap.setZoom(newzoom);
}
};
const setMapBounds = locations => {
updateMapDimensions();
const bounds = getBounds(locations);
const dimensions = {
width: mapDimensions.width - mapOffset.x - BUFFER * 2,
height: mapDimensions.height - mapOffset.y - BUFFER * 2
};
const zoomLevel = getBoundsZoomLevel(bounds, dimensions);
gmap.setZoom(zoomLevel);
setOffsetCenter(bounds.getCenter());
};
const offsetLatLng = (latlng, offsetX, offsetY) => {
offsetX = offsetX || 0;
offsetY = offsetY || 0;
const scale = Math.pow(2, gmap.getZoom());
const point = gmap.getProjection().fromLatLngToPoint(latlng);
const pixelOffset = new google.maps.Point((offsetX / scale), (offsetY / scale));
const newPoint = new google.maps.Point(
point.x - pixelOffset.x,
point.y + pixelOffset.y
);
return gmap.getProjection().fromPointToLatLng(newPoint);
};
const setOffsetCenter = latlng => {
const newCenterLatLng = offsetLatLng(latlng, mapOffset.x / 2, mapOffset.y / 2);
gmap.panTo(newCenterLatLng);
};
const locations = [{
name: ''Wilshire Country Club'',
lat: 34.077796,
lng: -118.331151
}, {
name: ''301 N Rossmore Ave'',
lat: 34.077146,
lng: -118.327805
}, {
name: ''5920 Beverly Blvd'',
lat: 34.070281,
lng: -118.331831
}];
locations.forEach(function(location) {
let marker = new google.maps.Marker({
position: new google.maps.LatLng(location.lat, location.lng),
title: location.name
})
marker.setMap(gmap);
markers.push(marker);
});
mapOffset.x = overlayEl.offsetWidth;
document.zoom = bool => zoomWithOffset(bool);
document.setBounds = () => setMapBounds(locations);
section {
height: 180px;
margin-bottom: 15px;
font-family: sans-serif;
color: grey;
}
figure {
position: relative;
margin: 0;
width: 100%;
height: 100%;
}
figcaption {
position: absolute;
left: 15px;
top: 15px;
width: 120px;
padding: 15px;
background: white;
box-shadow: 0 2px 5px rgba(0, 0, 0, .3);
}
gmap {
display: block;
height: 100%;
}
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
<section>
<figure>
<gmap id="gmap"></gmap>
<figcaption id="overlay">
<h4>Tile Overlay</h4>
<p>To be avoided by the map!</p>
</figcaption>
</figure>
</section>
<button onclick="zoom(true)">zoom in</button>
<button onclick="zoom(false)">zoom out</button>
<button onclick="setBounds()">set bounds</button>
Esto no es particularmente difícil una vez que encuentre la respuesta anterior relevante .
Necesita convertir el centro del mapa en sus coordenadas mundiales, encontrar dónde se debe centrar el mapa para colocar el centro aparente donde lo desea y volver a centrar el mapa utilizando el centro real .
La API siempre centrará el mapa en el centro de la ventana gráfica, por lo que debe tener cuidado si usa map.getCenter()
ya que devolverá el centro real, no el centro aparente. Supongo que sería posible sobrecargar la API para que se getCenter()
sus getCenter()
y setCenter()
, pero no lo he hecho.
Código a continuación. Ejemplo en línea . En el ejemplo, al hacer clic en el botón se desplaza el centro del mapa (hay un cruce de carreteras) 100px abajo y se deja 200px.
function offsetCenter(latlng, offsetx, offsety) {
// latlng is the apparent centre-point
// offsetx is the distance you want that point to move to the right, in pixels
// offsety is the distance you want that point to move upwards, in pixels
// offset can be negative
// offsetx and offsety are both optional
var scale = Math.pow(2, map.getZoom());
var worldCoordinateCenter = map.getProjection().fromLatLngToPoint(latlng);
var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0);
var worldCoordinateNewCenter = new google.maps.Point(
worldCoordinateCenter.x - pixelOffset.x,
worldCoordinateCenter.y + pixelOffset.y
);
var newCenter = map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
map.setCenter(newCenter);
}
Otro enfoque cuando se trata de compensar una ruta o un grupo de marcadores se puede encontrar aquí:
https://.com/a/26192440/1238965
Todavía usa el método fromLatLngToPoint()
descrito en @Andrew Leach answer.
También eche un vistazo a la función panBy (x: número, y: número) en el objeto de mapas.
La documentación menciona esto sobre la función:
Cambia el centro del mapa por la distancia dada en píxeles. Si la distancia es menor que el ancho y el alto del mapa, la transición se animará suavemente. Tenga en cuenta que el sistema de coordenadas del mapa aumenta de oeste a este (para valores x) y de norte a sur (para valores y).
Solo úsalo así:
mapsObject.panBy(200, 100)
Una vieja pregunta, lo sé. ¿Pero qué tal una forma más centrada en CSS?
http://codepen.io/eddyblair/pen/VjpNQQ
Lo que hice fue:
Envuelva el mapa y la superposición en un contenedor con
overflow: hidden
Superpuesto la superposición con la
position: absolute
Extendió el ancho aparente del mapa por el ancho de la superposición (más cualquier relleno y desplazamiento) estableciendo un
margin-left
negativomargin-left
.A continuación, para cumplir con https://www.google.com/permissions/geoguidelines/attr-guide.html colocaron los widgets y los divs de atribución.
De esta forma, el centro del mapa se alinea con el centro del área deseada. El js es solo el mapa estándar js.
Reubicar los iconos para ver la calle es un ejercicio para el lector :)
Si desea la superposición a la izquierda, simplemente cambie la línea 24
margin-left
a margin-right
y la línea 32 de right
a left
.