Google Maps API v3:fitBoundsの後にsetZoomを実行できますか?


201

埋め込み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の直後に呼び出された場合、マップのズームレベルを変更しません。

マップに適用せずに境界のズームレベルを取得する方法はありますか?これを解決するための他のアイデア?


1
stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3をご覧ください
Mawgはモニカを2014

回答:


337

編集:以下のマットダイアモンドのコメントを参照してください。

とった!これを試して:

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

必要に応じて変更してください。


76
素晴らしい解決策は、私に多くのトラブルを完全に救いました。addListenerOnceメソッドを使用してさらに単純化できることを追加したかっただけです...この方法では、リスナーが保存して手動で削除する必要がなく、メソッドが自動的に処理します。
マットダイアモンド

9
これには、マップを「スキップ」する動作があります。代わりに、「zoom_change」イベントをリッスンし、fitBounds()を呼び出す前にセットアップします。以下の私の回答を参照してください
ベンジャミンサスマン

ありがとう!google.maps.event.addListenerOnce(map、 "idle"、function(){}-> SugarCRMの私のマップパッケージに
最適

リスナーがトリガーされません。document.readyとwindow.loadでこれを試しました。何か案は?mapオブジェクトはOKで、addListenerも試しました: `var map = $("#js-main-map-canvas "); var listener = google.maps.event.addListenerOnce(map、 "idle"、function(){alert( 'hello');}); `
Henrik Erlandsson 14年

Henrik、$( "#js-main-map-canvas")[0]または$( "#js-main-map-canvas")。get(0);を試してください。
ラファエル

68

アプリの1つで同様の問題を解決しました。問題の説明に少し戸惑いましたが、私と同じ目標を持っていると思います...

私のアプリでは、1つ以上のマーカーをプロットし、マップがそれらすべてを表示していることを確認したいと考えていました。問題は、私がfitBoundsメソッドのみに依存している場合、単一の点があるとズームレベルが最大になることでした。これは良くありませんでした。

解決策は、ポイントが多い場合はfitBoundsを使用し、ポイントが1つしかない場合はsetCenter + setZoomを使用することでした。

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

5
あなたの答えはGoogle Maps V3の私の問題を解決しました。ありがとう!
FR6

1
私はまったく同じ問題を抱えていましたが、あなたの解決策はうまくいきました!ありがとう!
manubkk

私は自分で同じアプローチを試していましたが、ズームを設定する前にsetCenter()を呼び出さなかったため、うまくいきませんでした...なぜこのステップが必要なのか疑問に思っていますが、とにかく今はうまくいきます...たくさんのジム!
daveoncode

マップセンターは私が抱えていた問題を解決しました!
ナイスワン

1
良い答えをありがとう+1
Bharat Chodvadiya

44

私は何度もこのページにアクセスして回答を得ました。既存の回答はすべて非常に役に立ちましたが、問題を正確に解決することはできませんでした。

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

基本的に、私は「zoom_changed」イベントが「アイドル」イベントを待っているときに発生したマップのUIの「スキップ」を妨げていることを発見しました。

これが誰かに役立つことを願っています!


4
素晴らしい、「スキップ/自動ズーム」動作もありました。他の読者へのメモとして:ベンジャミンが上記の「addListener」の代わりに行う「addListenerOnce」を必ず使用するか、ブラウザが常にクラッシュする理由を理解してください;-)
Geert-Jan

6
またfitBounds()、使用する場合は、呼び出す前にリスナーを追加する必要があることに注意してくださいzoom_changed
gapple

1
このおかげで、v4にはfitBounds(bounds、minZoomLevel)が必要です:)
Richard

3
ベンジャミン、ズームレベルを維持する場合はトリガーする必要がないbounds_changedため、を使用する方が良いと思います。私の試みjsfiddle.net/rHeMp/10はそれを確認していませんが、未定義の動作に依存すべきではありません。zoom_changedfitBounds
TMS

10

これを修正するには、前もってmaxZoomを設定し、後で削除します。例えば:

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

ズームインしすぎないようにするための最善の解決策です。シンプルで直感的。地図の描画と再描画はありません。
user2605793 2014年

これは確かにこれまでのところ最高のウォークアラウンドです。
ダウンヒル

2
ズームは非同期で行われるため(ズームインするまでにmaxZoomがnullに戻るため)、fitBoundsを呼び出した直後にmaxZoomをリセットすると、これは機能しません。「アイドル」がリセットされるまで待つと、これは修正されると思いますが。
user987356 2017

4

私が間違っていないのであれば、すべてのポイントを可能な限り高いズームレベルで地図上に表示したいと考えています。これを実現するには、マップのズームレベルを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);

結果:成功しました!


3

私が使う:

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

これは24のうち小さい方とコードに応じて必要なズームレベルを使用しますが、おそらくズームを変更し、ズームアウトの量は気にしません。


