Comment compenser le point central dans Google maps api V3

J'ai une carte Google avec un panneau semi-transparent couvrant une partie de la zone. J'aimerais ajuster le point central de la carte pour tenir compte de la partie de la carte qui est partiellement obscurcie. Voir l'image ci-dessous. Idéalement, le point central de la carte est l'endroit où les croix et la broche sont placés.

J'espère que cela à du sens.

La raison en est simple: lorsque vous zoomez, il faut centrer la carte sur le crochet plutôt que 50% 50%. De plus, je vais tracer des marqueurs sur la carte et les suivre dans l'ordre. Lorsque la carte se concentre sur eux, ils doivent également être en position décalée.

Merci d'avance!

Maquette de la carte que je construis

Ceci n'est pas particulièrement difficile une fois que vous trouvez la réponse précédente pertinente .

Vous devez convertir le centre de la carte en coordonnées mondiales, trouver où la carte doit être centrée pour mettre le centre apparent où vous le souhaitez et recentrer la carte en utilisant le centre réel .

L'API centra toujours la carte au centre de la fenêtre, de sorte qu'il faut faire attention si vous utilisez map.getCenter() car elle renverra le centre réel et non le centre apparent. Je suppose qu'il serait possible de surcharger l'API afin que ses getCenter() et setCenter() soient remplacées, mais je n'ai pas fait cela.

Code ci-dessous. Exemple en ligne . Dans l'exemple, en cliquant sur le bouton, vous déplacez le centre de la carte (il y a une jonction de route là-bas) en bas de 100px et 200px gauche.

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

Regardez également la fonction panBy (x: numéro, y: nombre) sur l'objet de cartes.

La documentation mentionne la fonction:

Change le centre de la carte par la distance donnée en pixels. Si la distance est inférieure à la largeur et à la hauteur de la carte, la transition sera bien animée. Notez que le système de coordonnées de la carte augmente d'ouest en est (pour les valeurs x) et du nord au sud (pour les valeurs y).

Utilisez-le comme ceci:

 mapsObject.panBy(200, 100) 

Voici une méthode plus simple qui pourrait être plus utile dans la conception réactive puisque vous pouvez utiliser des pourcentages au lieu de pixels. Pas de coordonnées mondiales, ni 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); 

Voici un exemple de résolution du problème en utilisant la méthode panBy() de l'API de cartes: http://jsfiddle.net/upsidown/2wej9smf/

Andrew's est la réponse. Cependant, dans mon cas, map.getBounds () a continué à revenir indéfini. Je l'ai réparé en attente de l'événement bound_changed, puis appelez la fonction pour décaler le centre. Ainsi:

 var center_moved = false; google.maps.event.addListener(map, 'bounds_changed', function() { if(!center_moved){ offsetCenter(map.getCenter(), 250, -200); center_moved = true; } }); 

Après une recherche approfondie, je n'ai pas pu trouver un moyen de faire cela, y compris le zoom inclus. Heureusement, un homme intelligent a découvert. Il y a aussi un violon ici

 '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> 

Ancienne question, je sais. Mais qu'en est-il d'une manière plus centrée sur CSS?

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

Ce que j'ai fait était:

  • Enrouler la carte et la superposer dans un conteneur avec overflow: hidden

  • Superposer la superposition avec la position: absolute

  • Augmenter la largeur apparente de la carte par la largeur de la superposition (plus tout rembourrage et décalage) en définissant une margin-left négative margin-left .

  • Ensuite, pour se conformer à https://www.google.com/permissions/geoguidelines/attr-guide.html a placé les widgets et les divisions d'attribution.

De cette façon, le centre de la carte est en ligne avec le centre de la zone désirée. Le js est juste carte standard js.

Repositionner les icônes pour street-view est un exercice pour le lecteur 🙂


Si vous voulez la superposition sur la gauche, changez la ligne 24 margin-left vers la margin-right et la droite 32 de right à left .

Une autre approche en matière de compensation d'un itinéraire ou d'un groupe de marqueurs peut être trouvée ici:

https://stackoverflow.com/a/26192440/1238965

Il utilise toujours la méthode fromLatLngToPoint() décrite dans la réponse @Andrew Leach.