RailsでGoogle mapsを使いこなすためのメモ 5 / すでに存在するピンは再度取得しないようにする
ユーザーが地図を操作した時に、すでに地図上に存在しているお店の情報まで再度取得して、ピンまで落としてしまうという問題を解消する処理を考えます。
RailsでGoogle mapsを使いこなすためのメモ
どのお店がすでに地図上に存在するのか知る必要があるので、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)を付け加えて、既に存在するお店を除外しています。
これで、地図を動かしても同じピンが落ちることがなくなりました。
やったねー。
このシリーズもここでいったん完結かな?
参考
ActionController::LiveとServer-Sent Events で地図上にじわじわ表示する
Google Maps入門(Google Maps JavaScript API V3)
Flea Markets Neukölln, Berlin, Germany (地図を使うサイトの例)