草庐IT

javascript - 在隐藏的 Bootstrap 选项卡 Pane 上重绘谷歌图表

coder 2025-02-17 原文

我在我的网络应用程序中使用谷歌散点图,它加载到文档就绪。我最近做了一些重组,并试图将页面内容划分到不同的 Bootstrap 选项卡中。

如果我在事件选项卡 Pane 上加载图形,它工作正常并且图形的宽度、高度参数是正确的。但是,如果我将图形移动到隐藏选项卡,则图形无法使用传递给函数的参数(特别是宽度和高度)正确加载。目前我正在调用文档准备好的图表。

这是我的代码

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>

在文档就绪时加载图表

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

这是我的主要 JS 文件,我在其中定义图形参数和其他内容(实际上与这个问题无关,但为了完整起见,我发布了整个函数)

(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);

我试过像这样重新加载图表,但没有成功

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

两种不同情况下的截图

在事件选项卡 Pane 上加载

在隐藏的选项卡 Pane 上加载

最佳答案

在隐藏的 div 中绘制图表(这通常是标签界面的实现方式)破坏了 Visualization API 中的维度检测算法,这就是为什么在除开始时打开的标签之外的任何标签中绘制图表时图表绘制奇怪的原因。

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

由于将选项卡初始化延迟到图表绘制之后对于 Bootstrap 来说并不是真正可行的选择,因此我建议替换此代码:

google.load("visualization", "1", {packages: ["corechart"]});

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

用这个:

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});

如果容器选项卡打开,这应该绘制图表,如果选项卡未打开,则创建一个一次性事件处理程序,在第一次打开选项卡时绘制图表。

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

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

google 对象在 jsapi 的脚本标签加载后就存在,这将是在执行此代码之前,因此您将始终触发 drawChart 函数在这里。然而,google 对象可用并不意味着可视化 API 已加载。

关于javascript - 在隐藏的 Bootstrap 选项卡 Pane 上重绘谷歌图表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23932363/

有关javascript - 在隐藏的 Bootstrap 选项卡 Pane 上重绘谷歌图表的更多相关文章

  1. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  2. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  3. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  4. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  5. Ruby on Rails regexp equals-tilde 与 array include 用于检查选项列表 - 2

    我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试

  6. Ruby隐藏与覆盖 - 2

    我刚刚了解到,在Java中,覆盖和隐藏之间是有区别的(静态方法是隐藏的,而不是覆盖),这意味着Java使用早期绑定(bind)和后期绑定(bind)。是否有与方法隐藏类似的东西,或者它只是具有方法重写? 最佳答案 Java具有三种不同的“方法”:实例方法,静态方法和构造函数。Ruby只有一个:实例方法。在Java中,静态方法的行为必须不同于实例方法,因为类不是对象。它们没有类,因此也没有父类(superclass),因此没有要覆盖的内容。在Ruby中,类与其他任何对象一样都是对象,它们具有一个类,该类可以具有父类(superclas

  7. ruby-on-rails - 使用 gmaps4rails 动态加载谷歌地图标记 - 2

    如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail

  8. css - Rails 4.1 和 Bootstrap 3 字形图标不工作 - 2

    我正在尝试消除使用Bootstrap3的Rails4元素中的glyphicon错误。我没有使用任何Bootstrapgem将其添加到Assets管道中。我手动将bootstrap.css和bootstrap.js添加到各自的app/assets目录下,分别添加到application.css和application.js什么的我现在在网络浏览器的控制台中看到以下内容:GEThttp://localhost:3000/fonts/glyphicons-halflings-regular.woff404(NotFound)localhost/:1GEThttp://localhost:30

  9. ruby - 选项卡的 Rubocop - 2

    我们想使用Rubocop来验证我们的ruby​​在语法上是否正确并遵循基本代码指南。除此之外我们有这个规则:我们使用制表符缩进以允许任何人决定他们希望如何呈现它们(将它们显示为2或4个空格)问题是rubocop似乎设计为完全拒绝缩进标签。我们怎样才能超越所有这些规则成为太空合规者?编辑:我正在考虑覆盖这个模块https://github.com/bbatsov/rubocop/blob/master/lib/rubocop/source_parser.rb将我文件中的所有制表符替换为2个空格,以创建gem的幻觉... 最佳答案 添加

  10. ruby - Ruby 中的选项菜单 - 2

    我正在尝试在Ruby中创建一个菜单,以便根据用户输入的内容,取决于调用的类。然后在这种情况下它将返回到“Main”或类“Options”。我希望有人能帮助我。这是我的代码。modulePhysicsG=21C=20000Pi=3.14D=100endclassOptionsputs"Pleaseselect1forAccelerationand2forEnergy."option=gets()ifoption==1thenputs"AccelCalc"#ThisisthebitthatneedstodirecttheusertotheclassAccelCalcelseputs"Ene

随机推荐