Как смещать центральную точку в Google maps api V3
У меня есть карта Google с полупрозрачной вставкой, закрывающей часть области. Я хотел бы настроить центральную точку карты, чтобы учесть часть карты, которая частично скрыта. См. изображение ниже. В идеале, где перекрестие и булавка размещены будет центральная точка карты.
Я надеюсь, что имеет смысл.
причина проста: при масштабировании необходимо центрировать карту над перекрестием, а не на 50% 50%. Кроме Того, Я будет нанесение маркеров на карту и перемещение по ним в последовательности. Когда карта центрируется на них, они также должны быть в положении смещения.
спасибо заранее!
9 ответов:
это не особенно трудно, как только вы найдете соответствующий предыдущий ответ.
вам нужно преобразовать центр карты в ее мировые координаты, найти, где карта должна быть центрирована, чтобы поместить видимого центр, где вы хотите его, и повторно центрировать карту с помощью реальные центр.
API всегда будет центрировать карту в центре окна просмотра, поэтому вам нужно быть осторожным, если вы используете
map.getCenter()
как это будет верните реальный центр, а не кажущийся центр. Я полагаю, что можно было бы перегрузить API, чтобы егоgetCenter()
иsetCenter()
методы заменены, но я этого не сделал.код ниже. пример онлайн. В Примере нажатие кнопки сдвигает центр карты (там есть дорожная развязка) вниз на 100px и влево на 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); }
также взгляните на функцию panBy(x:number, y:number) на объекте maps.
в документации упоминается об этой функции:
изменяет центр карты на заданное расстояние в пикселях. Если расстояние меньше, чем ширина и высота карты, переход будет плавно анимированы. Обратите внимание, что система координат карты увеличивается с запада на восток (для значений x) и с севера на юг (для y значения.)
просто используйте его так:
mapsObject.panBy(200, 100)
вот более простой метод, который может быть более полезным в адаптивном дизайне, так как вы можете использовать проценты вместо пикселей. Нет координат, нет LatLngs для очков!
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);
вот пример решения проблемы с помощью
panBy()
метод API карт:http://jsfiddle.net/upsidown/2wej9smf/
Андрей, это ответ. Однако, в моем случае, карта.getBounds () продолжал возвращаться неопределенным. Я исправил его в ожидании события bounds_changed и затем вызываем функцию для смещения центра. Вот так:
var center_moved = false; google.maps.event.addListener(map, 'bounds_changed', function() { if(!center_moved){ offsetCenter(map.getCenter(), 250, -200); center_moved = true; } });
старый вопрос, я знаю. Но как насчет более CSS-ориентированного способа?
http://codepen.io/eddyblair/pen/VjpNQQ
что я сделал:
оберните карту и наложите в контейнер с
overflow: hidden
наложил наложение с
position: absolute
расширенная карта шириной по ширине наложения (плюс любые отступы и смещения), установив a отрицательно
margin-left
.затем, чтобы соответствовать https://www.google.com/permissions/geoguidelines/attr-guide.html расположил виджеты и атрибуцию
div
s.таким образом, центр карты находится на одной линии с центром нужной области. Js - это просто стандартная карта js.
перемещение значков для street-view-это упражнение для читателя:)
если вы хотите наложение слева, просто измените строку
24
margin-left
доmargin-right
и строка 32right
доleft
.
после обширного поиска я не мог найти способ сделать это, что также включало масштабирование. К счастью умник уже разобрался. Существует также скрипку здесь
'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>
нашел еще одно простое решение. Если вы используете метод fitBounds, вы можете передать ему необязательный второй аргумент. Этот аргумент является дополнением, которое будет учитываться при подгонке границ.
// pass single side: map.fitBounds(bounds, { left: 1000 }) // OR use Number: map.fitBounds(bounds, 20)
читайте далее: официальные документы.
другой подход, когда речь заходит о смещении маршрута или группы маркеров можно найти здесь:
https://stackoverflow.com/a/26192440/1238965
Он по-прежнему использует
fromLatLngToPoint()
метод, описанный в ответе @Andrew Leach.