Morris.js charts in Bootstrap tabs
Morris.js is a javascript graph library based on the very competent raphael.js, I've come to include them in many projects lately because they are really dead simple to implement and they now, in the master branch, support the ability to natively resize with the page, in other words they are responsive, which is largely in demand right now.
Now can they be implemented in content that switches between display: block; and display: none; like bootstrap's tabs?
I've been working on a prototype for one of my clients who has the need to display data to their users in graphical form. It is easier to digest data in graphical form, easier to spot anomalies etc etc...
One setback with using graphical elements is that they tend to take up a lot of space. Which makes other content less visible, and in data heavy user interfaces, screen real estate is worth a lot in many senses. Thus, developers struggle with the traditional issue of letting users have the cake and eat it at the same time.
Solution -> Tabs. Great stuff, the space issue is resolved, but through implementing tabs we've spawned another problem:
Problem -> The tabbed content has the selector attribute display: none;
And why is this a problem? Graphs are generally drawn on document ready, which means the page loads, all elements are in place(except for our background tab) and the javascript starts drawing graphs on the elements it can see, hence our hidden tab will have nothing in it when its clicked.
Example:
http://jsfiddle.net/b3rgstrom/cD6dd/2/
Now there is a solution to this, we can use the function redraw() that comes with morris, and we'll jack it up to the bootstrap event that determines the tab is active, shown.bs.tab. So when the bootstrap tab is shown, we draw some graphs.
We will give each tab the HTML5 data-identifiers of the graphs that are present within them in the HTML. In the javascript we will determine on which tab we are, and take these identifiers and execute the redraw() function on them, this is so we don't try to redraw graphs that are not suppose to be shown at that time, economy economy...
The complete working solution can be found here:
http://jsfiddle.net/b3rgstrom/cD6dd/12/
So there you have it, pretty pretty morris graphs in bootstrap tabs. I'll include all the code snippets at the end here if you'd rather read it here than on jsFiddle.
Enjoy.
The HAML:
.panel.panel-default.tab-box#monitor .panel-heading %h3.panel-title %i.fa.fa-signal Monitoring report %ul.nav.nav-tabs %li.active %a{"data-toggle" => "tab", href: "#fuel-tab", "data-identifier" => "line, donut"} Fuel data %li %a{"data-toggle" => "tab", href: "#co2-tab", "data-identifier" => "bar1"} Co2 data .panel-body .tab-content #fuel-tab.tab-pane.active .row .col-sm-12.col-md-7.chart .caption Fuel consumption last 12 months %span.label.label-default Liter/100km #fuel-consumption .legend %span.label#city City %span.label#highway Highway %span.label#idle Idle .col-sm-12.col-md-5.chart .caption Fuel projection this month #fuel-projection .legend %span.label#projection Projection %span.label#today Until today #co2-tab.tab-pane .row .col-xs-12.chart .caption Monthly average Co2 Emissions %span.label.label-default g/km #co2-emissions
The JavaScript:
$('ul.nav a').on('shown.bs.tab', function (e) { var types = $(this).attr("data-identifier"); var typesArray = types.split(","); $.each(typesArray, function (key, value) { eval(value + ".redraw()"); }) }); // Morris graphs ---------------------------------------------------------- // // on doc ready $(function () { // Fuel consumption // // Data set for fuel consumption var fuel_data = [{ "period": "2013-01", "city": 66, "highway": 34, "idle": 9 }, { "period": "2013-02", "city": 62, "highway": 33, "idle": 8 }, { "period": "2013-03", "city": 61, "highway": 32, "idle": 7 }, { "period": "2013-04", "city": 66, "highway": 32, "idle": 6 }, { "period": "2013-05", "city": 67, "highway": 31, "idle": 5 }, { "period": "2013-06", "city": 68, "highway": 43, "idle": 7 }, { "period": "2013-07", "city": 62, "highway": 32, "idle": 5 }, { "period": "2013-08", "city": 61, "highway": 32, "idle": 5 }, { "period": "2013-09", "city": 58, "highway": 32, "idle": 7 }, { "period": "2013-10", "city": 60, "highway": 32, "idle": 7 }, { "period": "2013-11", "city": 60, "highway": 32, "idle": 6 }, { "period": "2013-12", "city": 62, "highway": 32, "idle": 8 }]; // Line chart parameters for fuel consumption var fuel_consumption = { element: 'fuel-consumption', hideHover: 'auto', data: fuel_data, xkey: 'period', xLabels: 'month', ykeys: ['city', 'highway', 'idle'], postUnits: ' l/100km', labels: ['City', 'Highway', 'Idle'], resize: true, lineColors: ['#A52A2A', '#72A0C1', '#7BB661'] //yLabelFormat: function(y) { return y.toString() + ' l/100km'; } } // Make a line chart from the parameters line = Morris.Line(fuel_consumption) // / Fuel consumption // // Fuel projection // // Data set for fuel projection var projection_data = [{ label: 'Until today', value: 180 }, { label: 'Projected', value: 400 }, ] // Donut chart parameters for fuel projection var fuel_projection = { element: 'fuel-projection', hideHover: 'auto', resize: true, data: projection_data, colors: ['#7BB661', '#72A0C1'], formatter: function (y) { return y + " liters" } } // Make a donut chart from the parameters donut = Morris.Donut(fuel_projection) // / Fuel projection // // Fuel emissions // // Data set for fuel emissions var co2_data = [{ month: 'Jan', emissions: 35 }, { month: 'Feb', emissions: 37 }, { month: 'Mar', emissions: 40 }, { month: 'Apr', emissions: 38 }, { month: 'Maj', emissions: 39 }, { month: 'Jun', emissions: 42 }, { month: 'Jul', emissions: 37 }, { month: 'Aug', emissions: 65 }, { month: 'Sep', emissions: 38 }, { month: 'Okt', emissions: 45 }, { month: 'Nov', emissions: 41 }, { month: 'Dec', emissions: 41 }] //Bar chart parameters for CO2 emissions var co2_emissions = { element: 'co2-emissions', resize: true, data: co2_data, xkey: 'month', ykeys: ['emissions'], labels: ['Co2 emissions'], barRatio: 0.4, xLabelAngle: 35, hideHover: 'auto', postUnits: ' g/km', formatter: function (y) { return y + " g/km" } } // Make a bar chart from the parameters bar1 = Morris.Bar(co2_emissions) // / Fuel emisisons // }); // / Morris graphs -------------------------------------------------------- //
The CSS:
.tab-box .panel-heading > .nav-tabs { float: right; margin-top: -2px; display: inline-block; border-bottom: 0; } .tab-box .panel-heading > .nav-tabs > li > a { border: 0; padding: 6px 7px; } @media (min-width: 444px) { .tab-box .panel-heading > .nav-tabs > li > a { padding: 6px 15px; } } .tab-box .panel-heading > .nav-tabs > li.active > a { border-left: 1px solid #dddddd; border-right: 1px solid #dddddd; border-bottom: 0; border-top: 1px solid #7c1c1d; background: #fff; } .panel.panel-default > .panel-heading h3 { display: inline-block; } svg { width: 100% !important; }
Additional resources needed:
bootstrap 3 css & js
fontawesome
jquery













