Search code examples
ruby-on-railsrubyruby-on-rails-3google-mapsgmaps4rails

Dynamically load Google Maps Markers with gmaps4rails


How do I load only markers that are inside the map bounds with gmaps4rails? And of course load new ones after pan and/or zoom.

Directly related to that, how can I get the current boundaries and zoomlevel of the map?


Solution

  • Here is how I did it, I only replace the markers after the user finishes panning or zooming, if you require different behavior then use a different event listener:

    In your view (index.html.erb):

    <%= gmaps({ "map_options" => { "zoom" => 15, 
                                   "auto_adjust" => false, 
                                   "detect_location" => true, 
                                   "center_on_user" => true }}, false, true) %>
    

    At the bottom of your view add:

    <script type="text/javascript" charset="utf-8">
    
    function gmaps4rails_callback() {
        google.maps.event.addListener(Gmaps4Rails.map, 'idle', function () {
            var bounds = Gmaps4Rails.map.getBounds();
            drawItems(bounds);
        });
    }
    
    </script>
    

    In application.js (using jQuery):

    function drawItems(theBounds) {
        var url = '/venues.json/?sw_y=' + theBounds.getSouthWest().lng() + 
                               '&sw_x=' + theBounds.getSouthWest().lat() + 
                               '&ne_y=' + theBounds.getNorthEast().lng() +
                               '&ne_x=' + theBounds.getNorthEast().lat();
        $.get(url, function(newItemData) {
            Gmaps4Rails.replace_markers(newItemData);
        });
    }
    

    venues_controller#index:

    def index
        # Only pull venues within the visible bounds of the map
        if (params[:sw_y] && params[:sw_x] && params[:ne_y] && params[:ne_x])
            bounds = [ [params[:sw_x].to_f, params[:sw_y].to_f], 
                     [params[:ne_x].to_f, params[:ne_y].to_f] ]
            @venues_within_bounds = Venue.within_bounds(bounds)
        else
            @venues_within_bounds = Venue.all
        end   
    
        respond_to do |format|
            format.html # index.html.erb
            format.json { 
                @data = @venues_within_bounds.collect {|v| {
                         :longitude => v.longitude, 
                         :latitude => v.latitude, 
                         :picture => v.marker_picture, 
                         :title => v.marker_title 
                }
                render :json => @data
            }
        end
    end
    

    Venue.rb model (using mongodb and mongoid):

    def self.within_bounds(bounds)
        self.where(:location.within => {"$box" => bounds })
    end