KonifarPod

GoogleMapAPI V3で中心位置をピクセル単位で指定する方法

   

Pocket

GoogleMapAPI V3を使うと指定したDOM要素にGoogleMapを表示することができますが、中心位置は必ずDOM要素の真ん中に指定されてしまいます。

例えばPlanettのようにピンを中心より上に表示するようなUIを実現したい時に、中心位置をちょっとずらして指定したいナァ、できればピクセル指定で指定したいナァなんて思うわけです。

Googlemap1

 

いや、もちろん表示する部分だけにピッタリGoogleMapを表示するようにすればいいんですがね。。GoogleMapの表示部分を画面全体に広げる場合にGoogleMapの再読み込みが走るので、画面がチラついてしまうんですよね。特にスマホ環境で。少しでもぬるぬる動かすために最初からマップを画面全体に表示しつつピン位置だけ中心からずらしたかった、というわけです。

 

1)実装方法

GoogleMapAPIを拡張して、panToWithOffset()というAPIを追加します。

 もともとpanTo()という緯度経度を指定して中心位置を移動するメソッドは用意されているので、それにoffsetを指定できるようにするというわけです。一応下記のコードで動くはず。(CoffeeScriptで確認済み)

[JavaScriptの場合]

// 上から120px
var marker_top = 120;

setUpGoogleMap = function() {
  var $el = $('#mapDiv');
  // 中心位置のpxを計算
  var center_offset = $el.height()/2-marker_top;
  google.maps.Map.prototype.panToWithOffset = function(latlng, offset_x, offset_y) {
    var map = this;
    // デフォルトのoffsetを指定
    var offset_x ||= 0;
    var offset_y ||= center_offset;
    var overlay = new google.maps.OverlayView();
    overlay.onAdd = function() {
      // pxと緯度経度を変換するため、GoogleMapのprojectionを利用する
      var projection = this.getProjection();
      var point = projection.fromLatLngToContainerPixel(latlng);
      point.x = point.x + offset_x;
      point.y = point.y + offset_y;
      map.panTo(projection.fromContainerPixelToLatLng(point));
    }
    overlay.draw = function() {
      // オーバーライドだけしておく必要がある
    }
    overlay.setMap(this);
  }
}

 

[CoffeeScriptの場合]

marker_top = 120

setUpGoogleMap = =>
  @$el = $ '#mapDiv'
  center_offset = @$el.height()/2-marker_top
  google.maps.Map.prototype.panToWithOffset = (latlng, offset_x, offset_y)->
    map = @
    offset_x ||= 0
    offset_y ||= center_offset
    overlay = new google.maps.OverlayView()
    overlay.onAdd = -> 
      projection = @getProjection()
      point = projection.fromLatLngToContainerPixel latlng
      point.x = point.x + offset_x
      point.y = point.y + offset_y
      map.panTo(projection.fromContainerPixelToLatLng point)
      overlay.draw = ->
    overlay.setMap @

 

2)利用方法

new google.maps.Map()でマップを初期化する前に 上記で用意したsetUpGoogleMap()を呼び出すだけです。そうするとmap.panToOffset()が使えるようになるので、マップを移動させる時に呼び出してください。引数でoffsetを指定しない場合はmarker_topで指定したピクセル位置に中心位置になります。

※ マップのDOM要素は、画面全体に表示されるようにCSSをかけるようにしておいてください。

#mapDiv {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
}

 

なんだかGoogleMapAPI V3は、かゆいところに手が届かない感じなんですよね。スムーズに横移動するpanTo()メソッドも移動時間をms単位で指定できるようにしてほしいし、setZoom()でズームレベルを変更するときも、スムーズにズームするようにdurationを指定できるようにしてほしい。。。

まあこのあたりはV2同様、だんだんと進化していくのでしょう、と信じてみる。

Pocket

 - Develop ,