admin管理员组文章数量:1277896
I am using google scatter chart in my web app and it loads on document ready. I recently did some restructuring and trying to divide the page content in different bootstrap tabs.
If I load the graph on the active tab pane it work fine and the width, height parameters of the graph is correct. However if I shift the graph to a hidden tab the graph doesn't load properly with the parameters passed on the function (specially width and height). At the moment I am calling the graph on document ready.
Here is my code
HTML
<div class="layout layout-stack-sm layout-main-right">
<div class="col-sm-3 layout-sidebar">
<div class="col-sm-12">
<ul id="myTab" class="nav nav-layout-sidebar nav-stacked">
<li class="active">
<a href="#quick-stats" data-toggle="tab">
<i class="fa fa-th"></i>
Quick Stats
</a>
</li>
<li>
<a href="#engagement-graph" data-toggle="tab">
<i class="fa fa-bar-chart-o"></i>
Engagement graph
</a>
</li>
</ul>
</div>
</div> <!-- layout sidebar -->
<div class="col-sm-9 layout-main">
<div class="tab-content stacked-content">
<div class="tab-pane fade in active" id="quick-stats">
Some content
</div>
<div class="tab-pane fade" id="engagement-graph">
<div id="myMoodPage">
<div class="graph" id="graph">
</div>
</div>
</div>
</div>
</div>
Loading graph on document ready
<script type="text/javascript" src="">
</script>
<script type="text/javascript">
google.load("visualization", "1", {packages: ["corechart"]});
$(document).ready(function () {
$('#myMoodPage').myMood({
graphDataUrl: '<?php echo $this->url('my_mood/mood_graph_data'); ?>',
graphData: <?php echo $graphData; ?>,
titles: ['<?php echo $this->translate('time'); ?>', '<?php echo $this->translate('mood'); ?>', '<?php echo $this->translate('avg'); ?>']
});
});
function updatePageCharts() {
$('#myMoodPage').myMood('loadGraph');
}
$("a[href='#engagement-graph']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChart
});
});
</script>
This is my main JS file where I am defining the graph parameters and other things (which are not actually relevant for this question, but just for the sake of pleteness I am posting the whole function)
(function ($) {
$.widget("ui.myMood", {
options: {
graphDataUrl: "",
graphData: {},
titles: ["time", "mood", "avg"]
},
_create: function () {
var self = this;
this.periodSelect = this.element.find('select[name="period"]');
this.questionSelect = this.element.find('select[name="question"]');
this.graphContainer = this.element.find(".statistics");
this.atStart = this.element.find("#atStart .value");
this.highest = this.element.find("#highest .value");
this.lowest = this.element.find("#lowest .value");
this.current = this.element.find("#current .value");
this.last30 = this.element.find("#last30 .value");
this.last30Trend = this.element.find("#last30");
this.week = this.element.find("#week .value");
this.weekTrend = this.element.find("#week");
this.graphId = "graph";
this.selectedFilterName = this.options.titles[2];
this.periodSelect.change(function () {
self.loadGraph()
});
this.questionSelect.change(function () {
self.loadGraph();
self.selectedFilterName = self.questionSelect.find("option:selected").text()
});
this.setGraphData(this.options.graphData);
return this
},
loadGraph: function () {
var self = this;
var data = {
period: self.periodSelect.val(),
question: self.questionSelect.val()
};
var success = function (data) {
self.setGraphData(data)
};
$.ajax({
type: "POST",
url: self.options.graphDataUrl,
data: data,
success: success
})
},
setGraphData: function (data) {
var self = this;
this.atStart.text(data.atStart);
this.highest.text(data.highest);
this.lowest.text(data.lowest);
this.current.text(data.current);
this.last30.text(data.last30.val);
this.last30Trend.find(".up, .down").hide();
this.last30Trend.removeClass("incr");
this.last30Trend.removeClass("decr");
if (Number(data.last30.trend) > 0) {
this.last30Trend.find(".up").show();
this.last30Trend.addClass("incr")
}
if (Number(data.last30.trend) < 0) {
this.last30Trend.find(".down").show();
this.last30Trend.addClass("decr")
}
this.week.text(data.week.val);
this.weekTrend.find(".up, .down").hide();
this.weekTrend.removeClass("incr");
this.weekTrend.removeClass("decr");
if (Number(data.week.trend) > 0) {
this.weekTrend.find(".up").show();
this.weekTrend.addClass("incr")
}
if (Number(data.week.trend) < 0) {
this.weekTrend.find(".down").show();
this.weekTrend.addClass("decr")
}
var moodData = data.mood;
var dataArray = new Array();
for (i in moodData) {
if (moodData[i].avg == null) {
moodData[i].avg = undefined
}
if (moodData[i].mood == null) {
moodData[i].mood = undefined
}
if (moodData[i].team == null) {
moodData[i].team = undefined
}
var moodText = '<div style="border-radius: 2px; padding: 10px; color: #ffffff; font-weight: bold; background-color: #9c3b8a;">';
if (moodData[i].event != null) {
moodText += moodData[i].event + " "
}
moodText += moodData[i].mood;
if (moodData[i]ment) {
moodText += "<br>" + moodData[i]ment
}
moodText += "</div>";
var avgText = '<div style="border-radius: 2px; padding: 10px; color: #ffffff; font-weight: bold; background-color: #15426c;">';
if (moodData[i].event != null) {
avgText += moodData[i].event + " "
}
avgText += moodData[i].avg;
if (moodData[i].publicComment) {
avgText += "<br>" + moodData[i].publicComment
}
avgText += "</div>";
var row = [new Date(moodData[i].time * 1000), Number(moodData[i].mood), moodText, Number(moodData[i].avg), avgText, false];
dataArray.push(row)
}
if (google) {
drawChart()
} else {
google.setOnLoadCallback(drawChart)
}
function drawChart() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn("date", self.options.titles[0]);
dataTable.addColumn("number", self.options.titles[1]);
dataTable.addColumn({
type: "string",
role: "tooltip",
p: {
html: true
}
});
dataTable.addColumn("number", self.selectedFilterName);
dataTable.addColumn({
type: "string",
role: "tooltip",
p: {
html: true
}
});
dataTable.addColumn({
type: "boolean",
role: "certainty"
});
dataTable.addRows(dataArray);
var dataView = new google.visualization.DataView(dataTable);
var chart = new google.visualization.ScatterChart(document.getElementById(self.graphId));
var options = {
legend: {
position: "bottom"
},
interpolateNulls: true,
chartArea: {
left: 25,
top: 25,
width: '92%',
height: '80%'
},
backgroundColor: "#ffffff",
vAxis: {
minValue: 0,
maxValue: 6,
viewWindow: {
min: 0,
max: 6
}
},
tooltip: {
isHtml: true
},
series: {
0: {
color: "#9c3b8a",
lineWidth: 2,
pointSize: 6
},
1: {
color: "#15426c",
lineWidth: 1,
pointSize: 3
}
}
};
chart.draw(dataView, options)
}
}
})
})(jQuery);
I tried reloading the graph like this, but it didn't work
$("a[href='#engagement-graph']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChart
});
});
Screenshot in 2 different situation
Loading on active tab pane
Loading on hidden tab pane
I am using google scatter chart in my web app and it loads on document ready. I recently did some restructuring and trying to divide the page content in different bootstrap tabs.
If I load the graph on the active tab pane it work fine and the width, height parameters of the graph is correct. However if I shift the graph to a hidden tab the graph doesn't load properly with the parameters passed on the function (specially width and height). At the moment I am calling the graph on document ready.
Here is my code
HTML
<div class="layout layout-stack-sm layout-main-right">
<div class="col-sm-3 layout-sidebar">
<div class="col-sm-12">
<ul id="myTab" class="nav nav-layout-sidebar nav-stacked">
<li class="active">
<a href="#quick-stats" data-toggle="tab">
<i class="fa fa-th"></i>
Quick Stats
</a>
</li>
<li>
<a href="#engagement-graph" data-toggle="tab">
<i class="fa fa-bar-chart-o"></i>
Engagement graph
</a>
</li>
</ul>
</div>
</div> <!-- layout sidebar -->
<div class="col-sm-9 layout-main">
<div class="tab-content stacked-content">
<div class="tab-pane fade in active" id="quick-stats">
Some content
</div>
<div class="tab-pane fade" id="engagement-graph">
<div id="myMoodPage">
<div class="graph" id="graph">
</div>
</div>
</div>
</div>
</div>
Loading graph on document ready
<script type="text/javascript" src="https://www.google./jsapi">
</script>
<script type="text/javascript">
google.load("visualization", "1", {packages: ["corechart"]});
$(document).ready(function () {
$('#myMoodPage').myMood({
graphDataUrl: '<?php echo $this->url('my_mood/mood_graph_data'); ?>',
graphData: <?php echo $graphData; ?>,
titles: ['<?php echo $this->translate('time'); ?>', '<?php echo $this->translate('mood'); ?>', '<?php echo $this->translate('avg'); ?>']
});
});
function updatePageCharts() {
$('#myMoodPage').myMood('loadGraph');
}
$("a[href='#engagement-graph']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChart
});
});
</script>
This is my main JS file where I am defining the graph parameters and other things (which are not actually relevant for this question, but just for the sake of pleteness I am posting the whole function)
(function ($) {
$.widget("ui.myMood", {
options: {
graphDataUrl: "",
graphData: {},
titles: ["time", "mood", "avg"]
},
_create: function () {
var self = this;
this.periodSelect = this.element.find('select[name="period"]');
this.questionSelect = this.element.find('select[name="question"]');
this.graphContainer = this.element.find(".statistics");
this.atStart = this.element.find("#atStart .value");
this.highest = this.element.find("#highest .value");
this.lowest = this.element.find("#lowest .value");
this.current = this.element.find("#current .value");
this.last30 = this.element.find("#last30 .value");
this.last30Trend = this.element.find("#last30");
this.week = this.element.find("#week .value");
this.weekTrend = this.element.find("#week");
this.graphId = "graph";
this.selectedFilterName = this.options.titles[2];
this.periodSelect.change(function () {
self.loadGraph()
});
this.questionSelect.change(function () {
self.loadGraph();
self.selectedFilterName = self.questionSelect.find("option:selected").text()
});
this.setGraphData(this.options.graphData);
return this
},
loadGraph: function () {
var self = this;
var data = {
period: self.periodSelect.val(),
question: self.questionSelect.val()
};
var success = function (data) {
self.setGraphData(data)
};
$.ajax({
type: "POST",
url: self.options.graphDataUrl,
data: data,
success: success
})
},
setGraphData: function (data) {
var self = this;
this.atStart.text(data.atStart);
this.highest.text(data.highest);
this.lowest.text(data.lowest);
this.current.text(data.current);
this.last30.text(data.last30.val);
this.last30Trend.find(".up, .down").hide();
this.last30Trend.removeClass("incr");
this.last30Trend.removeClass("decr");
if (Number(data.last30.trend) > 0) {
this.last30Trend.find(".up").show();
this.last30Trend.addClass("incr")
}
if (Number(data.last30.trend) < 0) {
this.last30Trend.find(".down").show();
this.last30Trend.addClass("decr")
}
this.week.text(data.week.val);
this.weekTrend.find(".up, .down").hide();
this.weekTrend.removeClass("incr");
this.weekTrend.removeClass("decr");
if (Number(data.week.trend) > 0) {
this.weekTrend.find(".up").show();
this.weekTrend.addClass("incr")
}
if (Number(data.week.trend) < 0) {
this.weekTrend.find(".down").show();
this.weekTrend.addClass("decr")
}
var moodData = data.mood;
var dataArray = new Array();
for (i in moodData) {
if (moodData[i].avg == null) {
moodData[i].avg = undefined
}
if (moodData[i].mood == null) {
moodData[i].mood = undefined
}
if (moodData[i].team == null) {
moodData[i].team = undefined
}
var moodText = '<div style="border-radius: 2px; padding: 10px; color: #ffffff; font-weight: bold; background-color: #9c3b8a;">';
if (moodData[i].event != null) {
moodText += moodData[i].event + " "
}
moodText += moodData[i].mood;
if (moodData[i].ment) {
moodText += "<br>" + moodData[i].ment
}
moodText += "</div>";
var avgText = '<div style="border-radius: 2px; padding: 10px; color: #ffffff; font-weight: bold; background-color: #15426c;">';
if (moodData[i].event != null) {
avgText += moodData[i].event + " "
}
avgText += moodData[i].avg;
if (moodData[i].publicComment) {
avgText += "<br>" + moodData[i].publicComment
}
avgText += "</div>";
var row = [new Date(moodData[i].time * 1000), Number(moodData[i].mood), moodText, Number(moodData[i].avg), avgText, false];
dataArray.push(row)
}
if (google) {
drawChart()
} else {
google.setOnLoadCallback(drawChart)
}
function drawChart() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn("date", self.options.titles[0]);
dataTable.addColumn("number", self.options.titles[1]);
dataTable.addColumn({
type: "string",
role: "tooltip",
p: {
html: true
}
});
dataTable.addColumn("number", self.selectedFilterName);
dataTable.addColumn({
type: "string",
role: "tooltip",
p: {
html: true
}
});
dataTable.addColumn({
type: "boolean",
role: "certainty"
});
dataTable.addRows(dataArray);
var dataView = new google.visualization.DataView(dataTable);
var chart = new google.visualization.ScatterChart(document.getElementById(self.graphId));
var options = {
legend: {
position: "bottom"
},
interpolateNulls: true,
chartArea: {
left: 25,
top: 25,
width: '92%',
height: '80%'
},
backgroundColor: "#ffffff",
vAxis: {
minValue: 0,
maxValue: 6,
viewWindow: {
min: 0,
max: 6
}
},
tooltip: {
isHtml: true
},
series: {
0: {
color: "#9c3b8a",
lineWidth: 2,
pointSize: 6
},
1: {
color: "#15426c",
lineWidth: 1,
pointSize: 3
}
}
};
chart.draw(dataView, options)
}
}
})
})(jQuery);
I tried reloading the graph like this, but it didn't work
$("a[href='#engagement-graph']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChart
});
});
Screenshot in 2 different situation
Loading on active tab pane
Loading on hidden tab pane
Share Improve this question edited May 29, 2014 at 11:39 0xburned asked May 29, 2014 at 11:33 0xburned0xburned 2,6558 gold badges44 silver badges71 bronze badges2 Answers
Reset to default 9Drawing charts inside hidden divs (which is usually what tab interfaces are implemented as) breaks the dimension detection algorithms in the Visualization API, which is why the chart draws oddly when drawn in any tab other than the tab open at the start.
You can load the API only once; subsequent calls to google.load
for the Visualization API will be ignored, which is why your "shown.bs.tab" event handler does not do what you want.
Since delaying the tab initialization until after the charts draw is not really a viable option with Bootstrap, I would suggest replacing this code:
google.load("visualization", "1", {packages: ["corechart"]});
$("a[href='#engagement-graph']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChart
});
});
with this:
function init () {
if (/* boolean expression teting if chart tab is open */) {
drawChart();
}
else {
$("a[href='#engagement-graph']").one('shown.bs.tab', drawChart);
}
}
google.load("visualization", "1", {packages: ["corechart"], callback: init});
This should draw the chart if its container tab is open, and create a one-time event handler that draws the chart the first time the tab is opened if the tab is not open.
You need to put this code inside the setGraphData
function to avoid a race condition with your data loading, and so the drawChart
function will be in scope. Also, remove these lines:
if (google) {
drawChart()
} else {
google.setOnLoadCallback(drawChart)
}
The google
object exists as soon as the script tag for the jsapi
loads, which will be before this code is executed, so you will always trigger the drawChart
function here. Having the google
object available, however, does not mean that the Visualization API is loaded.
Just incase other people are looking for a simpler solution.
An alternative is to implement the following:
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var ev = document.createEvent('Event');
ev.initEvent('resize', true, true);
window.dispatchEvent(ev);
});
This will cause the chart to re-draw as if the browser was resized.
本文标签: javascriptredraw google charts on hidden bootstrap tab paneStack Overflow
版权声明:本文标题:javascript - redraw google charts on hidden bootstrap tab pane - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741257448a2366955.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论