API Google Maps v3: Tôi có thể đặtZoom sau fitBound không?


201

Tôi có một tập hợp các điểm tôi muốn vẽ trên Google Map được nhúng (API v3). Tôi muốn giới hạn phù hợp với tất cả các điểm trừ khi mức thu phóng quá thấp (nghĩa là thu nhỏ quá nhiều). Cách tiếp cận của tôi là như thế này:

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

// extend bounds with each point

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

Điều này không hoạt động. Dòng cuối cùng "gmap.setZoom ()" không thay đổi mức thu phóng của bản đồ nếu được gọi trực tiếp sau fitBound.

Có cách nào để có được mức thu phóng của giới hạn mà không áp dụng nó cho bản đồ không? Những ý tưởng khác để giải quyết điều này?


1
Xem stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg nói Khôi phục Monica

Câu trả lời:


337

Chỉnh sửa : Xem bình luận của Matt Diamond bên dưới.

Hiểu rồi! Thử cái này:

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

Sửa đổi theo nhu cầu của bạn.


76
Giải pháp tuyệt vời, hoàn toàn cứu tôi rất nhiều rắc rối. Chỉ muốn thêm rằng bạn có thể đơn giản hóa hơn nữa bằng cách sử dụng phương thức addListenerOnce ... bằng cách đó, bạn không phải lưu người nghe và xóa thủ công, vì phương thức sẽ chăm sóc điều đó cho bạn.
Matt Diamond

9
Điều này có hành vi xem bản đồ "bỏ qua". Thay vào đó hãy lắng nghe sự kiện "zoom_change" và thiết lập nó trước khi gọi fitBound (). Xem câu trả lời của tôi dưới đây
Benjamin Sussman

