RailsでGoogle mapsを使いこなすためのメモ 5 / すでに存在するピンは再度取得しないようにする

Shunsuke Sawada

ユーザーが地図を操作した時に、すでに地図上に存在しているお店の情報まで再度取得して、ピンまで落としてしまうという問題を解消する処理を考えます。

  
RailsでGoogle mapsを使いこなすためのメモ

  1. 地図(現在位置を中心とした地図)を表示

  2. 地図デザインのカスタマイズ

  3. 表示範囲に含まれる情報をDBから取り出す

  4. 取り出したデータを使って地図にピンを落とす

  5. すでに存在するピンは再度取得しないようにする 今ココ

どのお店がすでに地図上に存在するのか知る必要があるので、map_canvasのdivにdata属性を持たせることにしました。

div id="map_canvas" data-shop-ids=""

という感じ。最初は何もないので、空ということで””としています。

marker.js.erbに下記のように変更します。

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var existing_ids = $('#map_canvas').attr('data-shop-ids');
if (existing_ids == '' || typeof(existing_ids) == "undefined") {
    shop_ids = [];
} else {
    shop_ids = existing_ids.split(',');
}

<% @locations.each do |location| %>

    // marker
    var marker_<%= location.id %> = new google.maps.Marker({
        position: new google.maps.LatLng(<%= location.latitude %>, <%= location.longitude %>),
        draggable: false,
        map: map_canvas,
        animation: google.maps.Animation.DROP
        });

    // Add id if it's new
    if ($.inArray("<%= location.id %>", place_ids) == -1) {
        place_ids.push("<%= location.id %>");
    }

<% end %>

// Update existing ids
$('#map_canvas').attr({'data-place-ids': place_ids});

一番上のところでは、すでにお店が存在していれば、shop_idsにそのidを代入して、なにも無ければ、空の配列をセットしています。

// Add id if it's new では、eachの中で処理中のお店のidが、shop_idsの中になければ追加していきます。
最終的にshop_idsは[1, 2, 4, 5, 19, 33]のような配列になっていて、コントローラでこれらのidをはじけばいいということです。

// Update existing ids で、divのdata属性を更新するのを忘れずに。再度ユーザーが地図を動かした時に処理に使われます。

google_maps.coffee.erbを変更する

data-shop-idsが更新されるので、それを取得して、コントローラに渡さなければいけません。最初やったようにGETパラメータに追加しました。

google_maps.coffee.erb

coffee
1
2
3
4
5
6
7
8
9
10
11
12
google.maps.event.addListener(map_canvas, 'idle', ->
    # shop-idsを取得
    shop_ids = $('#map_canvas').attr('data-place-ids')
    # 表示範囲を取得
    pos = map_canvas.getBounds()
    north = pos.getNorthEast().lat()
    south = pos.getSouthWest().lat()
    east    = pos.getNorthEast().lng()
    west = pos.getSouthWest().lng()
    # コントローラーに値をGETパラメータで渡す
    $.getScript("/shops/marker?&north=#{north}&south=#{south}&east=#{east}&west=#{west}&shop_ids=#{shop_ids}")
)

&shop_ids=#{shop_ids}をURLの最後に追加しています。

ShopsControllerを変更する

whereでshop_idsに該当するものを取り除きましょう。

shops_controller.rb

ruby
1
2
3
4
5
6
7
8
9
10
11
def marker
    #GETで渡ってきたidを配列にする
    shop_ids = params["shop_ids"].to_s.split(',').sort
    # 北から南、東から西の範囲をつくる
    lat = Range.new(*[params["north"], params["south"]].sort)
    lon = Range.new(*[params["east"], params["west"]].sort)
    # データ取得
    @locations = Shop.where(latitude: lat, longitude: lon).where.not(id: shop_ids)
end

.where.not(id: shop_ids)を付け加えて、既に存在するお店を除外しています。

Screen Shot 2014-01-12 at 10.56.48 AM

これで、地図を動かしても同じピンが落ちることがなくなりました。
やったねー。

このシリーズもここでいったん完結かな?

参考

ActionController::LiveとServer-Sent Events で地図上にじわじわ表示する

Google Maps入門(Google Maps JavaScript API V3)

Flea Markets Neukölln, Berlin, Germany (地図を使うサイトの例)

Google Maps API デモ ギャラリー

現在表示されている範囲内のマーカーだけ表示する[GoogleMapsAPIVersion3]+[PHP]

Googleマップをイラストマップみたいにしたい。

Add Markers to a Google Map With Ruby on Rails and JSON

5
Shunsuke Sawada

おすすめの記事

acts-as-taggable-on タグを表示させる順番を決めたい
Railsを4.2にバージョンアップしたら、Vagrantのローカル開発環境にアクセスできなくなった問題
Railsのバリデーションエラー後にレイアウトが崩れるとき