web-dev-qa-db-ja.com

Google Maps API V3でパンを制限するにはどうすればよいですか?

V2では、マップが特定の境界内に収まるようにパン/ドラッグを制限する方法がありました。 V3ではどのように行われますか?

ユーザーにヨーロッパのみを見てもらいたいとしましょう。ズームはすでに制限していますが、ドラッグを許可する場合(この場合、他の理由でこれを行う必要があります)、ユーザーは表示したい領域を超えてパンできます。

実用的な例またはコードスニペットを教えてください-私はエキスパートコーダーではありません...

ありがとう!

74
E. Tal

私はパーティーに少し遅れていると思いますが、これはまさに今必要だったものであり、改善したので、とにかく答えを投稿すると思いました。

Daniel Vassallobrendo の両方の答えがあれば、ユーザーはパンコントロール(有効になっている場合)を使用して、必要な領域から離れることができます。 @ Yauhen.Fがコメントで言及したもの。

したがって、dragendイベントを使用する代わりに、center_changedイベントを使用します。これは、ドラッグ中および誰かがパンコントロールを使用するたびに連続的に発生します。

// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(70.33956792419954, 178.01171875), 
     new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();

google.maps.event.addListener(map, 'center_changed', function() {
    if (allowedBounds.contains(map.getCenter())) {
        // still within valid bounds, so save the last valid position
        lastValidCenter = map.getCenter();
        return; 
    }

    // not valid anymore => return to last valid position
    map.panTo(lastValidCenter);
});

ドラッグ中に最後の有効な位置を継続的に保存することにより、ドラッグが終了するとすぐに移動するのではなく、範囲外になると移動が停止します。 ......

91
HenningJ

トリックは、dragendイベントをリッスンし、マップが許可された境界の外側にドラッグされた場合、内側に戻すことです。許可された境界を LatLngBounds オブジェクトとして定義する場合、contains()メソッドを使用できます。指定されたlat/lng引数が境界。

ズームレベルを制限することも重要ですが、すでにこれを行っているようです。

したがって、次の例を試してください。

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps JavaScript API v3 Example: Limit Panning</title> 
   <script type="text/javascript" 
           src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px;"></div> 

   <script type="text/javascript"> 

   var minZoomLevel = 5;

   var map = new google.maps.Map(document.getElementById('map'), {
      zoom: minZoomLevel,
      center: new google.maps.LatLng(38.50, -90.50),
      mapTypeId: google.maps.MapTypeId.ROADMAP
   });

   // Bounds for North America
   var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(28.70, -127.50), 
     new google.maps.LatLng(48.85, -55.90));

   // Listen for the dragend event
   google.maps.event.addListener(map, 'dragend', function() {
     if (allowedBounds.contains(map.getCenter())) return;

     // Out of bounds - Move the map back within the bounds

     var c = map.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = allowedBounds.getNorthEast().lng(),
         maxY = allowedBounds.getNorthEast().lat(),
         minX = allowedBounds.getSouthWest().lng(),
         minY = allowedBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     map.setCenter(new google.maps.LatLng(y, x));
   });

   // Limit the zoom level
   google.maps.event.addListener(map, 'zoom_changed', function() {
     if (map.getZoom() < minZoomLevel) map.setZoom(minZoomLevel);
   });

   </script> 
</body> 
</html>

上記の例のスクリーンショット。この場合、ユーザーはさらに南または極東にドラッグすることはできません。

Google Maps JavaScript API v3 Example: Limit Panning

21
Daniel Vassallo

私のバージョンは、@ HenningJのものに基づいていますが、lastValidCenterを変更して、の端に沿ってスムーズにドラッグできるようにします境界。

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            html { height: 100% }
            body { height: 100%; margin: 0; padding: 0 }
            #map-canvas { height: 100% }
        </style>
        <script type="text/javascript"
            src="http://maps.google.com/maps/api/js?sensor=false"></script>
        </script>
        <script type="text/javascript">
            function initialize() {
                var mapOptions = {
                    center: new google.maps.LatLng(28.70, -127.50),
                    zoom: 4,
                    mapTypeId: google.maps.MapTypeId.ROADMAP
                };
                var map = new google.maps.Map(document.getElementById("map-canvas"),
                        mapOptions);

                // bounds of the desired area
                var allowedBounds = new google.maps.LatLngBounds(
                  new google.maps.LatLng(28.70, -127.50),
                  new google.maps.LatLng(48.85, -55.90)
                );
                var boundLimits = {
                    maxLat : allowedBounds.getNorthEast().lat(),
                    maxLng : allowedBounds.getNorthEast().lng(),
                    minLat : allowedBounds.getSouthWest().lat(),
                    minLng : allowedBounds.getSouthWest().lng()
                };

                var lastValidCenter = map.getCenter();
                var newLat, newLng;
                google.maps.event.addListener(map, 'center_changed', function() {
                    center = map.getCenter();
                    if (allowedBounds.contains(center)) {
                        // still within valid bounds, so save the last valid position
                        lastValidCenter = map.getCenter();
                        return;
                    }
                    newLat = lastValidCenter.lat();
                    newLng = lastValidCenter.lng();
                    if(center.lng() > boundLimits.minLng && center.lng() < boundLimits.maxLng){
                        newLng = center.lng();
                    }
                    if(center.lat() > boundLimits.minLat && center.lat() < boundLimits.maxLat){
                        newLat = center.lat();
                    }
                    map.panTo(new google.maps.LatLng(newLat, newLng));
                });
            }
            google.maps.event.addDomListener(window, 'load', initialize);
        </script>
    </head>
    <body>
        <div id="map-canvas"/>
    </body>
