Search code examples
pythondjangodjango-viewsleafletfolium

How to dynamically generate optimal zoom on folium/leaflet?


I am using leaflet and folium to map out locations.

These locations can be filtered out and therefore requires something a bit dynamic.

I want to achieve two things:

  1. center the user on the map between the different locations (that works);
  2. Now I also want to regulate the zoom level to capture all the locations on the screen - sometime this zoom might be at street level, sometimes it might be at a country level.

I feel my problem can be solved by using fitBounds, which according to documentation automatically calculates the zoom to fit a rectangular area on the map.

That sounds ideal and this post here seems to be giving an answer about a similar question: pre-determine optimal level of zoom in folium

Slight problem, I just don't understand it.

I am thinking I should be able to use the min and max longitude and latitude to generate the rectangular area leaflet documentation refers to.

But how does that translate in the zoom levels provided by leaflet?

def function(request):
    markers = Model.objects.filter(location_active=True)

    #Max latitude & longitude
    min_latitude = Model.objects.filter(location_active=True).aggregate(Min('latitude'))['latitude__min']
    min_longitude = Model.objects.filter(location_active=True).aggregate(Min('longitude'))['longitude__min']

    #Min latitude & longitude
    max_latitude = Model.objects.filter(location_active=True).aggregate(Max('latitude'))['latitude__max']
    max_longitude = Model.objects.filter(location_active=True).aggregate(Max('longitude'))['longitude__max']

    sum_latitude = 0
    # sum latitude and longitude
    sum_latitude = max_latitude + min_latitude
    sum_longitude = max_longitude + min_longitude

    
    #average position for latitude and longitude
    average_latitude = sum_latitude/2
    print(f'average_latitude - {average_latitude} ')
    average_longitude = sum_longitude/2
    print(f'average_longitude - {average_longitude} ')

    center_location = [average_latitude,average_longitude]
    center_zoom_start= 12
    tiles_style = 'Stamen Terrain'
   
    
    #create Folium map
    m = folium.Map(location=center_location,zoom_start=center_zoom_start,tiles=tiles_style)
    m_access = folium.Map(location=center_location,zoom_start=center_zoom_start,tiles=tiles_style)

    context = {'markers':markers,'map_access':m_access._repr_html_,'map':m._repr_html_}
    
    return render(request,'template.html',context)

Solution

  • The answer was actually simple looking back.

    markers = Model.objects.filter(location_active=True)
    
    #Max latitude & longitude
    min_latitude = Model.objects.filter(location_active=True).aggregate(Min('latitude'))['latitude__min']
    min_longitude = Model.objects.filter(location_active=True).aggregate(Min('longitude'))['longitude__min']
    
    #Min latitude & longitude
    max_latitude = Model.objects.filter(location_active=True).aggregate(Max('latitude'))['latitude__max']
    max_longitude = Model.objects.filter(location_active=True).aggregate(Max('longitude'))['longitude__max']
    
    #average position for latitude and longitude
    average_latitude = sum_latitude/2
    print(f'average_latitude - {average_latitude} ')
    average_longitude = sum_longitude/2
    print(f'average_longitude - {average_longitude} ')
    
    center_location = [average_latitude,average_longitude]
    #center_zoom_start= 12
    tiles_style = 'Stamen Terrain'
    
    m = folium.Map(location=center_location,tiles=tiles_style) #<-- removed reference to zoom_start=center_zoom_start
    m.fit_bounds([[min_latitude, min_longitude], [max_latitude, max_longitude]]) #<-- added this bit. I did not knowwe could call m like that.
    m_access = folium.Map(location=center_location,tiles=tiles_style) #<-- removed reference to zoom_start=center_zoom_start