我有一张谷歌地图,上面有一个覆盖部分区域的半透明面板。我想调整地图的中心点以考虑地图中部分被遮挡的部分。见下图。理想情况下,放置十字准线和大头针的位置将是地图的中心点。
我希望这是有道理的。
原因很简单:当您缩放时,它需要将地图置于十字准线的中心,而不是 50% 50%。此外,我将在地图上绘制标记并按顺序移动它们。当地图以它们为中心时,它们也需要处于偏移位置。
提前致谢!
我有一张谷歌地图,上面有一个覆盖部分区域的半透明面板。我想调整地图的中心点以考虑地图中部分被遮挡的部分。见下图。理想情况下,放置十字准线和大头针的位置将是地图的中心点。
我希望这是有道理的。
原因很简单:当您缩放时,它需要将地图置于十字准线的中心,而不是 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);
}
还可以查看 maps 对象上的 panBy(x:number, y:number) 函数。
文档中提到了有关该功能的内容:
将地图的中心更改为给定距离(以像素为单位)。如果距离小于地图的宽度和高度,则过渡将平滑动画。请注意,地图坐标系从西向东(对于 x 值)和从北向南(对于 y 值)增加。
像这样使用它:
mapsObject.panBy(200, 100)
panBy()
以下是使用地图 API 的方法解决问题的示例:http: //jsfiddle.net/upsidown/2wej9smf/
刚刚找到另一个最简单的解决方案。如果您使用 fitBounds 方法,则可以将可选的第二个参数传递给它。此参数是填充,将在拟合边界时考虑。
// pass single side:
map.fitBounds(bounds, { left: 1000 })
// OR use Number:
map.fitBounds(bounds, 20)
进一步阅读:官方文档。
这是一种更简单的方法,可能在响应式设计中更有用,因为您可以使用百分比而不是像素。没有世界坐标,没有点的纬度!
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);
安德鲁的答案是。但是,就我而言, 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
通过设置负数将地图的表观宽度扩展为覆盖宽度(加上任何填充和偏移)margin-left
。
然后为了遵守https://www.google.com/permissions/geoguidelines/attr-guide.html定位小部件和属性div
。
这样,地图的中心就与所需区域的中心一致。js只是标准的地图js。
重新定位街景图标是读者的练习:)
如果您想要左侧的叠加层,只需将第 32行24
margin-left
更改为.margin-right
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
它仍然使用fromLatLngToPoint()
@Andrew Leach 回答中描述的方法。
下面是一个简单的使用示例:
500
250
当屏幕尺寸实时更改时,该解决方案也将顺利运行。
要求在css中使用and定义查询@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 进行定制