Вопрос

У меня есть набор точек, которые я хочу нанести на встроенную карту Google (API v3).Я бы хотел, чтобы границы учитывали все точки, если только уровень масштабирования не слишком низкий (т. Е. Не увеличен слишком сильно).Мой подход был примерно таким:

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

// extend bounds with each point

gmap.fitBounds(bounds); 
gmap.setZoom( Math.max(6, gmap.getZoom()) );

Это не сработает.Последняя строка "gmap.setZoom()" не изменяет уровень масштабирования карты, если вызывается непосредственно после fitBounds.

Есть ли способ получить уровень масштабирования границ, не применяя его к карте?Другие идеи по решению этой проблемы?

Это было полезно?

Решение

Редактировать:Смотрите комментарий Мэтта Даймонда ниже.

Понял!Попробуй это:

map.fitBounds(bounds);
var listener = google.maps.event.addListener(map, "idle", function() { 
  if (map.getZoom() > 16) map.setZoom(16); 
  google.maps.event.removeListener(listener); 
});

Модифицируйте в соответствии с вашими потребностями.

Другие советы

Я решил аналогичную проблему в одном из своих приложений.Я был немного сбит с толку вашим описанием проблемы, но я думаю, что у вас та же цель, что и у меня...

В своем приложении я хотел нанести один или несколько маркеров и убедиться, что на карте показаны их все.Проблема заключалась в том, что если бы я полагался исключительно на метод fitBounds, то уровень масштабирования был бы максимальным, когда была бы одна точка - это было бесполезно.

Решение состояло в том, чтобы использовать fitBounds, когда было много точек, и setCenter + setZoom, когда была только одна точка.

if (pointCount > 1) {
  map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);
}

Я заходил на эту страницу несколько раз, чтобы получить ответ, и хотя все существующие ответы были очень полезными, они не совсем решили мою проблему.

google.maps.event.addListenerOnce(googleMap, 'zoom_changed', function() {
    var oldZoom = googleMap.getZoom();
    googleMap.setZoom(oldZoom - 1); //Or whatever
});

По сути, я обнаружил, что событие 'zoom_changed' предотвратило "пропуск" пользовательского интерфейса карты, что произошло, когда я ждал события 'idle'.

Надеюсь, это кому-нибудь поможет!

Я только что исправил это, предварительно установив maxZoom, а затем удалив его впоследствии.Например:

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });

Если я не ошибаюсь, я предполагаю, что вы хотите, чтобы все ваши точки были видны на карте с максимально возможным уровнем масштабирования.Я добился этого, инициализировав уровень масштабирования карты на 16(не уверен, что это максимально возможный уровень масштабирования в версии V3).

var map = new google.maps.Map(document.getElementById('map_canvas'), {
  zoom: 16,
  center: marker_point,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

Затем, после этого, я занялся границами:

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

// You can have a loop here of all you marker points
// Begin loop
bounds.extend(marker_point);
// End loop

map.fitBounds(bounds);

Результат:Успеха!

Я использую:

gmap.setZoom(24); //this looks a high enough zoom value
gmap.fitBounds(bounds); //now the fitBounds should make the zoom value only less

При этом будет использоваться меньшее из 24 значений и необходимый уровень масштабирования в соответствии с вашим кодом, однако это, вероятно, все равно изменит масштаб и не заботится о том, насколько вы уменьшили масштаб.

У меня была такая же проблема, и я смог решить ее, используя следующий код.Этот слушатель (google.maps.addListenerOnce()) событие будет запущено только один раз, сразу после map.fitBounds() выполняется.Таким образом, нет никакой необходимости

  1. Отслеживать прослушиватель и вручную удалять его, или
  2. Подождите, пока карта не будет готова. idle.

Он изначально устанавливает соответствующий уровень масштабирования и позволяет пользователю увеличивать и уменьшать масштаб, превышающий начальный уровень масштабирования, поскольку срок действия прослушивателя событий истек.Например, если только google.maps.addListener() был вызван, тогда пользователь будет никогда иметь возможность увеличивать изображение выше указанного уровня масштабирования (в данном случае 4).С тех пор, как мы внедрили google.maps.addListenerOnce(), пользователь сможет увеличивать изображение до любого уровня, который он / она выберет.

map.fitBounds(bounds);

var zoom_level_for_one_marker = 4;

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

Была такая же проблема, требовалось разместить много маркеров на карте.Это решило мое дело:

  1. Объявлять границы
  2. Используйте схему, предоставленную koderoid (для каждого набора маркеров bounds.extend(objLatLng))
  3. Выполните подгонку ПОСЛЕ завершения создания карты:

    google.maps.event.addListenerOnce(map, 'idle', function() { 
        map.fitBounds( bounds );
    });
    

Я нашел решение, которое выполняет проверку перед вызовом fitBounds таким образом, вы не увеличиваете масштаб изображения и внезапно уменьшаете его

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

// extend bounds with each point

var minLatSpan = 0.001;
if (bounds.toSpan().lat() > minLatSpan) {
    gmap.fitBounds(bounds); 
} else {
    gmap.setCenter(bounds.getCenter());
    gmap.setZoom(16);
}

Вам придется немного поиграться с переменной minLatSpan, чтобы получить ее туда, куда вы хотите.Он будет варьироваться в зависимости как от уровня масштабирования, так и от размеров холста карты.

Вы также могли бы использовать долготу вместо широты

Пожалуйста, попробуйте это:

map.fitBounds(bounds);

// CHANGE ZOOM LEVEL AFTER FITBOUNDS
zoomChangeBoundsListener = google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
  if (this.getZoom()){
    this.setZoom(15);
  }
});
setTimeout(function(){
  google.maps.event.removeListener(zoomChangeBoundsListener)
}, 2000);