Cảm ơn! google.maps.event.addListenerOnce (map, "idle", function () {} -> đã hoạt động rất tốt cho gói bản đồ của tôi cho SugarCRM.
jjwdesign

Người nghe không được kích hoạt cho tôi. Tôi đã thử điều này trong document. Yet và window.load. Có ý kiến ​​gì không? đối tượng bản đồ là OK và cũng đã thử addListener: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (map, "idle", function () {alert ('hello');}); `
Henrik Erlandsson

Henrik, hãy thử $ ("# js-main-map-canvas") [0] hoặc $ ("# js-main-map-canvas"). Get (0);
Rafael

68

Tôi đã giải quyết một vấn đề tương tự trong một trong những ứng dụng của mình. Tôi hơi bối rối trước mô tả của bạn về vấn đề này, nhưng tôi nghĩ bạn có cùng mục tiêu tôi đã có ...

Trong ứng dụng của mình, tôi muốn vẽ một hoặc nhiều điểm đánh dấu và đảm bảo bản đồ hiển thị tất cả. Vấn đề là, nếu tôi chỉ dựa vào phương thức fitBound, thì mức thu phóng sẽ được tăng tối đa khi có một điểm duy nhất - điều đó không tốt.

Giải pháp là sử dụng fitBound khi có nhiều điểm và setCenter + setZoom khi chỉ có một điểm.

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

5
Câu trả lời của bạn đã giải quyết vấn đề của tôi với Google Maps V3. Cảm ơn!
FR6

1
Tôi đã có cùng một vấn đề, và giải pháp của bạn đã làm việc! Cảm ơn!
manubkk

Tôi đã thử cách tiếp cận tương tự một mình nhưng nó không hoạt động vì tôi đã không gọi setCenter () trước khi cài đặt thu phóng ... Tôi vẫn tự hỏi tại sao bước này lại cần thiết, nhưng dù sao thì bây giờ nó vẫn hoạt động ... cảm ơn rất nhiều Jim!
mã xác nhận

Trung tâm bản đồ đã giải quyết vấn đề tôi đang gặp phải! Đẹp một +1
Piotr Kula

1
Cảm ơn câu trả lời tốt của bạn +1
Bharat Jigvadiya

44

Tôi đã đến trang này nhiều lần để có câu trả lời, và trong khi tất cả các câu trả lời hiện có là rất hữu ích, chúng không giải quyết chính xác vấn đề của tôi.

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

Về cơ bản, tôi thấy rằng sự kiện 'zoom_changed' đã ngăn giao diện người dùng của bản đồ "bỏ qua" xảy ra khi tôi chờ đợi sự kiện 'nhàn rỗi'.

Hy vọng điều này sẽ giúp ai đó!


4
Tuyệt vời, tôi cũng có hành vi 'bỏ qua / tự động phóng to'. Cũng như một lưu ý cho những người đọc khác: hãy chắc chắn sử dụng "addListenerOnce" như Benjamin làm ở trên thay vì "addListener" hoặc phá vỡ lý do tại sao trình duyệt của bạn gặp sự cố mọi lúc ;-)
Geert-Jan

6
Cũng lưu ý rằng người nghe nên được thêm vào trước khi gọi fitBounds()nếu sử dụngzoom_changed
gapple

1
Cảm ơn vì điều này, có vẻ như v4 nên có fitBound (giới hạn, minZoomLevel) :)
Richard

3
Benjamin, tôi nghĩ sẽ tốt hơn khi sử dụng bounds_changed, vì zoom_changedkhông phải kích hoạt trong trường hợp khi fitBoundsgiữ mức thu phóng. Nỗ lực của tôi jsfiddle.net/rHeMp/10 không xác nhận điều đó, nhưng người ta không nên dựa vào hành vi không xác định.
TMS

10

Tôi vừa sửa lỗi này bằng cách đặt maxZoom trước, sau đó xóa nó sau. Ví dụ:

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

Giải pháp tốt nhất cho đến nay để ngăn chặn phóng to quá nhiều. Đơn giản và trực quan. Không vẽ và vẽ lại bản đồ.
user2605793

Đây thực sự là bước đi tốt nhất cho đến nay.
Downhillski

2
Tôi thấy rằng điều này không hoạt động nếu bạn đặt lại maxZoom ngay sau khi gọi fitBound, vì quá trình thu phóng xảy ra không đồng bộ (vì vậy maxZoom trở lại null vào thời điểm nó phóng to). Chờ cho đến khi "nhàn rỗi" để thiết lập lại nó sẽ khắc phục điều này mặc dù tôi đoán.
dùng987356

4

Nếu tôi không nhầm, tôi cho rằng bạn muốn tất cả các điểm của mình hiển thị trên bản đồ với mức thu phóng cao nhất có thể. Tôi đã thực hiện điều này bằng cách khởi tạo mức thu phóng của bản đồ thành 16 (không chắc đó có phải là mức thu phóng cao nhất có thể trên V3 không).

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

Sau đó, tôi đã làm các công cụ giới hạn:

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

Kết quả: Thành công!


3

Tôi sử dụng:

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

Điều này sẽ sử dụng mức nhỏ hơn 24 và mức thu phóng cần thiết theo mã của bạn, tuy nhiên có thể nó sẽ thay đổi mức thu phóng và không quan tâm đến mức độ bạn thu nhỏ.


Tôi ghét phải nói điều này, nhưng kỳ lạ như câu trả lời này trông giống như, đó là điều duy nhất hoạt động cho đến nay và tôi đã tìm kiếm 4-5 giờ trong khoảng thời gian 3 ngày. Vẫn sẽ tìm kiếm một giải pháp tốt hơn mặc dù.
Allov

3

Vui lòng thử điều này:

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

Tôi đã có cùng một vấn đề và tôi đã có thể giải quyết nó bằng cách sử dụng mã sau đây. Sự kiện listener ( google.maps.addListenerOnce()) này sẽ chỉ được kích hoạt một lần, ngay sau khi map.fitBounds()được thực thi. Vì vậy, không cần phải

  1. Theo dõi và xóa thủ công người nghe, hoặc
  2. Đợi đến khi có bản đồ idle.

Nó đặt mức thu phóng thích hợp ban đầu và cho phép người dùng phóng to và thu nhỏ vượt quá mức thu phóng ban đầu vì trình nghe sự kiện đã hết hạn. Ví dụ: nếu chỉ google.maps.addListener()được gọi, thì người dùng sẽ không bao giờ có thể phóng to qua mức thu phóng đã nêu (trong trường hợp là 4). Kể từ khi chúng tôi triển khai google.maps.addListenerOnce(), người dùng sẽ có thể phóng to đến bất kỳ cấp độ nào anh ấy / cô ấy chọn.

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

Có cùng một vấn đề, cần thiết để phù hợp với nhiều điểm đánh dấu trên bản đồ. Điều này đã giải quyết trường hợp của tôi:

  1. Khai báo giới hạn
  2. Sử dụng sơ đồ được cung cấp bởi koderoid (cho mỗi bộ đánh dấu bounds.extend(objLatLng))
  3. Thực hiện phù hợp với bản đồ SAU đã hoàn thành:

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

2

Tôi đã tìm thấy giải pháp kiểm tra trước khi gọi fitBoundsđể bạn không phóng to và đột nhiên thu nhỏ

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

Bạn sẽ phải chơi xung quanh với biến minLatSpan một chút để đưa nó đến nơi bạn muốn. Nó sẽ thay đổi dựa trên cả mức thu phóng và kích thước của khung vẽ bản đồ.

Bạn cũng có thể sử dụng kinh độ thay vì vĩ độ


Hoạt động với tôi, nhưng tôi không sử dụng minLatSpan - Tôi chỉ cần đặt thu phóng khi có 1 điểm đánh dấu trên bản đồ. Vì vậy, tôi chỉ kiểm tra nếu có nhiều hơn 1 điểm đánh dấu.
Micer

2

Tôi thấy nhiều giải pháp không chính xác hoặc quá phức tạp, vì vậy quyết định đăng một giải pháp thanh lịch, hiệu quả .

Lý do setZoom()không hoạt động như bạn mong đợi là fitBounds()không đồng bộ, do đó không đảm bảo rằng nó sẽ cập nhật ngay lập tức thu phóng, nhưng cuộc gọi của bạn setZoom()phụ thuộc vào điều đó.

Những gì bạn có thể xem xét là thiết lập minZoomtùy chọn bản đồ trước khi gọi fitBounds()và sau đó xóa nó sau khi hoàn thành (để người dùng vẫn có thể thu nhỏ thủ công nếu họ muốn):

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

Ngoài ra, nếu bạn cũng muốn giới hạn mức thu phóng tối đa, bạn có thể áp dụng thủ thuật tương tự với maxZoom tính.

Xem tài liệu MapOptions .


1

Tôi sử dụng điều này để đảm bảo mức thu phóng không vượt quá mức đã đặt để tôi biết hình ảnh vệ tinh sẽ khả dụng.

Thêm một người nghe cho zoom_changedsự kiện này. Điều này cũng có thêm lợi ích của việc kiểm soát điều khiển thu phóng trên UI.

Chỉ thực hiện setZoomnếu bạn cần, vì vậy một ifcâu lệnh thích hợp hơn Math.maxhoặcMath.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);

Để tránh thu nhỏ quá xa:

   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

Trong hàm này, bạn cần tự động thêm siêu dữ liệu để lưu trữ loại hình học chỉ vì hàm này chấp nhận bất kỳ hình dạng nào.

"fitGeometries" là một hàm JSON mở rộng một đối tượng bản đồ.

"Hình học" là một mảng javascript chung không phải là 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);
},

Thay phiên, tôi đã làm tất cả công việc mà không biết rằng có một phương thức extend () trên đối tượng LatLngBound. Điều này sẽ dễ dàng hơn nhiều.
CrazyEnigma

1

công việc này đối với tôi với API v3 nhưng với cài đặt thu phóng cố định:

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

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

1

Giống như tôi, nếu bạn không sẵn sàng chơi với người nghe, đây là một giải pháp đơn giản tôi đã nghĩ ra: Thêm một phương pháp trên bản đồ hoạt động đúng theo yêu cầu của bạn như thế này:

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

sau đó bạn có thể gọi map.fitLmtdBounds(bounds)thay vì map.fitBounds(bounds)đặt giới hạn trong phạm vi thu phóng được xác định ... hoặc map.fitLmtdBounds(bounds,3,5)để ghi đè phạm vi thu phóng ..


0

Hãy thử điều này.

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

Nếu điều này sẽ hữu ích cho bạn.

Tất cả tốt nhất


0

Sau khi tính toán các cột, bạn có thể kiểm tra khoảng cách giữa góc trên bên trái và góc dưới bên phải; sau đó bạn có thể hiểu mức thu phóng bằng cách kiểm tra khoảng cách (nếu khoảng cách quá xa mức thu phóng sẽ thấp) thì bạn có thể chọn wheter bằng phương pháp setbound hoặc setZoom ..


0

Tôi không muốn đề xuất nó, nhưng nếu bạn phải thử - hãy gọi trước

gmap.fitBounds(bounds);

Sau đó, tạo một Thread / AsyncTask mới, ngủ trong 20-50ms hoặc sau đó gọi

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

từ luồng UI (sử dụng trình xử lý hoặc onPostExecutephương thức cho AsyncTask).

Tôi không biết nếu nó hoạt động, chỉ là một gợi ý. Ngoài ra, bạn phải tự mình tính toán mức thu phóng từ các điểm của mình, kiểm tra xem nó có quá thấp không, sửa nó và sau đó chỉ cần gọigmap.setZoom(correctedZoom)


0

Nếu 'bound_changed' không bắn chính xác (đôi khi Google dường như không chấp nhận tọa độ hoàn hảo), thì hãy xem xét sử dụng 'centre_changed' thay thế.

Sự kiện 'centre_changed' kích hoạt mỗi khi fitBound () được gọi, mặc dù nó chạy ngay lập tức và không nhất thiết sau khi bản đồ đã di chuyển.

Trong các trường hợp bình thường, 'idle' vẫn là trình lắng nghe sự kiện tốt nhất, nhưng điều này có thể giúp một vài người gặp phải các vấn đề kỳ lạ với các cuộc gọi fitBound () của họ.

Xem google maps fitBound gọi lại


0

Để kết hợp với một giải pháp khác - tôi thấy rằng phương pháp "lắng nghe giới hạn bẻ khóa và sau đó thiết lập thu phóng mới" không hoạt động đáng tin cậy đối với tôi. Tôi nghĩ rằng đôi khi tôi đã gọi fitBoundstrước khi bản đồ được khởi tạo hoàn toàn và việc khởi tạo đã gây ra một sự kiện giới hạn sẽ sử dụng hết người nghe, trước khi fitBoundsthay đổi ranh giới và mức thu phóng. Tôi đã kết thúc với mã này, dường như hoạt động cho đến nay:

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

Đối với tôi giải pháp đơn giản nhất là đây:

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

Tất cả những gì tôi đã làm là:

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

Và nó hoạt động trên API V3.


map.setCenter chỉ chấp nhận một thuộc tính, latlng và bản đồ không có chức năng như getBoundZoomLevel
Viktor

Tôi nghĩ rằng có một chức năng như getBoundZoomLevel sau khi tôi thấy bài đăng này, và tôi thất vọng sau khi tôi nhận ra rằng không có.
sedran

tôi nghĩ getBoundZoomLevel () đã có sẵn trong API Google Maps V2 và không có trong API V3
Kush
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.