Highchart angular指令不会从动态(ajax)数据表重绘

时间:2013-12-19 03:03:15

标签: javascript ajax angularjs highcharts

我有一个AngularJs应用程序,它从API检索数据并将它们填充到表中。然后,我使用Highcharts根据该表绘制图表。如果我在表中使用静态数据,它工作正常,但是当我通过AJAX更新表时它不起作用。它不会重绘。

指令:

app.directive('highChart', function ($parse) {
    return {        
        link: function(scope, element, attrs) {
            scope.$watch('chartConfig', function (newVal) {
                if (newVal) {
                    var props = $parse(attrs.highChart)(scope);
                    props.chart.renderTo = element[0];
                    new Highcharts.Chart(props);
                }
            });
        }
    };
});

控制器:

appControllers.controller('SummaryController', ['$scope', '$timeout', 'Summaries',
    function ($scope, $timeout, Summaries) {
        // Request from API
        Summaries.get({ table: 'level'}).$promise.then(
            // success callback
            function(data) {
                $scope.levels = data.level[0][today];
                $scope.chartConfig = {
                    data: {
                        table: document.getElementById('daily-level')
                    },
                    chart: {
                        type: 'column'
                    },
                    title: {
                        text: 'Data extracted from a HTML table in the page'
                    },
                    yAxis: {
                        allowDecimals: false,
                        title: {
                            text: 'Units'
                        }
                    },
                    tooltip: {
                        formatter: function () {
                            return '<b>' + this.series.name + '</b><br/>' +
                                this.y + ' ' + this.x;
                        }
                    }
                 };
            }
    }]);

HTML

<div id="top-chart" high-chart="chartConfig"></div>

它只显示一个空图表。我的表确实由AJAX请求更新。我甚至在指令中检查了console.log(props)props.data.table确实显示了更新的表,但不知何故图表没有重绘。我已经尝试了多种方法来做到这一点,但都归结为相同的结果。目前,我只是使用jQuery超时刷新图表,它可以工作,但这意味着我在控制器内部使用DOM操作。我正在尝试使用指令实现此目的。

3 个答案:

答案 0 :(得分:3)

确定。我设法让它发挥作用。我认为问题是,Highcharts不知道这些变化,或者它是否知道变化,那时的DOM还没有完成渲染。这是代码的工作版本。

指令:

app.directive('highchart', function($parse, $timeout) {
    return {
        restrict: 'E',
        template: '<div></div>',
        replace: true,
        link: function(scope, element, attrs) {
            var config = $parse(attrs.config)(scope);
            $(element[0]).highcharts(config);

            scope.$watch(attrs.watch, function(newVal) {
                if (newVal) {
                    var complete = function (options) {
                        var chart = $(element[0]).highcharts();
                        // capture all available series
                        var allSeries = chart.series;
                        for (var i = 0; i < allSeries.length; i++) {
                            allSeries[i].setData(options.series[i].data, false);
                        }

                        chart.redraw();
                    };

                    // doesn't work without the timeout 
                    $timeout(function() {
                        Highcharts.data({
                            table: config.data.table,
                            complete: complete
                        });   
                    }, 0);
                }
            });
        }
    };
});

在控制器中,我们可以设置配置。

    $scope.chartConfig = {
         // config here
    };

使用它:

<highchart config="chartConfig" watch="levels"></highchart>

属性config绑定到$scope.chartConfigwatch是指令中watch.$scope()的触发器。当$scope.levels在控制器中发生变化时,它将重新渲染图表。

我实际上并不喜欢该指令对我现在拥有的watch属性的依赖性,但我不确定这样做的最佳或其他方法是什么。如果有人有更好的想法,请告诉我。

请注意,这只能将表转换为高图。对于其他人,您可能需要使用其他angularjs highcharts指令。

答案 1 :(得分:1)

在下面的示例中,您可以使用watch更新数据库中的更新数据。它会继续检查新数据并分别进行更改:

app.directive('line',['$compile', function ($compile) {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        scope: {
            data: '=',
        },
        link: function (scope, element) {
            scope.lineGraphInstance = Highcharts.chart(element[0],{
                chart: {
                    type: 'spline',
                    style: {
                        fontSize: '8px'
                    },
                    spacingBottom: scope.data.spacingBottom,
                    spacingTop: scope.data.spacingTop,
                    spacingLeft: scope.data.spacingLeft,
                    spacingRight: scope.data.spacingRight,
                },
                title: {
                    text: '',
                },                      
                xAxis: {
                    type: 'datetime',
                    title: {
                        text: scope.data.xtitle,
                        enabled: false
                    },
                    labels: {
                        style: {
                            fontSize: '8px'
                        },                  
                        autoRotation: 0,
                        formatter: function () {
                            var x=this.value;
                            if (scope.data.hasOwnProperty("dateformat"))
                                x= Highcharts.dateFormat(scope.data.dateformat, this.value);
                            if (scope.data.hasOwnProperty("xSuffix"))
                                x=x+scope.data.xSuffix;         
                            if(scope.data.hasOwnProperty("xPrefix"))
                                x=scope.data.xPrefix+x;

                            return x;
                        },
                    enabled:scope.data.xtitleEnable
                    },
                    tickWidth: 3,
                    tickLength:scope.data.tickLength,
                    tickInterval: 3600 * 100
                        },
                yAxis: {
                    opposite: true,
                    title: {
                        text: scope.data.ytitle,
                        enabled: false
                    },
                    min: 0,
                    labels: {
                        style: {
                            fontSize: '10px'
                        },
                        formatter: function () {
                            var y=this.value;
                            if (scope.data.hasOwnProperty("ySuffix"))
                                y=y+scope.data.ySuffix;         
                            if(scope.data.hasOwnProperty("yPrefix"))
                                y=scope.data.yPrefix+y;

                            return y;
                        },
                    },
                    plotLines: [{
                        value: scope.data.ucl,
                        color: '#F39C12',
                        dashStyle: 'shortdash',
                        width: 1,
                    }, {
                        value: scope.data.lcl,
                        color: '#F39C12',
                        dashStyle: 'shortdash',
                        width: 1,
                    }]
                },
                tooltip: {
                    headerFormat: '<b>{series.name}</b><br>',
                    pointFormat: '{point.x:%e. %b}: {point.y:.2f} '
                },
                plotOptions: {
                    spline: {
                        marker: {
                            enabled: true
                        }
                    }
                },
                legend:{
                    enabled:false
                },
                series:[{data:scope.data.data,
                marker: {
                    enabled: true,
                    radius: 2
                },
                lineWidth: 1
                }],
                credits: {
                    enabled: false
                },  
                exporting: { enabled: false 
                }
            }); 
            ***scope.$watch('data', function (newValue, oldValue) {
                if(newValue && newValue.data){
                    var graphData=newValue.data[0].data.slice(-5);
                    scope.lineGraphInstance.series[0].setData(graphData, true);
                }
            }, true);
        }***
    };
}]); 

答案 2 :(得分:0)

您是否尝试设置工厂,在调用从工厂获取值后,将使用$resource http://docs.angularjs.org/api/ngResource。$资源内部,然后将其显示在图表中?

编辑:更新示例http://jsfiddle.net/csTzc/184/