Я видел много неправильных или слишком сложных решений, поэтому решил опубликовать рабочее, элегантное решение.

Причина setZoom() работает не так, как вы ожидаете, не так ли fitBounds() является асинхронным, поэтому не дает гарантии, что он немедленно обновит масштабирование, но ваш вызов setZoom() полагается на это.

Что вы могли бы рассмотреть, так это установку minZoom опция отображения перед вызовом fitBounds() а затем очистите его после завершения (чтобы пользователи все еще могли уменьшить масштаб вручную, если захотят).:

var bounds = new google.maps.LatLngBounds();
// ... (extend bounds with all points you want to fit)

// Ensure the map does not get too zoomed out when fitting the bounds.
gmap.setOptions({minZoom: 6});
// Clear the minZoom only after the map fits the bounds (note that
// fitBounds() is asynchronous). The 'idle' event fires when the map
// becomes idle after panning or zooming.
google.maps.event.addListenerOnce(gmap, 'idle', function() {
  gmap.setOptions({minZoom: null});
});

gmap.fitBounds(bounds);

Кроме того, если вы хотите также ограничить максимальное увеличение, вы можете применить тот же трюк с maxZoom собственность.

Посмотрите на Документы mapOptions.

Я использую это для того, чтобы уровень масштабирования не превышал установленного уровня, чтобы я знал, что спутниковые снимки будут доступны.

Добавьте слушателя в zoom_changed событие.Это также дает дополнительное преимущество в управлении элементом управления масштабированием в пользовательском интерфейсе.

Только выполнять setZoom если вам нужно, так что if утверждение предпочтительнее, чем Math.max или к Math.min

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() > 19 ) { 
        map.setZoom(19); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);

Чтобы не увеличивать масштаб слишком сильно:

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() < 6 ) { 
        map.setZoom(6); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);

В этой функции вам нужно динамически добавлять метаданные для хранения типа геометрии только потому, что функция принимает любую геометрию.

"fitGeometries" - это функция JSON, расширяющая объект карты.

"geometries" - это универсальный массив javascript, а не MVCArray().

geometry.metadata = { type: "point" };
var geometries = [geometry];

fitGeometries: function (geometries) {
    // go and determine the latLngBounds...
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < geometries.length; i++) {
        var geometry = geometries[i];
        switch (geometry.metadata.type)
        {
            case "point":
                var point = geometry.getPosition();
                bounds.extend(point);
                break;
            case "polyline":
            case "polygon": // Will only get first path
                var path = geometry.getPath();
                for (var j = 0; j < path.getLength(); j++) {
                    var point = path.getAt(j);
                    bounds.extend(point);
                }
                break;
        }
    }
    this.getMap().fitBounds(bounds);
},

эта работа для меня с API v3, но с настройкой фиксированного масштабирования:

var bounds = new google.maps.LatLngBounds();
// extend bounds with each point

gmap.setCenter(bounds.getCenter()); 
gmap.setZoom( 6 );

