web-dev-qa-db-ja.com

Google Maps API 3のfitBoundsパディング-マーカーがオーバーレイされたコントロールによって隠れないようにします

map.fitBounds() を呼び出した後、マップビューにパディングを追加できるようにしたいので、マップコントロールやマーカーをカバーするスライドパネルなどに関係なく、すべてのマーカーを表示できます開いたとき。リーフレットには fitBoundsにパディングを追加するオプション がありますが、Googleマップにはありません。

最北のマーカーがビューポートの上に部分的に隠れていることがあります。多くの場合、最も西のマーカーはズームスライダーの下にあります。 API 2では、マップビューポートから指定されたパディングを減らして仮想ビューポートを形成し、メソッドshowBounds()を呼び出して、その仮想ビューポートに基づいてズームとセンタリングを計算および実行することができました。

map.showBounds(bounds, {top:30,right:10,left:50});

API 2のこれの実際の例は、showBounds()のサンプルリンクの下にあります here

API V3で同様の機能を見つけることはできませんが、できれば別の方法で実現できます。多分私は北東と南西のポイントをつかむことができ、それらを含めた後に境界をさらに拡張するために偽の座標を追加できますか?

更新

Codepen 以下のコードが機能しない場合)

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    draggable: true,
    streetViewControl: false,
    zoomControl: false
  });

  var marker1 = new google.maps.Marker({
    position: {lat: 37, lng: -121},
    map: map,
  });

  var marker2 = new google.maps.Marker({
    position: {lat: 39.3, lng: -122},
    map: map,
  });
 
  var bounds = new google.maps.LatLngBounds();
  bounds.extend(marker1.position);
  bounds.extend(marker2.position);
  map.fitBounds(bounds);
}
#map {
  height: 640px;
  width: 360px;
}
#overlays {
  position: absolute;
  height: 50px;
  width: 340px;
  background: white;
  margin: -80px 10px;
  text-align: center;
  line-height: 50px;
}
/* Optional: Makes the sample page fill the window. */
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Simple markers</title>

  </head>
  <body>
    <div id="map"></div>
    <div id="overlays">Controls / Order pizza / ETA / etc.</div>
  
    <script async defer
    src="https://maps.googleapis.com/maps/api/js?&callback=initMap">
    </script>
  </body>
</html>

問題はこれです:

enter image description here

カスタムコントロール に記載されているようにコントロールを追加しようとしましたが、マップはそれを正確に認識していません- このフィドルマップカスタムから分岐)を参照してください制御例 。マーカーの1つはまだコントロールによって覆い隠されています。

28
jsurf

これは一種のハックっぽい解決策ですが、fitBoundsの後で1レベルズームアウトして、マーカーに十分なパディングを取得できます。

map変数がマップオブジェクトへの参照であると想定します。

map.setZoom(map.getZoom() - 1);
23
keune

2017年6月の時点で、Maps JavaScript APIはfitBounds()メソッドのパディングパラメータをサポートしています。

fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)

詳細については、ドキュメントを参照してください

https://developers.google.com/maps/documentation/javascript/reference#Map

12
xomena

この問題を解決するには、マーカーをビューに十分に押し込んだ緯度を含むようにマップの境界を拡張しました。

まず、オーバーレイビューを作成する必要があります

var overlayHelper = new google.maps.OverlayView();
overlayHelper.onAdd = function() {};
overlayHelper.onRemove = function() {};
overlayHelper.draw = function() {};
overlayHelper.setMap(map);

オーバーレイヘルパーを取得したら、マップ投影を取得し、それに基づいて計算を実行する必要があります。

マップ上にあるコントロールは、マップの右端にある幅420ピクセル、高さ100%のdivであることに注意してください。コントロールを収容するためにコードを変更する必要があることは明らかです。

var mapCanvas = $("#map_canvas"),
    controlLeft = mapCanvas.width() - 420, // canvas width minus width of the overlayed control
    projection = overlayHelper.getProjection(),
    widestPoint = 0, 
    latlng, 
    point;

// the markers were created elsewhere and already extended the bounds on creation
map.fitBounds(mapBounds);

// check if any markers are hidden behind the overlayed control
for (var m in markers) {
    point = projection.fromLatLngToContainerPixel(markers[m].getPosition());
    if (point.x > controlLeft && point.x > widestPoint) {
        widestPoint = point.x;
    }
}

if (widestPoint > 0) {
    point = new google.maps.Point(
                mapCanvas.width() + (widestPoint - controlLeft), 
                mapCanvas.height() / 2); // middle of map height, since we only want to reposition bounds to the left and not up and down

    latlng = projection.fromContainerPixelToLatLng(point);
    mapBounds.extend(latlng);
    map.fitBounds(mapBounds);
}

マップを初めてロードするときにこれを行っている場合は、これをマップイベントにラップしてアイドルを待機する必要があります。これにより、オーバーレイビューを初期化できます。イベントコールバック内にオーバーレイヘルパーの作成を含めないでください。

google.maps.event.addListenerOnce(map, 'idle', function() { <above code> });
10
Seain Malkin

更新しました

Google Maps APIは fitBounds メソッドでネイティブの「パディング」パラメータをサポートするようになりました(バージョン3.32以降、以前の場合は修正してください)。

