# encoding: utf-8
#
# = Google Maps Helpers
#
# make_map:: Create a GMap.
# finish_map:: Render the actual HTML needed for the given GMap.
#
# == Typical Usage
#
# <%=
# gmap = make_map(@locations)
# # (can tweak gmap here)
# finish_map(gmap)
# gmap.div(:width => 400, :height => 400)
# %>
#
##############################################################################
require_dependency 'map_collapsible'
require_dependency 'map_set'
module ApplicationHelper::Map
def make_map(objects, args={})
args = provide_defaults(args,
:map_div => 'map_div',
:controls => [ :large_map, :map_type ],
:info_window => true
)
collection = CollapsibleCollectionOfMappableObjects.new(objects)
gmap = init_map(args)
if args[:zoom]
gmap.center_zoom_init(collection.extents.center, args[:zoom])
else
gmap.center_zoom_on_points_init(*collection.representative_points)
end
for mapset in collection.mapsets
draw_mapset(gmap, mapset, args)
end
return gmap
end
def make_editable_map(object, args={})
args = provide_defaults(args,
:editable => true,
:info_window => false
)
gmap = make_map(object, args)
gmap.event_init(gmap, 'click', 'function(overlay, latlng) {
clickLatLng(latlng);
}')
gmap.event_init(gmap, 'dblclick', 'function(overlay, latlng) {
dblClickLatLng(latlng);
}')
return gmap
end
def make_thumbnail_map(objects, args={})
args = provide_defaults(args,
:controls => [ :small_map ],
:info_window => true,
:zoom => 2
)
return make_map(objects, args)
end
def provide_defaults(args, default_args)
default_args.merge(args)
end
def init_map(args={})
gmap = GMap.new(args[:map_div])
gmap.control_init(args[:controls].to_boolean_hash)
return gmap
end
def finish_map(gmap)
ensure_global_header_is_added
html = gmap.to_html(:no_script_tag => 1)
js = javascript_tag(html)
add_header(js)
end
def ensure_global_header_is_added
if !@done_gmap_header_yet
add_header(GMap.header(:host => DOMAIN))
@done_gmap_header_yet = true
end
end
def draw_mapset(gmap, set, args={})
title = mapset_marker_title(set)
marker = GMarker.new(set.center,
:draggable => args[:editable],
:title => title
)
if args[:info_window]
marker.info_window = mapset_info_window(set, args)
end
if args[:editable]
map_control_init(gmap, marker, args)
map_box_control_init(gmap, set, args) if set.is_box?
else
gmap.overlay_init(marker)
end
if set.is_box?
draw_box_on_gmap(gmap, set, args)
end
end
def draw_box_on_gmap(gmap, set, args)
box = GPolyline.new([
set.north_west,
set.north_east,
set.south_east,
set.south_west,
set.north_west,
], "#00ff88", 3, 1.0)
if args[:editable]
box_name = args[:box_name] || 'mo_box'
gmap.overlay_global_init(box, box_name)
else
gmap.overlay_init(box)
end
end
def mapset_marker_title(set)
result = ''
strings = map_location_strings(set.objects)
if strings.length > 1
result = "#{strings.length} #{:locations.t}"
else
result = strings.first
end
num_obs = set.observations.length
if num_obs > 1 and num_obs != strings.length
num_str = "#{num_obs} #{:observations.t}"
if strings.length > 1
result += ", #{num_str}"
else
result += " (#{num_str})"
end
end
return result
end
def map_location_strings(objects)
objects.map do |obj|
if obj.is_a?(Location)
obj.display_name
elsif obj.is_a?(Observation)
if obj.location
obj.location.display_name
elsif obj.lat
"#{format_latitude(obj.lat)} #{format_longitude(obj.long)}"
end
end
end.reject(&:blank?).uniq
end
def mapset_info_window(set, args)
lines = []
observations = set.observations
locations = set.underlying_locations
lines << mapset_observation_header(observations, args) if observations.length > 1
lines << mapset_location_header(locations, args) if locations.length > 1
lines << mapset_observation_link(observations.first, args) if observations.length == 1
lines << mapset_location_link(locations.first, args) if locations.length == 1
lines << mapset_coords(set)
return lines.join('
')
end
def mapset_observation_header(observations, args)
query = Query.lookup(:Observation, :in_set, :ids => observations.map(&:id))
show = link_to(:show_all.t, :controller => :observer, :action => :index_observation,
:params => query_params(query))
map = link_to(:map_all.t, :controller => :observer, :action => :map_observations,
:params => query_params(query))
return "#{:Observations.t}: #{observations.length} (#{show} | #{map})"
end
def mapset_location_header(locations, args)
query = Query.lookup(:Location, :in_set, :ids => locations.map(&:id))
show = link_to(:show_all.t, :controller => :location, :action => :index_location,
:params => query_params(query))
map = link_to(:map_all.t, :controller => :location, :action => :map_locations,
:params => query_params(query))
return "#{:Locations.t}: #{locations.length} (#{show} | #{map})"
end
def mapset_observation_link(obs, args)
link_to(obs.unique_format_name.t, :controller => :observer, :action => :show_observation,
:id => obs.id, :params => args[:query_params] || {})
end
def mapset_location_link(loc, args)
link_to(loc.display_name.t, :controller => :location, :action => :show_location,
:id => loc.id, :params => args[:query_params] || {})
end
def mapset_coords(set)
if set.is_point?
"#{format_latitude(set.lat)} #{format_longitude(set.long)}"
else
content_tag(:center,
"#{format_latitude(set.north)}
" +
"#{format_longitude(set.west)} #{format_longitude(set.east)}
" +
"#{format_latitude(set.south)}"
)
end
end
def format_latitude(val)
format_lxxxitude(val, 'N', 'S')
end
def format_longitude(val)
format_lxxxitude(val, 'E', 'W')
end
def format_lxxxitude(val, dir1, dir2)
deg = val.abs.round(4)
return "#{deg}°#{val < 0 ? dir2 : dir1}"
# sec = (val.abs * 3600).round
# min = (sec / 60.0).truncate
# deg = (min / 60.0).truncate
# sec -= min * 60
# min -= deg * 60
# return "#{deg}°#{min}′#{sec}″#{val < 0 ? dir2 : dir1}"
end
def map_control_init(gmap, marker, args, type='ct')
name = args[:marker_name] || 'mo_marker'
gmap.overlay_global_init(marker, name + '_' + type)
gmap.event_init(marker, 'dragend', "function(latlng) {
dragEndLatLng(latlng, '#{type}')
}")
end
def map_box_control_init(gmap, set, args)
for point, type in [
[set.north_west, 'nw'],
[set.north_east, 'ne'],
[set.south_west, 'sw'],
[set.south_east, 'se'],
]
marker = GMarker.new(point, :draggable => true)
map_control_init(gmap, marker, args, type)
end
end
# Center on a given location? (This is never used: -JPH 20120510)
# if respond_to?(:start_lat) && respond_to?(:start_long)
# gmap.center_zoom_init( [start_lat, start_long], Constants::GM_ZOOM )
# gmap.overlay_init(
# GMarker.new( [start_lat, start_long],
# :icon => icon_start,
# :title => name + " start",
# :info_window => "start"
# ))
# end
# Started playing with icons and the following got something to show up,
# but I decide not to pursue it further right now.
# gmap.icon_global_init(
# GIcon.new(
# :image => "/images/blue-dot.png",
# :icon_size => GSize.new( 24,38 ),
# :icon_anchor => GPoint.new(12,38),
# :info_window_anchor => GPoint.new(9,2)
# ), "blue_dot")
# blue_dot = Variable.new("blue_dot")
end