Карти Google v3 fitBounds () Наблизьте масштаб для одного маркера


92

Чи можна встановити максимальний рівень масштабування fitBounds()? Моя проблема полягає в тому, що коли на мапі подається лише одне місце, вона наближається наскільки це можливо, що дійсно виводить карту з контексту і робить її марною. Можливо, я приймаю неправильний підхід?

Спасибі заздалегідь!


2
stackoverflow.com/questions/4523023/… - набагато краще рішення. Відповідь @Nequins
Кеннет

Відповіді:


138

Мені подобається рішення mrt (особливо, коли ви не знаєте, на скільки точок ви будете картографувати або коригувати), за винятком того, що воно відкидає маркер, щоб він більше не знаходився в центрі карти. Я просто розширив його додатковою точкою, віднімаючи також 0,01 від lat та lng, так що він утримує маркер у центрі. Чудово працює, спасибі мер!

// Pan & Zoom map to show all markers
function fitToMarkers(markers) {

    var bounds = new google.maps.LatLngBounds();

    // Create bounds from markers
    for( var index in markers ) {
        var latlng = markers[index].getPosition();
        bounds.extend(latlng);
    }

    // Don't zoom in too far on only one marker
    if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
       var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
       var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
       bounds.extend(extendPoint1);
       bounds.extend(extendPoint2);
    }

    map.fitBounds(bounds);

    // Adjusting zoom here doesn't work :/

}

4
Хороша ідея щодо збереження оригінального центру. Причина того, що рівень масштабування не може бути надійно відрегульований при використанні fitBounds()методу, полягає в тому, що масштабування відбувається асинхронно: stackoverflow.com/questions/2989858/…
Metro Smurf

1
Для мене це чудово працювало. Мені довелося передати посилання на карту у функцію "function fitToMarkers (маркери, карта)" на V3, але це працює як шарм після цього!
Шейн

4
Люблю це. Хороший @ryan. Для мене це чудово працювало, але .01 у моєму випадку занадто зменшився, .001 потрапив у найкраще місце.
willdanceforfun 02.03.13

Дякую. Як і @willdanceforfun, той самий випадок, 001 потрапив у суть.
Горан Яковлевич

1
Я рекомендував би це рішення stackoverflow.com/questions/2437683 / ...
NinjaOnSafari

38

Ви можете налаштувати свою карту за maxZoomдопомогою MapOptions (api-reference) таким чином:

var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Це дозволить уникнути збільшення масштабу карти під час використання fitBounds()та навіть видалить рівні масштабування з регулятора масштабування.


@candlejack Точно так, як описано в моїй відповіді?
Flygenring

6
Ви можете встановити maxZoomдо установки кордонів , а потім скинути його знову , використовуючи map.setOptions({ maxZoom: undefined })на idleподії справили за рахунок зміни меж. Це запобігає збільшенню та зменшенню ефекту, замість того, щоб скинути масштабування idleподії.
El Yobo,

29

Іншим рішенням є розширення меж, якщо ви виявите, що вони занадто малі, перш ніж виконувати fitBounds ():

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
   var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
   bounds.extend(extendPoint);
}
map.fitBounds(bounds);

19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Використання опції MaxZoom найкраще підходить для не масштабування, щоб наблизитись до позначок, які ви маєте.


Фантастично! Рятувальник життя!
Jaypee

18

Додавши всі реальні межі, додайте ці рядки

var offset = 0.002;     
var center = bounds.getCenter();                            
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));

він отримує центр реальних меж, а потім додає дві додаткові точки - одну на північний схід і одну на південний захід від вашого центру

Це ефективно встановлює мінімальне збільшення, змінює значення зміщення, щоб збільшити або зменшити масштабування



11

Ви можете використовувати

map.setOptions({
    maxZoom: [what u want],
    minZoom: [what u want]
});

таким чином, ви встановлюєте властивості карти після того, як карта була ініціалізована .... Ви можете встановити їх стільки разів, скільки Вам потрібно ... але у Вашому випадку ... Ви можете встановити їх перед fitBounds ()

удачі, раруту


7

Я запобігаю збільшенню карти на дальнє, додаючи цей рядок коду:

var zoomOverride = map.getZoom();
        if(zoomOverride > 15) {
        zoomOverride = 15;
        }
      map.setZoom(zoomOverride);

Безпосередньо після цього рядка:

map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));

Не соромтеся змінювати рівень масштабування до будь-якого рівня, який ви не хочете, щоб карта наближалася.

Якщо у вас є якісь проблеми або запитання, просто залиште мені коментар до допису в блозі, який я написав про це, на http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the- map-from-zooming-in-too-close-on-a-single-marker


1
Мені подобається це рішення, але вставляю setzoom всередину, якщо не викликати його кожного разу. Також може бути побічний ефект синхронізації, який повертає значення "undefined" із getzoom (). Рішення: zoom = map.getZoom (); if (typeof zoom! == 'undefined' && zoom> 8) map.setZoom (8);
Le Droid

5

Мені дуже подобається рішення mrt, і воно чудово працює, якщо у вас завжди є лише одна точка для роботи. Однак я виявив, що якщо обмежувальне поле не базувалося на одній точці, але точки були дуже близько одна до одної, це все одно могло б призвести до того, що карта буде занадто збільшена.

