Programing

Google지도 API V3에서 중심점을 오프셋하는 방법

lottogame 2020. 10. 21. 07:34
반응형

Google지도 API V3에서 중심점을 오프셋하는 방법


지역의 일부를 덮는 반투명 패널이있는 Google지도가 있습니다. 지도에서 부분적으로 가려진 부분을 고려하여지도의 중심점을 조정하고 싶습니다. 아래 이미지를 참조하십시오. 이상적으로는 십자선과 핀이 배치되는 위치가지도의 중심점이됩니다.

그게 말이 되길 바랍니다.

이유는 간단합니다. 확대 / 축소 할 때 50 % 50 %가 아닌 십자선 위에지도를 중앙에 배치해야합니다. 또한지도에 마커를 플로팅하고 순서대로 이동합니다. 지도가 중심에있을 때 오프셋 위치에 있어야합니다.

미리 감사드립니다!

내가 만들고있는지도의 모형


관련 이전 답변 을 찾으면 특별히 어렵지 않습니다 .

지도의 중심을 세계 좌표로 변환하고, 원하는 위치에 겉보기 중심을 배치하기 위해지도의 중심이 필요한 위치를 찾은 다음 실제 중심을 사용하여지도의 중심을 다시 조정해야합니다 .

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);

}

또한 maps 객체의 panBy (x : number, y : number) 함수를 살펴보십시오.

문서는 함수에 대해 다음과 같이 언급합니다.

지정된 거리 (픽셀)만큼지도 중심을 변경합니다. 거리가지도의 너비와 높이보다 작 으면 전환이 부드럽게 애니메이션됩니다. 지도 좌표계는 서쪽에서 동쪽 (x 값)과 북쪽에서 남쪽 (y 값)으로 증가합니다.

다음과 같이 사용하십시오.

mapsObject.panBy(200, 100)

다음은 픽셀 대신 백분율을 사용할 수 있으므로 반응 형 디자인에서 더 유용 할 수있는 더 간단한 방법입니다. 세계 좌표도없고 LatLngs to Points도 없습니다!

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/


앤드류가 답입니다. 그러나 제 경우에는 map.getBounds ()가 계속해서 undefined를 반환했습니다. 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입니다.

스트리트 뷰의 아이콘 위치 변경은 독자를위한 연습입니다. :)


당신은 왼쪽, 단지 변화 라인에 오버레이 원하는 경우 24 margin-leftmargin-right라인 (32) right에을 left.


다른 가장 간단한 해결책을 찾았습니다. fitBounds 메서드를 사용하는 경우 선택적 두 번째 인수를 해당 메서드에 전달할 수 있습니다. 이 인수는 패딩이며 경계를 맞추는 동안 고려됩니다.

// pass single side:
map.fitBounds(bounds, { left: 1000 })

// OR use Number:
map.fitBounds(bounds, 20)

추가 읽기 : 공식 문서 .


광범위한 검색 후 나는 줌을 포함하여 이것을 수행하는 방법을 찾을 수 없었습니다. 고맙게도 영리한 녀석 이 알아 냈습니다. 여기바이올린도 있습니다

'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 답변에 설명 된 방법을 여전히 사용합니다 .

참고 URL : https://stackoverflow.com/questions/10656743/how-to-offset-the-center-point-in-google-maps-api-v3

반응형