Paul.Whipp

Am I jumping through too many hoops?

Recommended Posts

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.

 

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now