24

I currently have a 3 tabbed page. Each tab is a div that is set to display: hidden when not selected. In these tabs I have a Grid system created with Susy (compass plugin). Also each tab page has a set of Highcharts. When I load the page, depending on which tab is in the URl, one of the tabs is loaded. All of the charts look fine, however when I switch to a different tab, some of the charts are not fitting correctly in their div. If I just re-size the window, the charts are recalculated and then they fit perfectly. Or if I reload that same tab, the charts fit fine too. Can I call a function that will resize all the charts on the page when I make my tab switch?

It looks like this: How it looks

when it should look like this: How it should look

EDIT: Seems like this isn't a problem directly related to highcharts, for example my google maps looks like this: How Google Maps looks

but when I resize the window it adjusts correctly: How Google Maps looks after resize

Can I make CSS refresh/adjust my grids through a function call in JS when the tab gets switched?

1
  • It's really hard to know without seeing more code, but I would guess that something is setting "width" and "height" directly on the charts - probably highcharts JS. On option is for JS to change those values - but you should be able to override the width setting with max-width: 100% - as you might with images in a responsive grid. Commented Apr 25, 2013 at 17:03

3 Answers 3

46

What worked for me is calling:

$(window).resize();

When I load a new tab. Still having the issues with the Google Maps API, but it works great with Highcharts.

4
  • 3
    To save someone a couple of minutes here is the full snippet for jQuery UI / Tabs and the Highcharts-Width-Problem. $(function () { $("#tabs").tabs( { activate: function () { $(window).resize(); } }); });
    – konrad_pe
    Commented Jul 15, 2014 at 10:28
  • 2
    window.dispatchEvent(new Event('resize')) is less jQuery code
    – Developia
    Commented Apr 11, 2015 at 7:31
  • new Event('resize') is elegant, but unfortunately unsupported by IE. For cross-browser support use var evt = document.createEvent("HTMLEvents"); evt.initEvent("resize", false, true); window.dispatchEvent(evt);
    – pmont
    Commented Oct 22, 2015 at 18:56
  • google.maps.event.trigger(MapObject, 'resize');, call this when moving to tab with Google Maps will fix the Google Map issue. var MapObject = new google.maps.Map(document.getElementById('#myMap'), { }); Commented Nov 25, 2015 at 8:30
6

You will find a lot of issues when you are trying to render things that start off using "display: none". While $(window).resize() might work in many cases, I would suggest trying to first render your page before having display: none take effect. A possible solution would be to set opacity: 0 or visibility: hidden.

The display attribute is what controls how your element will render, for instance block (100% width) or inline (fit contents). When an element has display: none, it overrides this, ultimately removing it's effective width and height until that element receives a block type.

Here is a example to demonstrate: http://jsfiddle.net/m2f3scmm/3/

<div id="log1" style="display: none;">
</div>
<div id="log2" style="visibility: hidden;">
</div>
<div id="log3" style="opacity: 0">
</div>

When you are using the "resize" hack, you are assuming the plugin or script you are using is binding to the window's resize event which is not always the case. Triggering the window.resize could also slow down rendering or cause unwanted effects (for instance, the little animation highcharts does when first rendering - which looks lame when it happens each time a tab is changed).

3
/**
 * Adjust size for hidden charts
 * @param chart highcharts
 */
function adjustGraph(chart) {
    try {
        if (typeof (chart === 'undefined' || chart === null) && this instanceof jQuery) { // if no obj chart and the context is set
            this.find('.chart-container:visible').each(function () { // for only visible charts container in the curent context
                $container = $(this); // context container
                $container.find('div[id^="chart-"]').each(function () { // for only chart
                    $chart = $(this).highcharts(); // cast from JQuery to highcharts obj
                    $chart.setSize($container.width(), $chart.chartHeight, doAnimation = true); // adjust chart size with animation transition
                });
            });
        } else {
            chart.setSize($('.chart-container:visible').width(), chart.chartHeight, doAnimation = true); // if chart is set, adjust
        }
    }
    catch (err) {
        // do nothing
    }
}

usage

$(window).resize(function () {
        if (this.resizeTO) clearTimeout(this.resizeTO);
        this.resizeTO = setTimeout(function () {
            // resizeEnd call function with pass context body
            adjustGraph.call($('body'));

        }, 500);
    });

for bootstrap tab

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
            var isChart = $(this).attr('data-chart');
            var target = $(this).attr('href');
            if (isChart) {
                // call functio inside context target
                adjustGraph.call($(target));
            }
        });



  <ul id="tabs" class="nav nav-tabs" data-tabs="tabs">
        <li class="active">
            <a href="#anagrafica" data-toggle="tab"><h5>Anagrafica</h5></a>
        </li>
        <li>
            <a href="#consumi" data-toggle="tab" data-chart="1"><h5>Consumi</h5></a>
        </li>
    </ul>

on chart

new Highcharts.Chart({
            chart: {
                renderTo: 'chart-bar',
                defaultSeriesType: 'column',
                zoomType: 'xy',
                backgroundColor: null,
                events: {
                    load: function (event) {
                        adjustGraph(this);
                    }
                }
            },

html code

div class="tab-pane" id="charts">
    <div class="row-fluid">
        <div class="span6 offset3">
            <div id="myCarousel" class="carousel slide">
                <!-- Carousel items -->
                <div class="carousel-inner chart-container">
                    <div class="active item">
                        <h3>Chart 1/h3>
                        <div id="bar-pod-annuale">
                           <div id="chart-bar" style="width:100%;margin: 0 auto"></div>
                        </div>
                    </div>
                    <div class="item">
                        <h3>Char 2</h3>
                        /** chart **/
                    </div>
                    <div class="item">
                        <h3>Char 3</h3>
                        /** chart **/
                    </div>
                </div>
                <!-- Carousel nav -->
                <a class="carousel-control left" href="#myCarousel" data-slide="prev">‹</a>
                <a class="carousel-control right" href="#myCarousel" data-slide="next">›</a>
            </div>
        </div>
    </div>

See on jsfiddle http://jsfiddle.net/davide_vallicella/LuxFd/2/

Not the answer you're looking for? Browse other questions tagged or ask your own question.