Как и я, если вы не хотите играть со слушателями, это простое решение, которое я придумал:Добавьте на карту метод, который работает строго в соответствии с вашими требованиями, подобный этому :

    map.fitLmtdBounds = function(bounds, min, max){
        if(bounds.isEmpty()) return;
        if(typeof min == "undefined") min = 5;
        if(typeof max == "undefined") max = 15;

        var tMin = this.minZoom, tMax = this.maxZoom;
        this.setOptions({minZoom:min, maxZoom:max});
        this.fitBounds(bounds);
        this.setOptions({minZoom:tMin, maxZoom:tMax});
    }

тогда вы можете позвонить map.fitLmtdBounds(bounds) вместо того, чтобы map.fitBounds(bounds) чтобы установить границы в пределах определенного диапазона масштабирования...или map.fitLmtdBounds(bounds,3,5) чтобы переопределить диапазон масштабирования..

Пожалуйста, попробуйте это.

// Find out what the map's zoom level is
zoom = map.getZoom();
if (zoom == 1) {
  // If the zoom level is that low, means it's looking around the
world.
  // Swap the sw and ne coords
  viewportBounds = new
google.maps.LatLngBounds(results[0].geometry.location, initialLatLng);
  map.fitBounds(viewportBounds);
}

Если это будет вам полезно.

Всего наилучшего

После расчета границ вы можете проверить расстояние между верхним левым и нижним правым углами;затем вы можете определить уровень масштабирования, проверив расстояние (если расстояние слишком велико, уровень масштабирования будет низким), затем вы можете выбрать более высокий, используя метод setbound или setZoom..

Мне не хотелось бы предлагать это, но если вы должен попробуйте - первый звонок

gmap.fitBounds(bounds);

Затем создайте новый поток / AsyncTask, переведите его в спящий режим на 20-50 мс или около того, а затем вызовите

gmap.setZoom( Math.max(6, gmap.getZoom()) );

из потока пользовательского интерфейса (используйте обработчик или onPostExecute метод для асинхронной задачи).

Я не знаю, сработает ли это, просто предложение.Кроме этого, вам нужно было бы каким-то образом самостоятельно рассчитать уровень масштабирования по вашим точкам, проверить, не слишком ли он низкий, исправить его, а затем просто вызвать gmap.setZoom(correctedZoom)

Если 'bounds_changed' срабатывает некорректно (иногда Google, похоже, не принимает координаты идеально), то рассмотрите возможность использования вместо этого 'center_changed'.

Событие 'center_changed' срабатывает каждый раз при вызове fitBounds(), хотя оно запускается немедленно и не обязательно после перемещения карты.

В обычных случаях "idle" по-прежнему является лучшим средством прослушивания событий, но это может помочь паре людей, столкнувшихся со странными проблемами при вызовах fitBounds().

Видишь обратный вызов Google maps fitBounds

Чтобы перейти к другому решению - я обнаружил, что подход "прослушать событие bounds_changed, а затем установить новое масштабирование" для меня не работал надежно.Мне кажется, что я иногда звонил fitBounds до того, как карта была полностью инициализирована, и инициализация вызывала событие bounds_changed, которое использовало бы прослушиватель, до fitBounds изменены границы и уровень масштабирования.В итоге я получил этот код, который, кажется, работает до сих пор:

// If there's only one marker, or if the markers are all super close together,
// `fitBounds` can zoom in too far. We want to limit the maximum zoom it can
// use.
//
// `fitBounds` is asynchronous, so we need to wait until the bounds have
// changed before we know what the new zoom is, using an event handler.
//
// Sometimes this handler gets triggered by a different event, before
// `fitBounds` takes effect; that particularly seems to happen if the map
// hasn't been fully initialized yet. So we don't immediately remove the
// listener; instead, we wait until the 'idle' event, and remove it then.
//
// But 'idle' might happen before 'bounds_changed', so we can't set up the
// removal handler immediately. Set it up in the first event handler.

var removeListener = null;
var listener = google.maps.event.addListener(map, 'bounds_changed', () => {
  console.log(map.getZoom());
  if (map.getZoom() > 15) {
    map.setZoom(15);
  }

  if (!removeListener) {
    removeListener = google.maps.event.addListenerOnce(map, 'idle', () => {
      console.log('remove');
      google.maps.event.removeListener(listener);
    });
  }
});

Для меня самым простым решением было следующее:

map.fitBounds(bounds);

function set_zoom() {
    if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
    else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);
google.maps.event.addListener(marker, 'dblclick', function () {
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
});

Все, что я сделал, это:

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

И это работает на API версии V3.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top