</html>

ここでフィドル: http://jsfiddle.net/koenpunt/n7h6t/

9
Koen.

制限する最良の方法は、ズームレベルと中心点を設定し、ズーム、スクロールなどのコントロールを以下のように無効にすることです。

 var latlng = new google.maps.LatLng(18.283078,84.047556);
     var myOptions = {
          zoom: 12,

          center: latlng,
          zoomControl: false,
          mapTypeId: google.maps.MapTypeId.ROADMAP,
          scrollwheel: false,
        navigationControl: false,
        mapTypeControl: false,
        scaleControl: false,
        draggable: false,
        disableDoubleClickZoom: true,
        };
        map = new google.maps.Map(document.getElementById("map_canvas"),   myOptions);
3
AjayR

上記 のNice拡張機能は、dragstartイベントをリッスンすることにより、マップの中心を最後の有効な位置にリセットします。

// Limit panning
var lastCenter = map.getCenter();

google.maps.event.addListener(map, 'dragstart', function() {
    lastCenter = map.getCenter();
});

google.maps.event.addListener(map, 'dragend', function() {
    if(allowedBounds.contains(map.getCenter())) return;

    map.setCenter(lastCenter);
});
3
brendo

これは、Tom Andersenの回答と現在受け入れられているHenningJの回答を組み合わせたソリューションです。これの利点は、1)エッジに沿ったスムーズなスクロールを可能にし(HenningJのソリューションは不格好だと思われます)、2)エリアの外にズームインしても問題がありません(再び、HenningJの答えはズームイン時に壊れているようです)境界付近)。

トムの答えは、ロックオフ領域を画面の中央に配置したことを除いて、私にとってはほぼ機能していました。

// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(70.33956792419954, 178.01171875), 
     new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();

google.maps.event.addListener(map, 'center_changed', function() {

    var mapBounds = map.getBounds();
    var mapNe = mapBounds.getNorthEast();
    var mapSw = mapBounds.getSouthWest();
    var center = map.getCenter();

    if( allowedBounds.contains(mapNe) && allowedBounds.contains(mapSw) ) {
        //the user is scrolling within the bounds.
        lastValidCenter = center;
        return;
    }

    //the user has scrolled beyond the Edge.

    var mapWidth = mapNe.lng() - mapSw.lng();
    var mapHeight = mapNe.lat() - mapSw.lat();

    var x = center.lng();
    var y = center.lat();

    var maxX = allowedBounds.getNorthEast().lng();
    var maxY = allowedBounds.getNorthEast().lat();
    var minX = allowedBounds.getSouthWest().lng();
    var minY = allowedBounds.getSouthWest().lat();

    //shift the min and max dimensions by 1/2 of the screen size, so the bounds remain at the Edge of the screen

    maxX -= (mapWidth / 2);
    minX += (mapWidth / 2);

    maxY -= (mapHeight / 2);
    minY += (mapHeight / 2);


    if (x < minX) {
        x = minX;
    }
    if (x > maxX) {
        x = maxX;
    }
    if (y < minY){
        y = minY;
    }
    if (y > maxY){
        y = maxY;
    }

    map.panTo(new google.maps.LatLng(y, x));

});
2
George Huber

モバイルとデスクトップで機能するシンプルなソリューションを次に示します。これにより、世界の最大または最小緯度を超えてマップのパンが停止し、最小ズームレベルを設定できるようになります。これにより、ズームが大きくなりすぎて灰色の領域が表示されるのを防ぐことができます(マップに設定したサイズによって異なります)。

(HenningJの承認済みの回答で提案されているcenter_changedイベントの使用には注意することをお勧めします。私の場合、これにより作成されるイベントの数がGoogle Chromeでスタックオーバーフローエラーを引き起こします。代わりに、 'dragend'イベントを使用できます-ただし、ユーザーがエリア外にドラッグすると、すぐにマップの有効なエリアに「スナップバック」します)。

var lastValidCenter;
var minZoomLevel = 2;

