Google Maps API v3: Dapatkah saya mengaturZoom setelah fitBounds?


201

Saya memiliki serangkaian poin yang ingin saya plot di Google Map yang disematkan (API v3). Saya ingin batas untuk mengakomodasi semua titik kecuali jika tingkat zoom terlalu rendah (mis. Terlalu memperkecil). Pendekatan saya seperti ini:

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

// extend bounds with each point

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

Ini tidak berhasil. Baris terakhir "gmap.setZoom ()" tidak mengubah level zoom peta jika dipanggil langsung setelah fitBounds.

Apakah ada cara untuk mendapatkan tingkat zoom batas tanpa menerapkannya pada peta? Gagasan lain untuk menyelesaikan ini?


1
Lihat stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg mengatakan mengembalikan Monica

Jawaban:


337

Sunting : Lihat komentar Matt Diamond di bawah ini.

Mengerti! Coba ini:

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

Ubah sesuai kebutuhan Anda.


76
Solusi hebat, benar-benar menyelamatkan saya dari banyak masalah. Hanya ingin menambahkan bahwa Anda dapat menyederhanakannya lebih jauh dengan menggunakan metode addListenerOnce ... dengan cara itu, Anda tidak perlu menyimpan pendengar dan menghapusnya secara manual, karena metode itu akan mengurusnya untuk Anda.
Matt Diamond

9
Ini memiliki perilaku melihat peta "lewati". Alih-alih dengarkan acara "zoom_change", dan atur sebelum memanggil fitBounds (). Lihat jawaban saya di bawah ini
Benjamin Sussman