私はこれを言うのが嫌ですが、この答えが奇妙に見えたように、これはこれまでに機能した唯一のものであり、私は3日間で4〜5時間を探していました。まだより良い解決策を探しています。
Allov、2011年

3

これを試してください:

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

同じ問題があり、次のコードを使用して解決できました。このリスナー(google.maps.addListenerOnce())イベントmap.fitBounds()は、実行直後に1回だけ発生します。だから、する必要はありません

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

2

同じ問題があり、マップ上の多くのマーカーを合わせる必要がありました。これは私のケースを解決しました:

  1. 境界を宣言する
  2. koderoidが提供するスキームを使用(マーカーセットごとにbounds.extend(objLatLng)
  3. マップが完了した後にfitboundsを実行します。

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

2

呼び出す前にチェック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変数を少しいじる必要があります。ズームレベルとマップキャンバスのサイズの両方に基づいて変化します。

緯度の代わりに経度を使用することもできます


動作しますが、minLatSpanを使用していません。マップにマーカーが1つある場合のみズームを設定する必要があります。したがって、私は1つ以上のマーカーがあるかどうかのみをチェックしています。
マイサー2014

2

私は多くの誤った、または複雑すぎるソリューションを見たので、実用的でエレガントなソリューションを投稿することにしました。

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のドキュメントをご覧ください。


1

これを使用して、ズームレベルが設定レベルを超えないようにし、衛星画像が利用可能になることを確認します。

zoom_changedイベントにリスナーを追加します。これには、UI上のズームコントロールを制御するという追加の利点もあります。

のみ実行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);

1

この関数では、ジオメトリを受け入れるためだけに、ジオメトリタイプを格納するためにメタデータを動的に追加する必要があります。

「fitGeometries」は、マップオブジェクトを拡張するJSON関数です。

「geometries」は、MVCArray()ではなく、汎用のJavaScript配列です。

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

あるいは、LatLngBoundsオブジェクトにextend()メソッドがあることを知らずにすべての作業を行いました。これははるかに簡単です。
CrazyEnigma 2010

1

この作業は私にとってAPI v3を使用していますが、固定ズームを設定しています:

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

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

1

私のように、あなたがリスナーと遊ぶ気がないなら、これは私が思いついた簡単な解決策です:このようなあなたの要件に従って厳密に機能するマップにメソッドを追加してください:

    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)、ズーム範囲をオーバーライドしたりできます。


0

ぜひお試しください。

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

これがあなたに役立つかどうか。

ではごきげんよう


0

境界の計算後、左上隅と右下隅の間の距離を確認できます。次に、距離をテストすることでズームレベルを理解できます(距離が遠すぎる場合、ズームレベルは低くなります)。その後、setboundメソッドまたはsetZoomを使用して選択できます。


0

私はそれを提案したくありませんが、あなた試す必要がある場合-最初の電話

gmap.fitBounds(bounds);

次に、新しいThread / AsyncTaskを作成し、20〜50ミリ秒ほどスリープさせてから、

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

UIスレッドから(onPostExecuteAsyncTaskのハンドラーまたはメソッドを使用)。

それが機能するかどうかはわかりませんが、単なる提案です。それ以外は、自分でポイントからズームレベルを何らかの方法で計算し、低すぎるかどうかを確認し、修正してから、次のように呼び出す必要があります。gmap.setZoom(correctedZoom)


0

「bounds_changed」が正しく実行されない場合(Googleが座標を完全に受け入れないように見える場合があります)、代わりに「center_changed」の使用を検討してください。

'center_changed'イベントは、fitBounds()が呼び出されるたびに発生しますが、マップが移動した直後に実行されるわけではありません。

通常の場合、「アイドル」は依然として最良のイベントリスナーですが、これは、fitBounds()呼び出しで奇妙な問題が発生しているカップルを助ける場合があります。

グーグルマップを見るfitBoundsコールバック


0

別の解決策を試してみると、「bounds_changedイベントをリッスンしてから、新しいズームを設定する」というアプローチは、確実に機能しないことがわかりました。fitBounds地図が完全に初期化される前に呼び出すことがあったと思います。初期化によりfitBounds、境界とズームレベルが変更される前に、リスナーを使い果たすbounds_changedイベントが発生していました。私はこのコードで終わりました、これは今のところうまくいくようです:

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

私にとって最も簡単な解決策はこれです:

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

私がしたことはすべて:

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

そしてそれはV3 APIで動作します。


map.setCenterは1つの属性latlngのみを受け入れ、mapにはgetBoundsZoomLevelのような関数はありません
Viktor

この投稿を見て、getBoundsZoomLevelのような関数があると思いましたが、ないことに気付いてがっかりしました。
セダン

getBoundsZoomLevel()はV3 APIではなくGoogle Maps V2 APIで利用可能だったと思います
Kush
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.