Code coverage report for app/views/exams/examsAvgChartView.js

Statements: 100% (34 / 34)      Branches: 100% (31 / 31)      Functions: 100% (8 / 8)      Lines: 100% (34 / 34)      Ignored: none     

All files » app/views/exams/ » examsAvgChartView.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188                  1                                       1                                                   1               1       1                                                               5 5 5   13 13                               3   2   2                               2   4 4   4 3     4 2         2 4   4 4     4 3 3         2   2       2       2   2 2   1      
/*global require, define, console, $ */
/*jslint nomen: true, debug: true, todo: true */
 
/**
 * @module examsAvgChartView
 * @extends module:chartView
 */
 
 
define([
    "views/chartView",
    "underscore",
    "utils"
],
    function (chartView, _, utils) {
        "use strict";
 
        /**
         * @name module:examsAvgChartView
         * @description Average exams chart
         * @requires module:chartView
         * @class Backbone.View
         * @requires module:chartView
         * @requires underscore
         * @requires module:utils
         * @see module:utils
         * @constructor
         * @returns {Function} Backbone.View constructor
         */
        return chartView.extend({
            /**
             * @name module:examsAvgChartView#examType
             * @description Exam type declaration
             * @type {string}
             */
            examType: "ege",
            /**
             * @name module:examsAvgChartView#type
             * @description Chart type
             * @type {string}
             */
            type: "spline",
            /**
             * @name module:examsAvgChartView#options
             * @description Chart config extension object
             * @type {object}
             */
            options: {
                yAxis: {
                    title: {
                        text: "score".toLocaleString() + ", %"
                    }
                },
                tooltip: {
                    formatter: function () {
                        return "<b>" + this.series.name + "</b><br/>" + this.x + ": " + this.y.toPrecision(3);
                    }
                },
                plotOptions: {
                    series: {
                        point: {
                            events: {
                                click: function () {
                                    this.series.chart.options
                                        .getWidget().switchMode({
                                            year: this.category
                                        });
                                    return this.category;
                                }
                            }
                        }
                    }
                },
                series: [
                    {
                        name: "weightedAvg".toLocaleString()
                    },
                    {
                        name: "weightedAvgMathRus".toLocaleString()
                    }
                ]
            },
            /**
             * @name module:examsAvgChartView#dataproc
             * @description Data processing helpers
             * @type {object}
             */
            dataproc: {
                /**
                 * @name module:examsAvgChartView#dataproc@respDivider
                 * @description Series data formatter.
                 * Divides 1st array elements by 2nd's elements with same index
                 * @param dividends {array} Dividends array
                 * @param divisors {array} Divisors array
                 * @param range {array} Intersection indexes
                 * @param [shift] {number}
                 * @function
                 */
                respDivider: function (dividends, divisors, range, shift) {
                    shift = shift || 0;
                    var i;
                    return _.map(range, function (v, k) {
                        // undefined is not a null for Highcharts.js
                        i = dividends[v - shift];
                        return typeof i === 'number' && !isNaN(i) ?
                                i / (divisors[v - shift] || 1) :
                                null;
                    });
                }
            },
            /**
             * @name module:examsAvgChartView#update
             * @description Updates chart state by new data
             * @function
             * @param [data] {array} new data
             * @returns {object|undefined} chart.series or undefined
             */
            update: function (data) {
                // If we got the same data as rendered skip below
                // TODO: _.isEqual costs a lot for big collections. Think about it
                if (this.chart && data && !_.isEqual(this.data, data)) {
 
                    this.data = data;
 
                    var view = this,
                        min = Infinity,
                        max = -Infinity,
                        range,
                        year,
                        exam = {},
                        weight = {},
                        series = this.chart.series,
 
                    // Average math & rus exam result is shown separately
                        weightMathRus = {},
                        examMathRus = {};
 
                    // There's no way to predict exams date range.
                    // May be this value should be defined on server-side
 
                    _.each(data, function (item) {
                        // Previous API support
                        year = item.year || (new Date(item.date)).getFullYear();
                        item.year = year;
                        /* istanbul skip else */
                        if (year > max) {
                            max = year;
                        }
                        /* istanbul skip else */
                        if (year < min) {
                            min = year;
                        }
                    });
 
                    // Weighted data extraction
                    _.each(data, function (item) {
                        year = item.year - min;
                        // exam[year] is undefined by default
                        exam[year] = 100 * item.average / item.limit * item.total + (exam[year] || 0);
                        weight[year] = item.total + (weight[year] || 0);
 
                        /* istanbul skip else */
                        if (item.name === "math" || item.name === "russian") {
                            examMathRus[year] = 100 * item.average / item.limit * item.total + (examMathRus[year] || 0);
                            weightMathRus[year] = item.total + (weightMathRus[year] || 0);
                        }
                    });
 
                    // x axis range
                    range = _.range(min, max + 1);
                    // false second argument is needed to prevent useless redraw
                    series[0].update(
                        {data: this.dataproc.respDivider(exam, weight, range, min)},
                        false
                    );
                    series[1].update(
                        {data: this.dataproc.respDivider(examMathRus, weightMathRus, range, min)},
                        false
                    );
                    this.chart.xAxis[0].setCategories(range, false);
 
                    this.redraw();
                    return series;
                }
                return;
            }
        });
    });