Terima kasih! google.maps.event.addListenerOnce (peta, "idle", function () {} -> bekerja sangat baik untuk paket peta saya untuk SugarCRM.
jjwdesign

Pendengar tidak terpicu untuk saya. Saya mencoba ini di document.ready dan window.load. Ada ide? objek peta OK dan coba addListener juga: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (peta, "idle", function () {alert ('hello');}); `
Henrik Erlandsson

Henrik, coba $ ("# js-main-map-canvas") [0] atau $ ("# js-main-map-canvas"). Dapatkan (0);
Rafael

68

Saya memecahkan masalah serupa di salah satu aplikasi saya. Saya sedikit bingung dengan deskripsi masalah Anda, tetapi saya pikir Anda memiliki tujuan yang sama dengan yang saya miliki ...

Di aplikasi saya, saya ingin memplot satu atau lebih spidol dan memastikan peta menunjukkan semuanya. Masalahnya adalah, jika saya hanya mengandalkan metode fitBounds, maka tingkat zoom akan dimaksimalkan ketika ada satu titik - itu tidak baik.

Solusinya adalah menggunakan fitBounds ketika ada banyak poin, dan setCenter + setZoom ketika hanya ada satu titik.

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

5
Jawaban Anda telah menyelesaikan masalah saya dengan Google Maps V3. Terima kasih!
FR6

1
Saya memiliki masalah yang sama persis, dan solusi Anda berhasil! Terima kasih!
manubkk

Saya mencoba pendekatan yang sama sendiri tetapi tidak berhasil karena saya tidak menggunakan setCenter () sebelum mengatur zoom ... Saya masih bertanya-tanya mengapa langkah ini diperlukan, tapi tetap sekarang ini bekerja ... terima kasih a banyak Jim!
daveoncode

Map Center memecahkan masalah yang saya alami! Bagus satu +1
Piotr Kula

1
Terima kasih atas jawaban Baik Anda +1
Bharat Chodvadiya

44

Saya telah mengunjungi halaman ini beberapa kali untuk mendapatkan jawabannya, dan sementara semua jawaban yang ada sangat membantu, mereka tidak menyelesaikan masalah saya dengan tepat.

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

Pada dasarnya saya menemukan bahwa acara 'zoom_changed' mencegah UI peta dari "melompati" yang terjadi ketika saya menunggu acara 'idle'.

Semoga ini bisa membantu seseorang!


4
Luar biasa, saya juga memiliki perilaku 'melompati / memperbesar otomatis'. Sama seperti catatan untuk pembaca lain: pastikan untuk menggunakan "addListenerOnce" seperti yang dilakukan Benjamin di atas alih-alih "addListener", atau hancurkan pikiran Anda mengapa browser Anda mogok sepanjang waktu ;-)
Geert-Jan

6
Perhatikan juga bahwa pendengar harus ditambahkan sebelum menelepon fitBounds()jika menggunakanzoom_changed
gapple

1
Terima kasih untuk ini, sepertinya v4 harus memiliki fitBounds (bounds, minZoomLevel) :)
Richard

3
Benjamin, saya pikir itu lebih baik untuk digunakan bounds_changed, karena zoom_changedtidak harus dipicu dalam kasus ini ketika fitBoundsmenjaga tingkat zoom. Upaya saya jsfiddle.net/rHeMp/10 tidak mengkonfirmasi itu, tetapi orang tidak harus bergantung pada perilaku yang tidak terdefinisi.
TMS

10

Saya baru saja memperbaiki ini dengan mengatur maxZoom terlebih dahulu, kemudian menghapusnya setelah itu. Sebagai contoh:

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

Solusi terbaik sejauh ini untuk mencegah zoom terlalu banyak. Sederhana dan intuitif. Tidak ada gambar dan gambar ulang peta.
user2605793

Ini memang langkah terbaik sejauh ini.
Downhillski

2
Saya menemukan bahwa ini tidak berfungsi jika Anda mereset maxZoom segera setelah memanggil fitBounds, karena zoom terjadi secara tidak serempak (jadi maxZoom kembali ke nol saat diperbesar). Menunggu sampai "idle" untuk mengatur ulang akan memperbaikinya meskipun saya kira.
user987356

4

Jika saya tidak salah, saya berasumsi Anda ingin semua poin Anda terlihat di peta dengan tingkat zoom setinggi mungkin. Saya menyelesaikan ini dengan menginisialisasi tingkat zoom peta ke 16 (tidak yakin apakah itu tingkat zoom setinggi mungkin pada V3).

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

Kemudian setelah itu saya melakukan hal-hal batas:

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

Hasil: Sukses!


3

Saya menggunakan:

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

Ini akan menggunakan yang lebih kecil dari 24 dan tingkat zoom yang diperlukan sesuai dengan kode Anda, namun itu mungkin mengubah zoom pula dan tidak peduli berapa banyak Anda memperkecil.


Aku benci mengatakan ini, tapi seaneh jawaban ini, itu satu-satunya yang berhasil sejauh ini dan aku sudah mencari 4-5 jam dalam rentang 3 hari. Akan tetap mencari solusi yang lebih baik.
Allov

3

Silakan coba ini:

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

2

Saya memiliki masalah yang sama dan saya bisa menyelesaikannya menggunakan kode berikut. Acara pendengar ( google.maps.addListenerOnce()) ini hanya akan dipecat satu kali, tepat setelah map.fitBounds()dieksekusi. Jadi, tidak perlu

  1. Melacak dan menghapus pendengar secara manual, atau
  2. Tunggu sampai peta selesai idle.

Ini mengatur tingkat zoom yang sesuai pada awalnya dan memungkinkan pengguna untuk memperbesar dan memperkecil tingkat zoom awal karena pendengar acara telah kedaluwarsa. Misalnya, jika hanya google.maps.addListener()dipanggil, maka pengguna tidak akan pernah bisa memperbesar melewati tingkat zoom yang dinyatakan (dalam kasus ini, 4). Karena kami menerapkan google.maps.addListenerOnce(), pengguna akan dapat memperbesar ke level apa pun yang dia pilih.

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

2

Punya masalah yang sama, diperlukan agar sesuai dengan banyak spidol di peta. Ini menyelesaikan kasus saya:

  1. Nyatakan batas
  2. Gunakan skema yang disediakan oleh koderoid (untuk setiap set marker bounds.extend(objLatLng))
  3. Jalankan fitbounds SETELAH peta selesai:

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

2

Saya telah menemukan solusi yang melakukan pemeriksaan sebelum menelepon fitBoundssehingga Anda tidak memperbesar dan tiba-tiba memperkecil

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

Anda harus bermain-main dengan variabel minLatSpan sedikit untuk mendapatkannya di tempat yang Anda inginkan. Ini akan bervariasi berdasarkan level zoom dan dimensi kanvas peta.

Anda juga bisa menggunakan garis bujur dan bukan garis lintang


Bekerja untuk saya, tapi saya tidak menggunakan minLatSpan - Saya perlu mengatur zoom hanya ketika 1 marker ada di peta. Karena itu saya hanya memeriksa apakah ada lebih dari 1 spidol.
Micer

2

Saya melihat banyak solusi yang salah atau terlalu rumit, jadi saya memutuskan untuk memposting solusi yang berfungsi dan elegan .

Alasannya setZoom()tidak berfungsi seperti yang Anda harapkan adalah karena fitBounds()tidak sinkron, sehingga tidak memberikan jaminan bahwa itu akan segera memperbarui zoom, tetapi panggilan Anda untuk setZoom()mengandalkan itu.

Yang mungkin Anda pertimbangkan adalah mengatur minZoomopsi peta sebelum memanggil fitBounds()dan kemudian menghapusnya setelah selesai (sehingga pengguna masih dapat memperkecil secara manual jika mereka mau):

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

Selain itu, jika Anda ingin juga membatasi zoom maks, Anda dapat menerapkan trik yang sama dengan maxZoomproperti.

Lihat dokumen MapOptions .


1

Saya menggunakan ini untuk memastikan level zoom tidak melebihi level yang ditentukan sehingga saya tahu gambar satelit akan tersedia.

Tambahkan pendengar ke zoom_changedacara tersebut. Ini memiliki manfaat tambahan untuk mengontrol kontrol zoom pada UI juga.

Eksekusi hanya setZoomjika Anda perlu, jadi ifpernyataan lebih disukai Math.maxatauMath.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);

Untuk mencegah memperkecil terlalu jauh:

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

1

Dalam fungsi ini, Anda perlu menambahkan metadata secara dinamis untuk menyimpan jenis geometri hanya karena fungsi menerima geometri apa pun.

"fitGeometries" adalah fungsi JSON yang memperluas objek peta.

"geometri" adalah array javascript generik bukan 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);
},

Bergantian, saya melakukan semua pekerjaan tanpa mengetahui bahwa ada metode extended () pada objek LatLngBounds. Ini akan jauh lebih mudah.
CrazyEnigma

1

ini cocok untuk saya dengan API v3 tetapi dengan pengaturan zoom tetap:

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

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

1

Seperti saya, jika Anda tidak mau bermain dengan pendengar, ini adalah solusi sederhana yang saya buat: Tambahkan metode pada peta yang bekerja secara ketat sesuai dengan kebutuhan Anda seperti ini:

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

maka Anda dapat menelepon map.fitLmtdBounds(bounds)alih-alih map.fitBounds(bounds)mengatur batas di bawah rentang zoom yang ditentukan ... atau map.fitLmtdBounds(bounds,3,5)untuk menimpa rentang zoom ..


0

Silakan coba ini.

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

Jika ini akan membantu Anda.

Semua yang terbaik


0

Setelah perhitungan batas Anda dapat memeriksa jarak antara sudut kiri atas dan kanan bawah; maka Anda dapat memahami tingkat zoom dengan menguji jarak (jika jarak terlalu jauh tingkat zoom akan rendah) maka Anda dapat memilih apakah menggunakan metode setbound atau setZoom ..


0

Saya tidak suka menyarankannya, tetapi jika Anda harus mencoba - panggilan pertama

gmap.fitBounds(bounds);

Kemudian buat Thread / AsyncTask baru, minta tidur selama 20-50ms atau lebih dan kemudian panggil

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

dari utas UI (gunakan handler atau onPostExecutemetode untuk AsyncTask).

Saya tidak tahu apakah itu berhasil, hanya sebuah saran. Selain itu, Anda harus menghitung sendiri tingkat pembesaran dari poin Anda sendiri, periksa apakah terlalu rendah, perbaiki, lalu panggil sajagmap.setZoom(correctedZoom)


0

Jika 'bounds_changed' tidak diaktifkan dengan benar (terkadang Google tampaknya tidak menerima koordinat dengan sempurna), maka pertimbangkan untuk menggunakan 'center_changed'.

Peristiwa 'center_changed' diaktifkan setiap kali fitBounds () dipanggil, meskipun berjalan segera dan tidak harus setelah peta dipindahkan.

Dalam kasus normal, 'idle' masih menjadi pendengar acara terbaik, tetapi ini dapat membantu beberapa orang mengalami masalah aneh dengan panggilan fitBounds () mereka.

Lihat callback Google Map fitBounds


0

Untuk berpadu dengan solusi lain - saya menemukan bahwa pendekatan "mendengarkan acara bounds_changed dan kemudian mengatur zoom baru" tidak bekerja andal bagi saya. Saya pikir saya kadang-kadang menelepon fitBoundssebelum peta diinisialisasi penuh, dan inisialisasi menyebabkan peristiwa bounds_changed yang akan menghabiskan pendengar, sebelum fitBoundsmengubah batas dan tingkat zoom. Saya berakhir dengan kode ini, yang tampaknya berfungsi sejauh ini:

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

0

Bagi saya solusi termudah adalah ini:

map.fitBounds(bounds);

function set_zoom() {
    if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
    else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);

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

-3

Yang saya lakukan adalah:

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

Dan itu bekerja pada V3 API.


map.setCenter hanya menerima satu atribut, latlng, dan peta tidak memiliki fungsi seperti getBoundsZoomLevel
Viktor

Saya pikir ada fungsi seperti getBoundsZoomLevel setelah saya melihat posting ini, dan saya kecewa setelah saya sadar tidak ada.
sedran

saya pikir getBoundsZoomLevel () tersedia di Google Maps V2 API dan tidak di V3 API
Kush
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.