setOutOfBoundsListener();

function setOutOfBoundsListener() {
        google.maps.event.addListener(map, 'dragend', function () {
            checkLatitude(map);
        });
        google.maps.event.addListener(map, 'idle', function () {
            checkLatitude(map);
        });
        google.maps.event.addListener(map, 'zoom_changed', function () {
            checkLatitude(map);
        });
};

function checkLatitude(map) {
    if (this.minZoomLevel) {
        if (map.getZoom() < minZoomLevel) {
            map.setZoom(parseInt(minZoomLevel));
        }
    }

    var bounds = map.getBounds();
    var sLat = map.getBounds().getSouthWest().lat();
    var nLat = map.getBounds().getNorthEast().lat();
    if (sLat < -85 || nLat > 85) {
        //the map has gone beyone the world's max or min latitude - gray areas are visible
        //return to a valid position
        if (this.lastValidCenter) {
            map.setCenter(this.lastValidCenter);
        }
    }
    else {
        this.lastValidCenter = map.getCenter();
    }
}
1
Chris Halcrow

HenningJからの回答を試してみましたが、マップは、中心が境界の角にくるまでパンを停止しませんでしたが、これは理想的ではありませんでした。私の解決策は次のとおりです。

google.maps.event.addListener(map, 'center_changed', function() {
    var mapBounds = map.getBounds();
    if(allowedBounds.contains(mapBounds.getNorthEast()) && allowedBounds.contains(mapBounds.getSouthWest())) {
        lastCenter = map.getCenter();
        return;
    }

    map.panTo(lastCenter);
}, this));
1
Brandon Peters

件名には 別のスレッド があり、これも非常に優れています。解決しなければならなかった問題は、手動で境界を設定して中心の封じ込めを確認する代わりに、ページの読み込み時に境界を設定し、ズームインするとEdgeにドラッグできるようにすることでした。

そこで、一度マップの読み込み時にパン境界を設定しました。次に、マップがまだ最大ズームになっているかどうかを確認し、最大ズームになっている場合は、最初の中心を返します。ズームインした場合、CENTERが含まれているかどうかを確認するだけでなく、初期境界のエッジにパンします。これにより、許可されたパンがビューポートの半分だけ拡張されるためです。

残念ながら、これで仕事が完了し、ゆっくりパンしたときにうまく機能しますが、素早くパンすると少しぎくしゃくします。

これを回避する方法について提案があれば、感謝します。

    map = new google.maps.Map( // defaults
        document.getElementById("map22"),
        {
            disableDefaultUI        : true,
            zoomControl             : true,
            zoom                    : 7,
            minZoom                 : 7,
            maxZoom                 : 10,
            center                  : new google.maps.LatLng(
                64.99473104134819,
                -19.22332763671875
            ),
            mapTypeId               : google.maps.MapTypeId.ROADMAP
        }
    );



    function borders(){
        return {
            maxLat : map.getBounds().getNorthEast().lat(),
            maxLng : map.getBounds().getNorthEast().lng(),
            minLat : map.getBounds().getSouthWest().lat(),
            minLng : map.getBounds().getSouthWest().lng(),
            center : map.getCenter()
        }
    }

    google.maps.event.addListenerOnce(map,'idle',function() {
        limit = borders();
    });

    google.maps.event.addListener(map,'drag',function() {
        if(map.getZoom() == 7) return map.setCenter(limit.center);
        current = borders();
        if( current.maxLng < limit.maxLng && current.minLng > limit.minLng ) activeCenterLng = current.center.lng();
        if( current.maxLat < limit.maxLat && current.minLat > limit.minLat ) activeCenterLat = current.center.lat();
        map.setCenter(
            new google.maps.LatLng(
                activeCenterLat,
                activeCenterLng
            )
        );
    });
1
tim

ここに投稿された他のソリューションでは必要なものを達成できなかったため、誰かが興味を持っている場合に備えて、回答を投稿します。

私が必要としたのは、ユーザーが地球の緯度境界(〜+/- 85度)を超えてパンできないように、マップの垂直境界(緯度)を制限することでしたが、他の境界も機能します。

このアプローチでは、同じcenter_changedイベントは他の場所で説明されており、禁止された境界の一部が表示される場合にセンターを単に修正します。

このメカニズムは、マップの最小ズームが設定されている場合にのみ機能し、ズームアウトにより許可された範囲内の領域よりも多くの領域が表示されることはありません。

作業例: http://jsbin.com/vizihe

