在隐藏的引导选项卡窗格上重绘google图表 [英] redraw google charts on hidden bootstrap tab pane

查看:215
本文介绍了在隐藏的引导选项卡窗格上重绘google图表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的网络应用程序中使用谷歌散点图,并在准备好的文档上加载。我最近做了一些重组,并尝试将页面内容分成不同的引导标签。



如果我在活动选项卡窗格中加载图形,它会正常工作,图形的宽度,高度参数是正确的。但是,如果我将图转移到隐藏的选项卡上,图形无法正确加载在函数上传递的参数(特别是宽度和高度)。目前我正在准备文件上的图表。



这是我的代码



HTML

 < div class =layout layout-stack-sm layout-main-right> 
< div class =col-sm-3 layout-sidebar>
< div class =col-sm-12>
< ul id =myTabclass =nav nav-layout-sidebar nav-stacked>
< li class =active>
< a href =#quick-statsdata-toggle =tab>
< i class =fa fa-th>< / i>
& nbsp;& nbsp;快速统计资料
< / a>
< / li>
< li>
< a href =#engagement-graphdata-toggle =tab>
< i class =fa fa-bar-chart-o>< / i>
& nbsp;& nbsp;订婚图
< / a>
< / li>
< / ul>
< / div>
< / div> <! - 布局侧边栏 - >

< div class =col-sm-9 layout-main>
< div class =tab-content stacked-content>
< div class =tab-pane fade in activeid =quick-stats>
一些内容
< / div>
< div class =tab-pane fadeid =engagement-graph>
< div id =myMoodPage>
< div class =graphid =graph>
< / div>
< / div>
< / div>
< / div>
< / div>

载入文件准备就绪图

 < script type =text / javascriptsrc =https://www.google.com/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'); $'

$ b $('a [href ='#engagement-graph'])。('shown.bs.tab',function(e){
google .load('visualization','1',{
packages:['corechart'],
callback:drawChart
});
});

< / script>

这是我的主要JS文件,我定义了图形参数和其他东西相关的这个问题,但只是为了完整起见,我发布了整个函数)

pre $ (function($){
$ .widget(ui.myMood,{
options:{
graphDataUrl:,
graphData:{},
titles:[time, 心情,平均]
},
_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);
返回这个
},
loadGraph:function(){
var self = this;
var data = {
period:self.periodSelect.val(),
question:self.questionSelect.val()
};
var success = function(data){
self.setGraphData(data)
};
$ .ajax({
类型:POST,
url:self.options.graphDataUrl,
数据:数据,
成功:成功
})
},
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(。 。下)显示();
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(。 。下)显示();
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-颜色:#9c3b8a;>';
if(moodData [i] .event!= null){
moodText + = moodData [i] .event +
}
moodText + = moodData [i]。心情;
if(moodData [i] .comment){
moodText + =< br> + moodData [i] .comment
}
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]。平均;
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({
类型:布尔值,
角色:确定性
});
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:{
colo r:#9c3b8a,
lineWidth:2,
pointSize:6
},
1:{
color:#15426c,
lineWidth:1,
pointSize:3
}
}
};
chart.draw(dataView,options)
}
}
})
})(jQuery);

我尝试像这样重新加载图表,但它无效

$ b $ ('shown.bs.tab',function(e){
$ b

  $(a [href ='#engagement-graph'])。 b $ b google.load('visualization','1',{
packages:['corechart'],
callback:drawChart
});
});



<2>截屏2种不同情况

在活动标签窗格



加载隐藏的标签页面


在隐藏div中绘制图表(这通常是tab接口的实现方式)打破了Visualization API中的维度检测算法,这就是为什么图表奇怪地绘制如果在开始时打开的选项卡以外的任何选项卡中绘制。



您只能加载API一次;后续对 google.load 对Visualization API的调用将被忽略,这就是为什么您的shown.bs.tab事件处理程序不能执行您想要的操作。



由于延迟了标签初始化,直到图表绘制对Bootstrap不是一个真正可行的选项,我会建议替换此代码:

  google.load(visualization,1,{packages:[corechart]}); $'
$ b $(a [href ='#engagement-graph'])。on('shown.bs.tab',function(e){
google.load('visualization ','1',{
packages:['corechart'],
callback:drawChart
});
});

用这个:

 函数init(){
if(/ *布尔表达式如果图表选项卡打开* /){
drawChart();

else {
$(a [href ='#engagement-graph'])。one('shown.bs.tab',drawChart);


$ b google.load(visualization,1,{packages:[corechart],callback:init});

如果它的容器选项卡打开,这应该绘制图表,并创建一次性事件处理程序



您需要将此代码放入 setGraphData 函数来避免数据加载时的竞争条件,所以 drawChart 函数将在范围内。另外,删除这些行:

  if(google){
drawChart()
} else {
google.setOnLoadCallback(drawChart)
}

只要 jsapi 的脚本标记加载时(这些代码在执行之前),就会存在google 对象,因此您将始终触发 drawChart 函数。然而,让 google 对象可用,并不意味着加载了Visualization API。


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>
                        &nbsp;&nbsp;Quick Stats
                    </a>
                </li>
                <li>
                    <a href="#engagement-graph" data-toggle="tab">
                        <i class="fa fa-bar-chart-o"></i>
                        &nbsp;&nbsp;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.com/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 completeness 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].comment) {
                    moodText += "<br>" + moodData[i].comment
                }
                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

解决方案

Drawing 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.

这篇关于在隐藏的引导选项卡窗格上重绘google图表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