[GIS] OpenLayers dynamic map width inside Bootstrap tabs

bootstrap-frameworkgeodjangoopenlayers-2

I have the following layout, produced with Django and Bootsrap frameworks: some tabs with inside each one of them other 3 sub-tabs.
In every first sub-tab I have an OpenLayers-2.13 map.
This is what I've produced so far:

  • onload.js

    $(document).ready(function(){
        $('a[data-toggle="tab"]').on('shown', function (e) {
            e.target // activated tab
            e.relatedTarget // previous tab
        })
    
        // Show shapefile tabs
        $('#shape-tabs-links a:first').tab('show');
    
        // Put css modifications here, otherwise OpenLayers complains that about map div size is missing
        $('.map').css('width', '100%');
        $('.map').css('height', '50%');
    
        $(window).resize(function() {
            var w = $('.map').width();
            $('.map').css('height', w*3/6);
        });
    
        // Stuff to do per tab
        $('.shapes').each(function() {
            shpId = $(this).val();
            // Show view, cods and info subtabs
            $('#per-shape-tabs-links-'+shpId+' a:first').tab('show');
            renderMaps(shpId); // Map render function defined in anothe js file
        });
    });
    
  • style.css

    .map{background-color:#fff}
    
  • page.html

    <ul id="shape-tabs-links" class="nav nav-pills">
    {% for shape in shape_list %}
        <li><a href="#tabs-{{ shape.id }}" data-toggle="tab">{{ shape.name }}</a></li>
    {% endfor %}
    </ul>
    <div id="shape-tabs" class="tab-content"><!-- First level tabs -->
    {% for shape in shape_list %}
        <div id="tabs-{{ shape.id }}" class="tab-pane">
            <ul id="per-shape-tabs-links-{{ shape.id }}" class="nav nav-tabs">
                <li><a href="#tabs-view-{{ shape.id }}" data-toggle="tab">Data Visualization</a></li>
                <li><a href="#tabs-cods-{{ shape.id }}" data-toggle="tab">CODs Management</a></li>
                <li><a href="#tabs-info-{{ shape.id }}" data-toggle="tab">Shapefile Info</a></li>
            </ul>
    
            <div id="per-shape-tabs" class="tab-content"><!-- Second level tabs -->
                <div id="tabs-view-{{ shape.id }}" class="tab-pane"><!-- subtab 1 -->
                    <div class="row-fluid">
                        <div class="span4"></div>
                        <div class="span8 well well-small">
                            <div id="view-map-{{ shape.id }}" class="span8 map"></div>
                        </div>
                    </div>   
                </div><!-- subtab 1 -->
    
                <div id="tabs-cods-{{ shape.id }}" class="tab-pane"><!-- subtab 2 -->
                    <div class="row-fluid">
                        <div class="span12"></div>
                    </div>
                </div><!-- subtab 2 -->
    
                <div id="tabs-info-{{ shape.id }}" class="tab-pane"><!-- subtab 3 -->
                    <div class="row-fluid">
                        <div class="span12"></div>
                    </div>
                </div><!-- subtab 3 -->
            </div>
        </div>
    {% endfor %}
    </div>
    

I've put css modifications inside onload.js and not inside style.css because OpenLayers complained that my div was without dimensions.
Probably a that is a matter of library loading order, but I've tried several combinations and the better one is the one in this code.

What I get loading the page it is a map div with the correct width, but with an height of few pixels in a way that the map is not visible.
If I resize my window everything get right and I can visualize my map correctly.
But if I refresh the page, I get the bad visualization described above.

On top of onload.js I've inserted the event function described in Bootstrap docs: maybe I have to render map when I'm sure that every tab component is [properly loaded, but I do not exactly how to use it and if this is the a possible solution.

Any ideas on how to solve this problem?

Thanks in advance.

EDIT here you are a simplified, working example of my issue: http://jsfiddle.net/ZrazJ/14/

Best Answer

What have you tried and failed to have work? I usually simply set the #map div (or in the case of that above example, a class) to match a CSS rule:

#map {
   width: 100%;
}

That should make it fill out the container. You might need to explicitly set height as well. I often do this with jQuery so that my map is never too far out of a certain aspect ratio. Something like:

$(window).resize(function() {
    var w = $("#map").width();
    $("#map").css("height", w*3/4);
}

This should work to create a map with dynamic width that doesn't look horrible if the window is resized.