[英]How to offset the center point in Google maps api V3
我有一張谷歌地圖,上面有一個半透明面板,覆蓋了該區域的一部分。 我想調整地圖的中心點以考慮到部分被遮擋的地圖部分。 見下圖。 理想情況下,放置十字准線和圖釘的位置將是地圖的中心點。
我希望這是有道理的。
原因很簡單:縮放時需要將地圖居中放置在十字准線上,而不是 50% 50%。 此外,我將在地圖上繪制標記並按順序移動它們。 當地圖以它們為中心時,它們也需要處於偏移位置。
提前致謝!
一旦您找到相關的先前答案,這並不是特別困難。
您需要將地圖的中心轉換為其世界坐標,找到需要將地圖居中的位置以將明顯的中心放在您想要的位置,然后使用真實中心重新居中地圖。
API 將始終將地圖以視口的中心為中心,因此在使用map.getCenter()
需要小心,因為它將返回真實中心,而不是明顯中心。 我想可以重載 API 以替換其getCenter()
和setCenter()
方法,但我還沒有這樣做。
代碼如下。 在線示例。 在示例中,單擊該按鈕會將地圖的中心(那里有一個路口)向下移動 100 像素並向左移動 200 像素。
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) 函數。
文檔提到了有關該功能的內容:
按給定的像素距離更改地圖的中心。 如果距離小於地圖的寬度和高度,過渡將平滑動畫。 請注意,地圖坐標系從西向東(對於 x 值)和從北向南(對於 y 值)增加。
只需像這樣使用它:
mapsObject.panBy(200, 100)
這是使用地圖 API 的panBy()
方法解決問題的示例: http : //jsfiddle.net/upsidown/2wej9smf/
這是一種更簡單的方法,在響應式設計中可能更有用,因為您可以使用百分比而不是像素。 沒有世界坐標,沒有 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);
剛剛找到了另一個最簡單的解決方案。 如果您使用 fitBounds 方法,您可以將可選的第二個參數傳遞給它。 這個參數是填充,將在擬合邊界時考慮。
// pass single side:
map.fitBounds(bounds, { left: 1000 })
// OR use Number:
map.fitBounds(bounds, 20)
進一步閱讀: 官方文檔。
安德魯的就是答案。 但是,就我而言, map.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
覆蓋覆蓋position: absolute
通過設置負margin-left
將地圖的表觀寬度擴展到覆蓋寬度(加上任何填充和偏移)。
然后為了符合https://www.google.com/permissions/geoguidelines/attr-guide.html定位小部件和歸屬div
s。
這樣,地圖的中心就與所需區域的中心對齊。 js 只是標准的地圖 js。
重新定位街景圖標是讀者的練習:)
如果您想要左側的疊加層,只需將第24
行margin-left
更改為margin-right
,將第 32 行right
更改為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>
可以在此處找到偏移路線或一組標記的另一種方法:
https://stackoverflow.com/a/26192440/1238965
它仍然使用@Andrew Leach 回答中描述的fromLatLngToPoint()
方法。
下面是一個SIMPLE使用的例子:
500
桌面版250
時, MOBILE版本當屏幕尺寸實時變化時,該解決方案也將順利運行。
要求查詢在CSS被定義與@media screen and (min-width: 1025px)
和@media screen and (max-width: 1024px)
代碼:
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: 13
});
bounds = new google.maps.LatLngBounds();
// add markers to bounds
// Initial bounds
defineBounds()
// Trigger resize browser and set new bounds
google.maps.event.addDomListener(window, 'resize', function() {
defineBounds()
});
}
function defineBounds() {
if (window.matchMedia("(min-width:1025px)").matches) {
map.fitBounds(bounds, {
top: 100,
right: 100,
left: 600, // 500 + 100
bottom: 100
});
} else {
map.fitBounds(bounds, {
top: 80,
right: 80,
left: 80,
bottom: 330 // 250 + 80
});
}
}
該解決方案可以針對位於屏幕兩側的 OVERLAY 進行定制
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.