まだテストする機会はありませんでしたが、アップグレードできる場合は、ネイティブの方法を使用することをお勧めします。バージョン3.32未満を使用していてアップグレードできない場合-私の解決策はあなたのためです。


私は working solutionerzzo で取り、少し改善しました。

fitBoundsWithPadding(googleMapInstance, PolygonLatLngBounds, {left:250, bottom:10});

引数の説明:

  1. gMap-Googleマップインスタンス
  2. bounds-GoogleはLatLngBoundsオブジェクトをフィットするようにマッピングします
  3. paddingXY-オブジェクトリテラル:2つの可能な形式:
    • {x、y}-水平および垂直パディング用(x = left = right、y = top = bottom)
    • {左、右、上、下}

コピーする関数リスト

function fitBoundsWithPadding(gMap, bounds, paddingXY) {
        var projection = gMap.getProjection();
        if (projection) {
            if (!$.isPlainObject(paddingXY))
                paddingXY = {x: 0, y: 0};

            var paddings = {
                top: 0,
                right: 0,
                bottom: 0,
                left: 0
            };

            if (paddingXY.left){
                paddings.left = paddingXY.left;
            } else if (paddingXY.x) {
                paddings.left = paddingXY.x;
                paddings.right = paddingXY.x;
            }

            if (paddingXY.right){
                paddings.right = paddingXY.right;
            }

            if (paddingXY.top){
                paddings.top = paddingXY.top;
            } else if (paddingXY.y) {
                paddings.top = paddingXY.y;
                paddings.bottom = paddingXY.y;
            }

            if (paddingXY.bottom){
                paddings.bottom = paddingXY.bottom;
            }

            // copying the bounds object, since we will extend it
            bounds = new google.maps.LatLngBounds(bounds.getSouthWest(), bounds.getNorthEast());

            // SW
            var point1 = projection.fromLatLngToPoint(bounds.getSouthWest());


            // we must call fitBounds 2 times - first is necessary to set up a projection with initial (actual) bounds
            // and then calculate new bounds by adding our pixel-sized paddings to the resulting viewport
            gMap.fitBounds(bounds);

            var point2 = new google.maps.Point(
                ( (typeof(paddings.left) == 'number' ? paddings.left : 0) / Math.pow(2, gMap.getZoom()) ) || 0,
                ( (typeof(paddings.bottom) == 'number' ? paddings.bottom : 0) / Math.pow(2, gMap.getZoom()) ) || 0
            );

            var newPoint = projection.fromPointToLatLng(new google.maps.Point(
                point1.x - point2.x,
                point1.y + point2.y
            ));

            bounds.extend(newPoint);

            // NE
            point1 = projection.fromLatLngToPoint(bounds.getNorthEast());
            point2 = new google.maps.Point(
                ( (typeof(paddings.right) == 'number' ? paddings.right : 0) / Math.pow(2, gMap.getZoom()) ) || 0,
                ( (typeof(paddings.top) == 'number' ? paddings.top : 0) / Math.pow(2, gMap.getZoom()) ) || 0
            );
            newPoint = projection.fromPointToLatLng(new google.maps.Point(
                point1.x + point2.x,
                point1.y - point2.y
            ));

            bounds.extend(newPoint);

            gMap.fitBounds(bounds);
        }
    }
8
Roman86

map.fitBounds()で言及したのと同じパディング構文を使用して、API V3でmap.showBounds()を使用できます。

map.fitBounds(bounds, {top:30,right:10,left:50});を使用するだけでうまくいきました。

(これはxomenaまたはRoman86の投稿へのコメントの可能性があります。コメントするのに十分な評判がありません)

4
Milan Švehla

この問題のより一般的な解決策を提供します。ポジションがある場合marker.getPosition()、この関数を使用して_(x, y)_ピクセル離れた別の位置を見つけることができます。

_function extendedLocation(position, x, y) {
    var projection = map.getProjection();
    var newMarkerX = projection.fromLatLngToPoint(position).x + x/(Math.pow(2, map.getZoom()))
    var newMarkerY = projection.fromLatLngToPoint(position).y + y/(Math.pow(2, map.getZoom()))
    var newMarkerPoint = new google.maps.Point(newMarkerX, newMarkerY);
    return projection.fromPointToLatLng(newMarkerPoint)
}
_

注:正のxは右方向、正のyは下方向です。したがって、一般的には、マーカーを表示するには、yの負の値を渡す必要があります。 extendedLocation(marker.getPosition(), 4, -18)

想定される高さの上部に永続的なスライダーまたはそのような要素がある場合は、関数でyパラメーターを_-30_として使用します。

4ポイントの配列を返す、より一般化された関数を作成できます。各ポイントは、指定された上、下、右、左の方向から_(x, y)_ピクセル離れています。

_function getAllExtendedPosition(position, x, y){
   var positionArray = [];
   postitionArray.Push(extendedLocation(position, x, y);
   postitionArray.Push(extendedLocation(position, -x, -y);
   postitionArray.Push(extendedLocation(position, -x, y);
   postitionArray.Push(extendedLocation(position, x, -y);
   return positionArray
}
_
1