How to compensate for the center in Google maps api V3

I have a Google map with a translucent panel covering part of the area. I would like to adjust the center point of the map to allow for part of the partially closed map. See image below. Ideally, where the crosshair and pin are located, this will be the center point of the map.

Hope this makes sense.

The reason is simple: when scaling, you must center the map over the crosshair, and not at 50% 50%. In addition, I will draw markers on the map and move on them sequentially. When the map focuses on them, they should also be in an offset position.

Thanks in advance!

Mockup of the map I am building

+62
javascript google-maps-api-3
May 18 '12 at 16:55
source share
8 answers

It is not particularly difficult if you find the corresponding previous answer .

You need to convert the center of the map to your world coordinates, find where the map should be centered to place the visible center where you want, and re-center the map using the real center.

The API will always center the map in the center of the viewport, so you need to be careful if you use map.getCenter() , since it will return the real center, not the visible center. I believe it would be possible to overload the API so that its getCenter() and setCenter() methods are replaced, but I did not.

The code is below. Online example . In this example, pressing the button shifts the center of the map (there is a road connection) down 100 pixels and left 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); } 
+66
May 19 '12 at 2:28 pm
source share

Also take a look at the panBy function (x: number, y: number) on the map object.

The documentation mentions this feature:

Changes the center of the map by the specified distance in pixels. If the distance is less than the width and height of the map, the transition will be smoothly animated. Note that the coordinate system of the map increases from west to east (for x values) and from north to south (for y values).

Just use it like this:

 mapsObject.panBy(200, 100) 
+49
Jul 09 '13 at 7:37 on
source share

Here is a simpler method that might be more useful in responsive design, since you can use percentages instead of pixels. No world coordinates, no 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); 
+9
Apr 30 '15 at 1:36
source share

Here is an example of solving the problem using the panBy() method of the maps API: http://jsfiddle.net/upsidown/2wej9smf/

+7
Dec 08 '14 at 12:11
source share

Andrew is the answer. However, in my case map.getBounds () returned undefined. I fixed it while waiting for the bounds_changed event, and then called a function to offset the center. For example:

 var center_moved = false; google.maps.event.addListener(map, 'bounds_changed', function() { if(!center_moved){ offsetCenter(map.getCenter(), 250, -200); center_moved = true; } }); 
+6
May 22 '13 at 20:38
source share

After an extensive search, I could not find a way to do this, including scaling. Fortunately, the smart guy realized that. There is also a violin here

 '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> 
+3
Aug 23 '16 at 11:23
source share

Old question, I know. But what about a more CSS-oriented way?

http://codepen.io/eddyblair/pen/VjpNQQ

What I've done:

  • Wrap the card and lay it in the container using overflow: hidden

  • Overlay overlay on position: absolute

  • Increased map visibility width over the width of the overlay (plus any padding and offset) by setting a negative margin-left .

  • Then, to comply with https://www.google.com/permissions/geoguidelines/attr-guide.html , widgets and attribution div s were placed.

Thus, the center of the map lies in the center with the center of the desired area. Js is just a standard js map.

Moving icons for a street performance is an exercise for the reader :)




If you want to overlay on the left, just change line 24 margin-left to margin-right and line 32 right to left .

+2
Jun 29 '16 at 15:11
source share

Another approach when it comes to compensating for a route or group of tokens can be found here:

stack overflow

It still uses the fromLatLngToPoint() method described in @Andrew Leach's answer.

+1
Oct 05 '14 at 8:52
source share



All Articles