    /** * @class Ext.sparkline.Box * Generates a box plot graph from the provided {@link #values} array. * * See <a href="http://en.wikipedia.org/wiki/Box_plot">Wikipedia Box Plots</a> * * See {@link Ext.sparkline.Base the base class} for a simple example. */Ext.define('Ext.sparkline.Box', {    extend: 'Ext.sparkline.Base',     alias: 'widget.sparklinebox',     config: {         /**         * @cfg {Boolean} [raw=false] By default the points are calculated from the input values array. Set this to true to passthe pre-calculated points in the values config.         */        raw: false,         /**         * @cfg {String} [boxLineColor=#000] The color of the box outline.         */        boxLineColor: '#000',                /**         * @cfg {String} [boxFillColor=#cdf] The color of the box fill.         */        boxFillColor: '#cdf',                /**         * @cfg {String} [whiskerColor=#000] The color of the whiskers.         */        whiskerColor: '#000',                /**         * @cfg {String} [outlierLineColor=#333] The color of the outlier circles' outline.         */        outlierLineColor: '#333',                /**         * @cfg {String} [outlierFillColor=#fff] The fill color of the outlier circles.         */        outlierFillColor: '#fff',                /**         * @cfg {String} [medianColor=#f00] The color of the median line.         */        medianColor: '#f00',                /**         * @cfg {Boolean} [showOutliers=true] Configure as `false` to not show outlier circles.         */        showOutliers: true,                /**         * @cfg {Number} [outlierIQR=1.5] The inter-quartile range multipler used to calculate values that qualify as an outlier.         */        outlierIQR: 1.5,                /**         * @cfg {Number} [spotRadius=1.5] The radius of the outlier circles.         */        spotRadius: 1.5,                /**         * @cfg {Number} [target] If set, a crosshair will be drawn at the specified value point.         */        target: null,                /**         * @cfg {Number} [targetColor=#4a2] The color of the crosshair drawn at the pointe specified by {@link #target}.         */        targetColor: '#4a2',                /**         * @cfg {Number} [chartRangeMin] The minimum value to use for the range of Y values of the chart - Defaults to the minimum value supplied.         */        chartRangeMin: null,                /**         * @cfg {Number} [chartRangeMax] The maximum value to use for the range of Y values of the chart - Defaults to the minimum value supplied.         */        chartRangeMax: null    },     tipTpl: ['{field:this.fields}: {value}', {        fields: function(v) {            var fields = {                lq: 'Lower Quartile',                med: 'Median',                uq: 'Upper Quartile',                lo: 'Left Outlier',                ro: 'Right Outlier',                lw: 'Left Whisker',                rw: 'Right Whisker'            };            return fields[v];        }    }],    tooltipFormatFieldlistKey: 'field',     quartile: function (values, q) {        var vl;        if (q === 2) {            vl = Math.floor(values.length / 2);            return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;        } else {            if (values.length % 2 ) { // odd                 vl = (values.length * q + q) / 4;                return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];            } else { //even                 vl = (values.length * q + 2) / 4;                return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 :  values[vl-1];             }        }    },     // Ensure values is an array of numbers     applyValues: function(newValues) {        newValues = Ext.Array.map(Ext.Array.from(newValues), Number);        this.disabled = !(newValues && newValues.length);        this.applyConfigChange();        return newValues;    },     /*     * Simulate a single region     */    getRegion: function () {        return 1;    },     getRegionFields: function () {        var result = [            { field: 'lq', value: this.quartiles[0] },            { field: 'med', value: this.quartiles[1] },            { field: 'uq', value: this.quartiles[2] }        ];        if (this.loutlier !== undefined) {            result.push({ field: 'lo', value: this.loutlier});        }        if (this.routlier !== undefined) {            result.push({ field: 'ro', value: this.routlier});        }        if (this.lwhisker !== undefined) {            result.push({ field: 'lw', value: this.lwhisker});        }        if (this.rwhisker !== undefined) {            result.push({ field: 'rw', value: this.rwhisker});        }        return result;    },     renderHighlight: Ext.emptyFn,     renderGraph: function () {        var me = this,            canvas = me.canvas,            values = me.values,            vlen = values.length,            canvasWidth = me.getWidth(),            canvasHeight = me.getHeight(),            chartRangeMin = me.getChartRangeMin(),            chartRangeMax = me.getChartRangeMax(),            minValue = chartRangeMin == null ? Math.min.apply(Math, values) : chartRangeMin,            maxValue = chartRangeMax == null ? Math.max.apply(Math, values) : chartRangeMax,            canvasLeft = 0,            lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,            size, unitSize,            spotRadius = me.getSpotRadius(),            outlierLineColor = me.getOutlierLineColor(),            outlierFillColor = me.getOutlierFillColor(),            showOutliers = me.getShowOutliers(),            outlierIQR = me.getOutlierIQR(),            lineColor = me.getLineColor(),            whiskerColor = me.getWhiskerColor(),            targetColor = me.getTargetColor();         if (!me.callParent()) {            return;        }         if (me.raw) {            if (showOutliers && values.length > 5) {                loutlier = values[0];                lwhisker = values[1];                q1 = values[2];                q2 = values[3];                q3 = values[4];                rwhisker = values[5];                routlier = values[6];            } else {                lwhisker = values[0];                q1 = values[1];                q2 = values[2];                q3 = values[3];                rwhisker = values[4];            }        } else {            values.sort(function (a, b) { return a - b; });            q1 = me.quartile(values, 1);            q2 = me.quartile(values, 2);            q3 = me.quartile(values, 3);            iqr = q3 - q1;            if (showOutliers) {                lwhisker = rwhisker = null;                for (i = 0; i < vlen; i++) {                    if (lwhisker == null && values[i] > q1 - (iqr * outlierIQR)) {                        lwhisker = values[i];                    }                    if (values[i] < q3 + (iqr * outlierIQR)) {                        rwhisker = values[i];                    }                }                loutlier = values[0];                routlier = values[vlen - 1];            } else {                lwhisker = values[0];                rwhisker = values[vlen - 1];            }        }        me.quartiles = [q1, q2, q3];        me.lwhisker = lwhisker;        me.rwhisker = rwhisker;        me.loutlier = loutlier;        me.routlier = routlier;         unitSize = canvasWidth / (maxValue - minValue + 1);        if (showOutliers) {            canvasLeft = Math.ceil(spotRadius);            canvasWidth -= 2 * Math.ceil(spotRadius);            unitSize = canvasWidth / (maxValue - minValue + 1);            if (loutlier < lwhisker) {                canvas.drawCircle((loutlier - minValue) * unitSize + canvasLeft,                    canvasHeight / 2,                    spotRadius,                    outlierLineColor,                    outlierFillColor).append();            }            if (routlier > rwhisker) {                canvas.drawCircle((routlier - minValue) * unitSize + canvasLeft,                    canvasHeight / 2,                    spotRadius,                    outlierLineColor,                    outlierFillColor).append();            }        }         // box         canvas.drawRect(            Math.round((q1 - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight * 0.1),            Math.round((q3 - q1) * unitSize),            Math.round(canvasHeight * 0.8),            me.getBoxLineColor(),            me.getBoxFillColor()).append();        // left whisker         canvas.drawLine(            Math.round((lwhisker - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight / 2),            Math.round((q1 - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight / 2),            lineColor).append();        canvas.drawLine(            Math.round((lwhisker - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight / 4),            Math.round((lwhisker - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight - canvasHeight / 4),            whiskerColor).append();        // right whisker         canvas.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight / 2),            Math.round((q3 - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight / 2),            lineColor).append();        canvas.drawLine(            Math.round((rwhisker - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight / 4),            Math.round((rwhisker - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight - canvasHeight / 4),            whiskerColor).append();        // median line         canvas.drawLine(            Math.round((q2 - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight * 0.1),            Math.round((q2 - minValue) * unitSize + canvasLeft),            Math.round(canvasHeight * 0.9),            me.getMedianColor()).append();        if (me.target) {            size = Math.ceil(me.spotRadius);            canvas.drawLine(                Math.round((me.target - minValue) * unitSize + canvasLeft),                Math.round((canvasHeight / 2) - size),                Math.round((me.target - minValue) * unitSize + canvasLeft),                Math.round((canvasHeight / 2) + size),                targetColor).append();            canvas.drawLine(                Math.round((me.target - minValue) * unitSize + canvasLeft - size),                Math.round(canvasHeight / 2),                Math.round((me.target - minValue) * unitSize + canvasLeft + size),                Math.round(canvasHeight / 2),                targetColor).append();        }         // If mouse is over, re-apply the highlight         if (me.currentPageXY && me.el.getRegion().contains(me.currentPageXY)) {            me.currentRegion = null;            me.updateDisplay();        }        canvas.render();    }});