Reputation: 871
I have a Morris JS chart trying to load within a Twitter Bootstrap tab pane. The tabs work fine, but the chart will not load.
It looks like this article discusses the problem: http://www.doidea.se/blog/morris-js-charts-in-bootstrap-tabs
How would I translate their solution into my Rails code?
Here is my code:
View:
<!-- Nav tabs -->
<ul class="nav nav-tabs">
<li class="active"><a href="#home" data-toggle="tab">Home</a></li>
<li><a href="#profile" data-toggle="tab">Profile</a></li>
<li><a href="#messages" data-toggle="tab">Messages</a></li>
<li><a href="#settings" data-toggle="tab">Settings</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="home">...</div>
<div class="tab-pane" id="profile">
<%= content_tag :div, "", id: "info_chart", data: { info: @chart_data } %>
</div>
<div class="tab-pane" id="messages">...</div>
<div class="tab-pane" id="settings">...</div>
</div>
Application.JS
$('#myTab a').click(function (e) {
e.preventDefault()
$(this).tab('show')
})
ControllerName.js.coffee
$ ->
# only use morris if the post chart element is on the page.
if $('#info_chart').length > 0
Morris.Bar
element: 'info_chart'
data: $('#info_chart').data('info')
xkey: 'x'
ykeys: ['y']
labels: ['label']
Upvotes: 8
Views: 6460
Reputation: 9457
The top answer is partially correct. The problem, however, is the svg is not resized. In order to make sure the svg is resized, you can modify it by css:
if ($('#morris-stacked-bar-graph').length > 0) {
var morris_bar = Morris.Bar({
element: 'morris-stacked-bar-graph',
data: [
{x: '2011 Q1', y: 3, z: 2, a: 3},
{x: '2011 Q2', y: 2, z: null, a: 1},
{x: '2011 Q3', y: 0, z: 2, a: 4},
{x: '2011 Q4', y: 2, z: 4, a: 3}
],
xkey: 'x',
ykeys: ['y', 'z', 'a'],
labels: ['Y', 'Z', 'A'],
stacked: true,
barColors: $('#morris-stacked-bar-graph').data('colors').split(',')
});
$('ul.nav a').on('shown.bs.tab', function (e) {
morris_bar.redraw();
$('svg').css({ width: '100%' });
});
}
Upvotes: 2
Reputation: 3064
I was having the exact same problem, but in my case none of the above solutions worked.
What worked for me was to use the jquery ui tabs instead (link). These worked like a charm.
Your code would only need slight re-writing. Instead of
<!-- Nav tabs -->
<ul class="nav nav-tabs">
<li class="active"><a href="#home" data-toggle="tab">Home</a></li>
<li><a href="#profile" data-toggle="tab">Profile</a></li>
<li><a href="#messages" data-toggle="tab">Messages</a></li>
<li><a href="#settings" data-toggle="tab">Settings</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="home">...</div>
<div class="tab-pane" id="profile">
<%= content_tag :div, "", id: "info_chart", data: { info: @chart_data } %>
</div>
<div class="tab-pane" id="messages">...</div>
<div class="tab-pane" id="settings">...</div>
</div>
write:
<!-- Nav tabs and Panes-->
<div id="tabs">
<ul>
<li class="active"><a href="#home" data-toggle="tab">Home</a></li>
<li><a href="#profile" data-toggle="tab">Profile</a></li>
<li><a href="#messages" data-toggle="tab">Messages</a></li>
<li><a href="#settings" data-toggle="tab">Settings</a></li>
</ul>
<div id="home">...</div>
<div id="profile">
<%= content_tag :div, "", id: "info_chart", data: { info: @chart_data } %>
</div>
<div id="messages">...</div>
<div id="settings">...</div>
</div>
And then you just add this script:
<script>
$(function() {
$( "#tabs" ).tabs();
});
</script>
I hope this helps.
BTW all the fiddles I've found that try to catch event 'shown.bs.tab'
don't work anymore for some reason.
Upvotes: 0
Reputation: 1
This code is working for me, try it if you have multiple Chart on one tab:
$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
$.each(yourarray, function (index, value) {
value.redraw();
});
});
Upvotes: 0
Reputation: 4171
Found a solution to my situation for a single chart on tabs that wasn't display properly:
Save your graph as a variable:
var usage_graph = Morris.Line({
// config
});
Then listen for changes on the tabs, and redraw the graph:
$('ul.nav a').on('shown.bs.tab', function (e) {
usage_graph.redraw();
});
I hope this helps someone else.
Upvotes: 12
Reputation: 397
First, you want to check that you are using the correct version of morris.js, the current master branch on github has the redraw() function.
Second: Make sure that you are able to print a graph in the dom on say, you first active tab.
Third: Add another graph element in a tab that is not active, add data-identifiers for each tab to be able to redraw multiple graphs using:
$('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()");
})
});
This js will determine which data-identifiers are concerned whenever a tab is 'shown', you can have multiple graph elements separated by commas for instance. It will then take the value/values of the identifier, which obviously would be the same as your graph elements and call the redraw() function on them.
I see no need to make it more railsy than that for this, you could always convert to coffeescript ofcourse, but this should work.
Upvotes: 0