function initMap() {
  // sample bounds, can be anything and goes hand in hand with minZoom
  var northBoundary = 40
  var southBoundary = -40

  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 0, lng: 0},
    zoom: 4,
    // it's important to set this to a large enough value
    // so that zooming out does not show an area larger than allowed
    minZoom: 4 
  })

  map.addListener('center_changed', function () {
    var bounds = map.getBounds();
    var ne = bounds.getNorthEast()
    var sw = bounds.getSouthWest()
    var center = map.getCenter()

    if(ne.lat() > northBoundary) {
      map.setCenter({lat: center.lat() - (ne.lat() - northBoundary), lng: center.lng()})
    }

    if(sw.lat() < southBoundary) {
      map.setCenter({lat: center.lat() - (sw.lat() - southBoundary), lng: center.lng()})
    }   
  })
}
html, body, #map {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>
  <head>
<meta name="description" content="limit google map panning">
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
  </head>
  <body>
    <div id="map"></div>
    <script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
    async defer></script>
  </body>
</html>
0
Simone

Dragまたはdragendなどを使用している場合、オーバーフローする動きを制限するのではなく、マップが許可された境界に戻ります。イベントを「center_changed」に変更するだけで、そのようにジャンプするのを防ぎます。

変更されたjsfiddle: http://jsfiddle.net/Vjdde/1/

編集:フィドルがスタックオーバーフローを引き起こさない理由はわかりませんが、setCenterは再びcenter_changedを呼び出すため、そうする必要があります。

0
johanj

私はパーティーに少し遅れていることを知っていますが、middle 2016の時点で、可視エリアを制限する公式の方法はないようです。

境界を制限するいくつかの解決策があります(この質問ではそれらの一部)指定された境界。私のようなオーバーレイ画像に境界を制限したい場合、下に示すような動作が発生する可能性があります。この場合、オーバーレイマップは画像オーバーレイの下に表示されます。

enter image description here

この問題に取り組むために、オーバーレイをパンできないように境界を正常に制限する library を作成しました。

ただし、他の既存のソリューションと同様に、「振動」の問題があります。ユーザーがマウスの左ボタンを放した後、マップを積極的にパンすると、マップはそれ自体でパンを続け、徐々に遅くなります。私は常に地図を境界線に戻しますが、その結果、ある種の振動が生じ、しばらくすると落ち着きます。このパニング効果は、現時点ではJs APIが提供する手段では停止できません。 googleがmap.stopPanningAnimation()などのサポートを追加するまで、スムーズなエクスペリエンスを作成することはできないようです。

上記のライブラリを使用した例、私が得ることができた最もスムーズな厳密な境界体験:

function initialise(){
  
  var myOptions = {
     zoom: 5,
     center: new google.maps.LatLng(0,0),
     mapTypeId: google.maps.MapTypeId.ROADMAP,
  };
  var map = new google.maps.Map(document.getElementById('map'), myOptions);
  
  addStrictBoundsImage(map);
}

function addStrictBoundsImage(map){
        var bounds = new google.maps.LatLngBounds(
                new google.maps.LatLng(62.281819, -150.287132),
                new google.maps.LatLng(62.400471, -150.005608));

        var image_src = 'https://developers.google.com/maps/documentation/' +
                'javascript/examples/full/images/talkeetna.png';

        var strict_bounds_image = new StrictBoundsImage(bounds, image_src, map);
}
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
    google.load("maps", "3",{other_params:"sensor=false"});
</script>
<body style="margin:0px; padding:0px;" onload="initialise()">
         <div id="map" style="height:500px; width:1000px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>
0
Matej P.

ここでの解決策は、2つの問題を残しました。まず、矢印キーを押してすばやくパンを開始すると、エッジにヒットしたときにエッジに到達しません。パンの加速が大きな「ステップ」をとるため、次の「 「ステップ」は範囲外になっているので、その最後の「ステップ」は必要ありません。そのため、いったん停止したら、矢印キーを放してからもう一度押すと、もう少しパンします。第二に、これらのソリューションにはズーム変更後のパンが適切に含まれていませんでした。私は両方を解決し、ソリューションを投稿しました 別のスレッドで ですが、これが最初に正しい方向に着手したスレッドだったので、ここにリンクすると思いました。

0
qwertymodo

これはHenningJです。しかし、iosのHenningJはlastValidCentreを使用します。これは古くて良くないので、私はクランプします。

var mapObject = plugin_map.gmap3('get');
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(41.3957556, -88.4345472), 
     new google.maps.LatLng(49.4010417, -78.4286389)
);
google.maps.event.addListener(mapObject, 'center_changed', function() {
    if (allowedBounds.contains(mapObject.getCenter())) {
        // still within valid bounds, so save the last valid position
        return; 
    }

    // not valid anymore => return to last valid position
     var c = mapObject.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = allowedBounds.getNorthEast().lng(),
         maxY = allowedBounds.getNorthEast().lat(),
         minX = allowedBounds.getSouthWest().lng(),
         minY = allowedBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     //mapObject.setCenter(new google.maps.LatLng(y, x));
     mapObject.panTo(new google.maps.LatLng(y, x));
});
0
Tom Andersen