Ось спосіб спочатку перевірити, чи знаходяться точки на визначеній відстані одна від одної, а потім, якщо вони менше цієї мінімальної відстані, розширити межі на цю мінімальну відстань:

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like

// ...

var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();

if((sumA < minDistance && sumA > -minDistance) 
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
    var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
    bounds.extend(extendPoint1);
    bounds.extend(extendPoint2);
}

Сподіваюся, це комусь допомагає!


3

Це дає вам прямий контроль на максимально дозволеному масштабуванні встановлення меж.

var fitToMarkers = function(map, markers, maxZoom) {
    if (typeof maxZoom == 'undefined') maxZoom = 15;

    google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
        if (this.getZoom() > maxZoom) {
            this.setZoom(maxZoom);
        }
    });

    var bounds = new google.maps.LatLngBounds();
    for (var m = 0; m < markers.length; m++) {
        var marker = markers[m];
        var latlng = marker.getPosition();
        bounds.extend(latlng);
    }

    map.fitBounds(bounds);
};

3

Що стосується мене, я вирішую це шляхом створення простою події після fitBounds. Працює ідеально. Думаю, це одне з найбільш чистих рішень тут

var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) { 
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10
  });
  .... create markers, etc.
}
....
map.fitBounds(bounds);  
google.maps.event.addListenerOnce(map, 'idle', function() {
  if (locations.length == 1) {
    map.setZoom(11);
  }
});

2

Я вирішив цей шматок, оскільки Google Maps V3 керується подіями:

Ви можете сказати API повернути масштаб на належну величину, коли спрацьовує подія zoom_changed :

var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
    if (intial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         intial = false;
       }
    }
}); 

Я використовував intial, щоб карта не масштабувала занадто багато навантажень, коли можливі fitBounds були перероблені, без цього будь-яка подія масштабування більше 11 була б неможливою для користувача.


1

Після виклику fitBounds()методу спробуйте встановити рівень масштабування ще раз. Це змусить карту знаходитись на такому рівні масштабування, будучи центрованим у правильному місці.


0

У мене є рішення, яке базується на обмеженні максимального збільшення під час встановлення меж. Працює для мене (протестовано на Win 7 - IE 9, FF 13, Chrome 19):

// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..

// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;


// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
    // set max zoom only when fitting bounds
    if (window.fittingBounds && map.getZoom() > 16) {
        this.setZoom(16);
    }
});

0

І .. ось ще один.
Така ж ідея, як Мрт та Райан, але

  • також працює, якщо розмір меж не зовсім нульовий (*)
  • запобігає спотворення поблизу полюсів
  • використовує getCenter () замість getNorthEast ()

(*) Примітка: Якщо поле вже досить велике, додавання цих двох додаткових балів не повинно мати ефекту. Тож нам не потрібна подальша перевірка.

function calcBounds(markers) {
  // bounds that contain all markers
  var bounds = new google.maps.LatLngBounds();
  // Using an underscore _.each(). Feel free to replace with standard for()
  _.each(markers, function(marker) {
    bounds.extend(marker.getPosition());
  });
  // prevent lat/lng distortion at the poles
  var lng0 = bounds.getNorthEast().lng();
  var lng1 = bounds.getSouthWest().lng();
  if (lng0 * lng1 < 0) {
    // Take the cos at the equator.
    var cos = 1;
  }
  else {
    var cos0 = Math.cos(lng0);
    var cos1 = Math.cos(lng1);
    // Prevent division by zero if the marker is exactly at the pole.
    var cos_safe = Math.max(cos0, cos1, 0.0001);
  }
  var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
  var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
  // "radius" in either direction.
  // 0.0006 seems to be an ok value for a typical city.
  // Feel free to make this value a function argument.
  var rLat = 0.0006;
  var rLng = rLat / cos_safe;
  // expand the bounds to a minimum width and height
  var center = bounds.getCenter();
  var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
  var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
  bounds.extend(p0);
  bounds.extend(p1);
  return bounds;
}

EDIT: Я не точно впевнений, чи правильно розрахував мій коефіцієнт, враховуючи, що ми маємо проекцію Меркатора. Я можу перередагувати це ..


0

На нього вже відповіли тут Google Maps v3: Застосування хв. рівень масштабування при використанні fitBounds працює так, як очікувалося :), тож, якщо після меж пристосування масштабування менше, ніж скажімо 13, тоді ви можете встановити нове масштабування, яке ви надаєте


-1

Ось мій підхід до рішення, яке також працює, коли два маркери дуже близькі. Ефективний максимальний рівень масштабування однаковий в обох ситуаціях. Тож ми не закінчуємо неодмінно зменшення масштабу, коли є більше одного маркера

Ефект, знову ж таки, полягає у забезпеченні максимального масштабування, не використовуючи опцію maxZoom, що, ймовірно, має небажаний ефект, що робить неможливим для користувача масштабування далі рівня maxZoom за допомогою регулятора масштабування

Я заздалегідь розрахував maxLat, minLat, maxLng та minLng ...

var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
  // ensures that we do not zoom in too much
  var delta = (minLatSpan - (maxLat - minLat)) / 2;
  maxLat += delta;
  minLat -= delta;
}

map.fitBounds({
  east: maxLng,
  west: minLng,
  north: maxLat,
  south: minLat,
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.