Paul.Whipp

Members
  • Content count

    1
  • Joined

  • Last visited

Posts posted by Paul.Whipp


  1. I'm working on a large existing Angular application that has a requirement for a dashboard. I've added fusion charts via https://github.com/SunGard-Labs/angular-fusioncharts/. It is looking good but I'm concerned at the complexity of the javascript I'm writing.

     

    I need 'drill down' on a multi-series chart (which has variable aggregation) to open a tabular report listing the rows corresponding to the data aggregated into the selected bar. I've wired in a link function that opens the relevant page with the filters set depending upon the parameters so it all works but corrupts the global name space with a function (_ARD) to call back into the chart service and feels like I'm jumping through too many hoops to achieve the goal. Is there a better way to do this?

    angular.module('dhuiApp').factory(
        'FCCharts', function () {
            var charts = {};
            var factory = {
                charts: charts
            };
    
            function specializeChart(existing_name, specialization_name){
                var newChart = jQuery.extend(true, {}, charts[existing_name]);
                newChart.name = specialization_name;
                charts[specialization_name] = newChart;
            }
    
            charts.multi_series = {
                name: 'multi_series',
                chart: {
                    caption: "Caption",
                    xAxisName: "X Axis",
                    yAxisName: "Y Axis",
                    theme: "fint"
                },
                categories: [
                    {
                        category: []
                    }
                ],
                dataset: [],
                seriesNames: [],
                categoryLabels: [],
    
                makeSeriesItem: function(categoryIdx, seriesIdx){
                    // Make fc link string so we can do our own drill down
                    // Use _ARD global function to get back into this service
                    var categoryLabel = this.categoryLabels[categoryIdx];
                    var seriesName = this.seriesNames[seriesIdx];
                    var params = [this.name, categoryLabel, seriesName];
                    return {
                        value: 0,
                        link: 'j-_ARD-'+params.join('-')
                    };
                },
    
                newCategory: function (label){
                    // confused naming - fc has an extra 'category' layer under categories
                    var seriesIdx, series;
                    var category = {label: label};
                    var categoryIdx = this.categoryLabels.length; // about to add it
                    this.categories[0].category.push(category);
                    this.categoryLabels.push(label);
                    // Add category to all series
                    var num_series = this.dataset.length;
                    for (seriesIdx = 0; seriesIdx < num_series; seriesIdx++){
                        series = this.dataset[seriesIdx];
                        series.data.push(this.makeSeriesItem(categoryIdx, seriesIdx));
                    }
                },
    
                newSeries: function(series_name){
                    var series = {
                        seriesname: series_name,
                        data: []
                    };
                    var categoryIdx;
                    var seriesIdx = this.seriesNames.length; // about to add it
                    var num_categories = this.categories[0].category.length;
                    for (categoryIdx = 0; categoryIdx < num_categories; categoryIdx++){
                        series.data.push(this.makeSeriesItem(categoryIdx, seriesIdx));
                    }
                    this.dataset.push(series);
                    this.seriesNames.push(series_name);
                },
    
                getCategory: function(dt, aggregation){
                    var dt_format = {
                            Day: 'shortDate',
                            Week: 'ww/YY',
                            Month: 'MMM/YY'
                        }[aggregation] || 'MMM/YY';
                    return dt.format(dt_format);
                }
            };
    
            specializeChart('multi_series', 'uploads');
    
            charts.uploads.populate = function(report, from_dt, to_dt, aggregation, linkFn){
                var i;
                var num_rows = report.rows.length;
                var row, series_name, category_label;
                var series_data;
    
                // do the preamble
                this.chart.caption = report.title || 'Untitled';
                this.chart.xAxisName = aggregation;
                this.chart.yAxisName = this.chart.caption;
    
                // clear any existing data
                this.linkFn = linkFn;
                this.categoryLabels = [];
                this.seriesNames = [];
                this.categories[0].category = [];
                this.dataset = [];
    
                // Extract the data from the rows
                for (i = 0; i < num_rows; i++){
                    row = report.rows[i];
    
                    category_label = this.getCategory(row['Added On'], aggregation);
                    if (this.categoryLabels.indexOf(category_label) == -1){
                        this.newCategory(category_label);
                    }
    
                    series_name = row['Type'];
                    if (this.seriesNames.indexOf(series_name) == -1){
                        this.newSeries(series_name);
                    }
                    series_data = this.dataset[this.seriesNames.indexOf(series_name)].data;
                    series_data[this.categoryLabels.indexOf(category_label)].value += 1
                }
            };
    
            factory.getChart = function(chart_name) {
                return charts[chart_name];
            };
    
            factory.linkClicked = function(s){
                var params = s.split('-');
                console.log(params[0]);
                console.log(charts[params[0]]);
                charts[params[0]].linkFn(params.slice(1));
            };
    
            return factory;
        });
    
    /*
    Not having the event listeners working (might be a better solution if I could get them working):
    _ARD is used in the link text as the fusion chart function.
    This is nasty global pollution to link the angular scope to the chart data and I'd love a better method.
     */
    function _ARD(s){
        var fc_charts = angular.element(document.querySelector('.ng-scope')).injector().get('FCCharts');
        fc_charts.linkClicked(s);
    }
    

    I have wondered about rewriting the angular directives so that I use a specialization of the fusioncharts object as my 'intelligent chart object' (exposing the fusion chart object in the service) but with two angular fusioncharts packages already out there, a third seems like overkill.

     

    I'm going to be adding quite a few charts with similar drill down to tables representing the selected underlying data (sometimes through the intermediary of drill down charts) which is why I've set this up so that I can add more charts.