]> git.sesse.net Git - remoteglot/blobdiff - www/js/jquery.sparkline.js
Remove some chart types we don't need; kills 16 kb off the minified (non-gzipped...
[remoteglot] / www / js / jquery.sparkline.js
index 721e03b76b9b7bca11c25552f3aeae17abe87773..e1caac9155f5c38d3983002e137d6a7014fbbf19 100644 (file)
 *    <p>Sparkline: <span class="sparkline" values="1,4,6,6,8,5,3,5"></span></p>
 *    $('.sparkline').sparkline();
 *
-* For line charts, x values can also be specified:
-*   <p>Sparkline: <span class="sparkline">1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5</span></p>
-*    $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])
-*
 * By default, options should be passed in as teh second argument to the sparkline function:
 *   $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})
 *
 *   numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to "."
 *   numberDigitGroupCount - Number of digits between group separator - Defaults to 3
 *
-* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default),
-* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'
-*    line - Line chart.  Options:
-*       spotColor - Set to '' to not end each line in a circular spot
-*       minSpotColor - If set, color of spot at minimum value
-*       maxSpotColor - If set, color of spot at maximum value
-*       spotRadius - Radius in pixels
-*       lineWidth - Width of line in pixels
-*       normalRangeMin
-*       normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal"
-*                      or expected range of values
-*       normalRangeColor - Color to use for the above bar
-*       drawNormalOnTop - Draw the normal range above the chart fill color if true
-*       defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart
-*       highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable
-*       highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable
-*       valueSpots - Specify which points to draw spots on, and in which color.  Accepts a range map
+* There is 1 type of sparkline, selected by supplying a "type" option of 'bar' (default),
 *
 *   bar - Bar chart.  Options:
 *       barColor - Color of bars for postive values
 *       barSpacing - Gap between bars in pixels
 *       zeroAxis - Centers the y-axis around zero if true
 *
-*   tristate - Charts values of win (>0), lose (<0) or draw (=0)
-*       posBarColor - Color of win values
-*       negBarColor - Color of lose values
-*       zeroBarColor - Color of draw values
-*       barWidth - Width of bars in pixels
-*       barSpacing - Gap between bars in pixels
-*       colorMap - Optional mappnig of values to colors to override the *BarColor values above
-*                  can be an Array of values to control the color of individual bars or a range map
-*                  to specify colors for individual ranges of values
-*
-*   discrete - Options:
-*       lineHeight - Height of each line in pixels - Defaults to 30% of the graph height
-*       thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor
-*       thresholdColor
-*
-*   bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...
-*       options:
-*       targetColor - The color of the vertical target marker
-*       targetWidth - The width of the target marker in pixels
-*       performanceColor - The color of the performance measure horizontal bar
-*       rangeColors - Colors to use for each qualitative range background color
 *
-*   pie - Pie chart. Options:
-*       sliceColors - An array of colors to use for pie slices
-*       offset - Angle in degrees to offset the first slice - Try -90 or +90
-*       borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)
-*       borderColor - Color to use for the pie chart border - Defaults to #000
 *
-*   box - Box plot. Options:
-*       raw - Set to true to supply pre-computed plot points as values
-*             values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier
-*             When set to false you can supply any number of values and the box plot will
-*             be computed for you.  Default is false.
-*       showOutliers - Set to true (default) to display outliers as circles
-*       outlierIQR - Interquartile range used to determine outliers.  Default 1.5
-*       boxLineColor - Outline color of the box
-*       boxFillColor - Fill color for the box
-*       whiskerColor - Line color used for whiskers
-*       outlierLineColor - Outline color of outlier circles
-*       outlierFillColor - Fill color of the outlier circles
-*       spotRadius - Radius of outlier circles
-*       medianColor - Line color of the median line
-*       target - Draw a target cross hair at the supplied value (default undefined)
 *
 *
 *
 *   Examples:
 *   $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });
 *   $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });
-*   $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):
-*   $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });
-*   $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });
-*   $('#pie').sparkline([1,1,2], { type:'pie' });
 */
 
 /*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
         getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,
         remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,
         MouseHandler, Tooltip, barHighlightMixin,
-        line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,
+        bar, defaultStyles, initStyles,
         VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
 
     /**
         return {
             // Settings common to most/all chart types
             common: {
-                type: 'line',
+                type: 'bar',
                 lineColor: '#00f',
                 fillColor: '#cdf',
                 defaultPixelsPerValue: 3,
                 disableTooltips: false,
                 disableInteraction: false
             },
-            // Defaults for line charts
-            line: {
-                spotColor: '#f80',
-                highlightSpotColor: '#5f5',
-                highlightLineColor: '#f22',
-                spotRadius: 1.5,
-                minSpotColor: '#f80',
-                maxSpotColor: '#f80',
-                lineWidth: 1,
-                normalRangeMin: undefined,
-                normalRangeMax: undefined,
-                normalRangeColor: '#ccc',
-                drawNormalOnTop: false,
-                chartRangeMin: undefined,
-                chartRangeMax: undefined,
-                chartRangeMinX: undefined,
-                chartRangeMaxX: undefined,
-                tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{y}}{{suffix}}')
-            },
             // Defaults for bar charts
             bar: {
                 barColor: '#3366cc',
                 colorMap: undefined,
                 tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{value}}{{suffix}}')
             },
-            // Defaults for tristate charts
-            tristate: {
-                barWidth: 4,
-                barSpacing: 1,
-                posBarColor: '#6f6',
-                negBarColor: '#f44',
-                zeroBarColor: '#999',
-                colorMap: {},
-                tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value:map}}'),
-                tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }
-            },
-            // Defaults for discrete charts
-            discrete: {
-                lineHeight: 'auto',
-                thresholdColor: undefined,
-                thresholdValue: 0,
-                chartRangeMax: undefined,
-                chartRangeMin: undefined,
-                chartRangeClip: false,
-                tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')
-            },
-            // Defaults for bullet charts
-            bullet: {
-                targetColor: '#f33',
-                targetWidth: 3, // width of the target bar in pixels
-                performanceColor: '#33f',
-                rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],
-                base: undefined, // set this to a number to change the base start number
-                tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),
-                tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }
-            },
-            // Defaults for pie charts
-            pie: {
-                offset: 0,
-                sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
-                    '#dd4477', '#0099c6', '#990099'],
-                borderWidth: 0,
-                borderColor: '#000',
-                tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value}} ({{percent.1}}%)')
-            },
-            // Defaults for box plots
-            box: {
-                raw: false,
-                boxLineColor: '#000',
-                boxFillColor: '#cdf',
-                whiskerColor: '#000',
-                outlierLineColor: '#333',
-                outlierFillColor: '#fff',
-                medianColor: '#f00',
-                showOutliers: true,
-                outlierIQR: 1.5,
-                spotRadius: 1.5,
-                target: undefined,
-                targetColor: '#4a2',
-                chartRangeMax: undefined,
-                chartRangeMin: undefined,
-                tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),
-                tooltipFormatFieldlistKey: 'field',
-                tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',
-                    uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',
-                    lw: 'Left Whisker', rw: 'Right Whisker'} }
-            }
         };
     };
 
         }
     };
 
-    /**
-     * Line charts
-     */
-    $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {
-        type: 'line',
-
-        init: function (el, values, options, width, height) {
-            line._super.init.call(this, el, values, options, width, height);
-            this.vertices = [];
-            this.regionMap = [];
-            this.xvalues = [];
-            this.yvalues = [];
-            this.yminmax = [];
-            this.hightlightSpotId = null;
-            this.lastShapeId = null;
-            this.initTarget();
-        },
-
-        getRegion: function (el, x, y) {
-            var i,
-                regionMap = this.regionMap; // maps regions to value positions
-            for (i = regionMap.length; i--;) {
-                if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
-                    return regionMap[i][2];
-                }
-            }
-            return undefined;
-        },
-
-        getCurrentRegionFields: function () {
-            var currentRegion = this.currentRegion;
-            return {
-                isNull: this.yvalues[currentRegion] === null,
-                x: this.xvalues[currentRegion],
-                y: this.yvalues[currentRegion],
-                color: this.options.get('lineColor'),
-                fillColor: this.options.get('fillColor'),
-                offset: currentRegion
-            };
-        },
-
-        renderHighlight: function () {
-            var currentRegion = this.currentRegion,
-                target = this.target,
-                vertex = this.vertices[currentRegion],
-                options = this.options,
-                spotRadius = options.get('spotRadius'),
-                highlightSpotColor = options.get('highlightSpotColor'),
-                highlightLineColor = options.get('highlightLineColor'),
-                highlightSpot, highlightLine;
-
-            if (!vertex) {
-                return;
-            }
-            if (spotRadius && highlightSpotColor) {
-                highlightSpot = target.drawCircle(vertex[0], vertex[1],
-                    spotRadius, undefined, highlightSpotColor);
-                this.highlightSpotId = highlightSpot.id;
-                target.insertAfterShape(this.lastShapeId, highlightSpot);
-            }
-            if (highlightLineColor) {
-                highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],
-                    this.canvasTop + this.canvasHeight, highlightLineColor);
-                this.highlightLineId = highlightLine.id;
-                target.insertAfterShape(this.lastShapeId, highlightLine);
-            }
-        },
-
-        removeHighlight: function () {
-            var target = this.target;
-            if (this.highlightSpotId) {
-                target.removeShapeId(this.highlightSpotId);
-                this.highlightSpotId = null;
-            }
-            if (this.highlightLineId) {
-                target.removeShapeId(this.highlightLineId);
-                this.highlightLineId = null;
-            }
-        },
-
-        scanValues: function () {
-            var values = this.values,
-                valcount = values.length,
-                xvalues = this.xvalues,
-                yvalues = this.yvalues,
-                yminmax = this.yminmax,
-                i, val, isStr, isArray, sp;
-            for (i = 0; i < valcount; i++) {
-                val = values[i];
-                isStr = typeof(values[i]) === 'string';
-                isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;
-                sp = isStr && values[i].split(':');
-                if (isStr && sp.length === 2) { // x:y
-                    xvalues.push(Number(sp[0]));
-                    yvalues.push(Number(sp[1]));
-                    yminmax.push(Number(sp[1]));
-                } else if (isArray) {
-                    xvalues.push(val[0]);
-                    yvalues.push(val[1]);
-                    yminmax.push(val[1]);
-                } else {
-                    xvalues.push(i);
-                    if (values[i] === null || values[i] === 'null') {
-                        yvalues.push(null);
-                    } else {
-                        yvalues.push(Number(val));
-                        yminmax.push(Number(val));
-                    }
-                }
-            }
-            if (this.options.get('xvalues')) {
-                xvalues = this.options.get('xvalues');
-            }
-
-            this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);
-            this.miny = this.minyorg = Math.min.apply(Math, yminmax);
-
-            this.maxx = Math.max.apply(Math, xvalues);
-            this.minx = Math.min.apply(Math, xvalues);
-
-            this.xvalues = xvalues;
-            this.yvalues = yvalues;
-            this.yminmax = yminmax;
-
-        },
-
-        processRangeOptions: function () {
-            var options = this.options,
-                normalRangeMin = options.get('normalRangeMin'),
-                normalRangeMax = options.get('normalRangeMax');
-
-            if (normalRangeMin !== undefined) {
-                if (normalRangeMin < this.miny) {
-                    this.miny = normalRangeMin;
-                }
-                if (normalRangeMax > this.maxy) {
-                    this.maxy = normalRangeMax;
-                }
-            }
-            if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {
-                this.miny = options.get('chartRangeMin');
-            }
-            if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {
-                this.maxy = options.get('chartRangeMax');
-            }
-            if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {
-                this.minx = options.get('chartRangeMinX');
-            }
-            if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {
-                this.maxx = options.get('chartRangeMaxX');
-            }
-
-        },
-
-        drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
-            var normalRangeMin = this.options.get('normalRangeMin'),
-                normalRangeMax = this.options.get('normalRangeMax'),
-                ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),
-                height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);
-            this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();
-        },
-
-        render: function () {
-            var options = this.options,
-                target = this.target,
-                canvasWidth = this.canvasWidth,
-                canvasHeight = this.canvasHeight,
-                vertices = this.vertices,
-                spotRadius = options.get('spotRadius'),
-                regionMap = this.regionMap,
-                rangex, rangey, yvallast,
-                canvasTop, canvasLeft,
-                vertex, path, paths, x, y, xnext, xpos, xposnext,
-                last, next, yvalcount, lineShapes, fillShapes, plen,
-                valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
-
-            if (!line._super.render.call(this)) {
-                return;
-            }
-
-            this.scanValues();
-            this.processRangeOptions();
-
-            xvalues = this.xvalues;
-            yvalues = this.yvalues;
-
-            if (!this.yminmax.length || this.yvalues.length < 2) {
-                // empty or all null valuess
-                return;
-            }
-
-            canvasTop = canvasLeft = 0;
-
-            rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
-            rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
-            yvallast = this.yvalues.length - 1;
-
-            if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {
-                spotRadius = 0;
-            }
-            if (spotRadius) {
-                // adjust the canvas size as required so that spots will fit
-                hlSpotsEnabled = options.get('highlightSpotColor') &&  !options.get('disableInteraction');
-                if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {
-                    canvasHeight -= Math.ceil(spotRadius);
-                }
-                if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {
-                    canvasHeight -= Math.ceil(spotRadius);
-                    canvasTop += Math.ceil(spotRadius);
-                }
-                if (hlSpotsEnabled ||
-                     ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {
-                    canvasLeft += Math.ceil(spotRadius);
-                    canvasWidth -= Math.ceil(spotRadius);
-                }
-                if (hlSpotsEnabled || options.get('spotColor') ||
-                    (options.get('minSpotColor') || options.get('maxSpotColor') &&
-                        (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
-                    canvasWidth -= Math.ceil(spotRadius);
-                }
-            }
-
-
-            canvasHeight--;
-
-            if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {
-                this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
-            }
-
-            path = [];
-            paths = [path];
-            last = next = null;
-            yvalcount = yvalues.length;
-            for (i = 0; i < yvalcount; i++) {
-                x = xvalues[i];
-                xnext = xvalues[i + 1];
-                y = yvalues[i];
-                xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));
-                xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
-                next = xpos + ((xposnext - xpos) / 2);
-                regionMap[i] = [last || 0, next, i];
-                last = next;
-                if (y === null) {
-                    if (i) {
-                        if (yvalues[i - 1] !== null) {
-                            path = [];
-                            paths.push(path);
-                        }
-                        vertices.push(null);
-                    }
-                } else {
-                    if (y < this.miny) {
-                        y = this.miny;
-                    }
-                    if (y > this.maxy) {
-                        y = this.maxy;
-                    }
-                    if (!path.length) {
-                        // previous value was null
-                        path.push([xpos, canvasTop + canvasHeight]);
-                    }
-                    vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];
-                    path.push(vertex);
-                    vertices.push(vertex);
-                }
-            }
-
-            lineShapes = [];
-            fillShapes = [];
-            plen = paths.length;
-            for (i = 0; i < plen; i++) {
-                path = paths[i];
-                if (path.length) {
-                    if (options.get('fillColor')) {
-                        path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);
-                        fillShapes.push(path.slice(0));
-                        path.pop();
-                    }
-                    // if there's only a single point in this path, then we want to display it
-                    // as a vertical line which means we keep path[0]  as is
-                    if (path.length > 2) {
-                        // else we want the first value
-                        path[0] = [path[0][0], path[1][1]];
-                    }
-                    lineShapes.push(path);
-                }
-            }
-
-            // draw the fill first, then optionally the normal range, then the line on top of that
-            plen = fillShapes.length;
-            for (i = 0; i < plen; i++) {
-                target.drawShape(fillShapes[i],
-                    options.get('fillColor'), options.get('fillColor')).append();
-            }
-
-            if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {
-                this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
-            }
-
-            plen = lineShapes.length;
-            for (i = 0; i < plen; i++) {
-                target.drawShape(lineShapes[i], options.get('lineColor'), undefined,
-                    options.get('lineWidth')).append();
-            }
-
-            if (spotRadius && options.get('valueSpots')) {
-                valueSpots = options.get('valueSpots');
-                if (valueSpots.get === undefined) {
-                    valueSpots = new RangeMap(valueSpots);
-                }
-                for (i = 0; i < yvalcount; i++) {
-                    color = valueSpots.get(yvalues[i]);
-                    if (color) {
-                        target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
-                            canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),
-                            spotRadius, undefined,
-                            color).append();
-                    }
-                }
-
-            }
-            if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {
-                target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
-                    canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),
-                    spotRadius, undefined,
-                    options.get('spotColor')).append();
-            }
-            if (this.maxy !== this.minyorg) {
-                if (spotRadius && options.get('minSpotColor')) {
-                    x = xvalues[$.inArray(this.minyorg, yvalues)];
-                    target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
-                        canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),
-                        spotRadius, undefined,
-                        options.get('minSpotColor')).append();
-                }
-                if (spotRadius && options.get('maxSpotColor')) {
-                    x = xvalues[$.inArray(this.maxyorg, yvalues)];
-                    target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
-                        canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),
-                        spotRadius, undefined,
-                        options.get('maxSpotColor')).append();
-                }
-            }
-
-            this.lastShapeId = target.getLastShapeId();
-            this.canvasTop = canvasTop;
-            target.render();
-        }
-    });
-
     /**
      * Bar charts
      */
         }
     });
 
-    /**
-     * Tristate charts
-     */
-    $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {
-        type: 'tristate',
-
-        init: function (el, values, options, width, height) {
-            var barWidth = parseInt(options.get('barWidth'), 10),
-                barSpacing = parseInt(options.get('barSpacing'), 10);
-            tristate._super.init.call(this, el, values, options, width, height);
-
-            this.regionShapes = {};
-            this.barWidth = barWidth;
-            this.barSpacing = barSpacing;
-            this.totalBarWidth = barWidth + barSpacing;
-            this.values = $.map(values, Number);
-            this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
-
-            if ($.isArray(options.get('colorMap'))) {
-                this.colorMapByIndex = options.get('colorMap');
-                this.colorMapByValue = null;
-            } else {
-                this.colorMapByIndex = null;
-                this.colorMapByValue = options.get('colorMap');
-                if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
-                    this.colorMapByValue = new RangeMap(this.colorMapByValue);
-                }
-            }
-            this.initTarget();
-        },
-
-        getRegion: function (el, x, y) {
-            return Math.floor(x / this.totalBarWidth);
-        },
-
-        getCurrentRegionFields: function () {
-            var currentRegion = this.currentRegion;
-            return {
-                isNull: this.values[currentRegion] === undefined,
-                value: this.values[currentRegion],
-                color: this.calcColor(this.values[currentRegion], currentRegion),
-                offset: currentRegion
-            };
-        },
-
-        calcColor: function (value, valuenum) {
-            var values = this.values,
-                options = this.options,
-                colorMapByIndex = this.colorMapByIndex,
-                colorMapByValue = this.colorMapByValue,
-                color, newColor;
-
-            if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
-                color = newColor;
-            } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
-                color = colorMapByIndex[valuenum];
-            } else if (values[valuenum] < 0) {
-                color = options.get('negBarColor');
-            } else if (values[valuenum] > 0) {
-                color = options.get('posBarColor');
-            } else {
-                color = options.get('zeroBarColor');
-            }
-            return color;
-        },
-
-        renderRegion: function (valuenum, highlight) {
-            var values = this.values,
-                options = this.options,
-                target = this.target,
-                canvasHeight, height, halfHeight,
-                x, y, color;
-
-            canvasHeight = target.pixelHeight;
-            halfHeight = Math.round(canvasHeight / 2);
-
-            x = valuenum * this.totalBarWidth;
-            if (values[valuenum] < 0) {
-                y = halfHeight;
-                height = halfHeight - 1;
-            } else if (values[valuenum] > 0) {
-                y = 0;
-                height = halfHeight - 1;
-            } else {
-                y = halfHeight - 1;
-                height = 2;
-            }
-            color = this.calcColor(values[valuenum], valuenum);
-            if (color === null) {
-                return;
-            }
-            if (highlight) {
-                color = this.calcHighlightColor(color, options);
-            }
-            return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
-        }
-    });
-
-    /**
-     * Discrete charts
-     */
-    $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {
-        type: 'discrete',
-
-        init: function (el, values, options, width, height) {
-            discrete._super.init.call(this, el, values, options, width, height);
-
-            this.regionShapes = {};
-            this.values = values = $.map(values, Number);
-            this.min = Math.min.apply(Math, values);
-            this.max = Math.max.apply(Math, values);
-            this.range = this.max - this.min;
-            this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;
-            this.interval = Math.floor(width / values.length);
-            this.itemWidth = width / values.length;
-            if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {
-                this.min = options.get('chartRangeMin');
-            }
-            if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {
-                this.max = options.get('chartRangeMax');
-            }
-            this.initTarget();
-            if (this.target) {
-                this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');
-            }
-        },
-
-        getRegion: function (el, x, y) {
-            return Math.floor(x / this.itemWidth);
-        },
-
-        getCurrentRegionFields: function () {
-            var currentRegion = this.currentRegion;
-            return {
-                isNull: this.values[currentRegion] === undefined,
-                value: this.values[currentRegion],
-                offset: currentRegion
-            };
-        },
-
-        renderRegion: function (valuenum, highlight) {
-            var values = this.values,
-                options = this.options,
-                min = this.min,
-                max = this.max,
-                range = this.range,
-                interval = this.interval,
-                target = this.target,
-                canvasHeight = this.canvasHeight,
-                lineHeight = this.lineHeight,
-                pheight = canvasHeight - lineHeight,
-                ytop, val, color, x;
-
-            val = clipval(values[valuenum], min, max);
-            x = valuenum * interval;
-            ytop = Math.round(pheight - pheight * ((val - min) / range));
-            color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');
-            if (highlight) {
-                color = this.calcHighlightColor(color, options);
-            }
-            return target.drawLine(x, ytop, x, ytop + lineHeight, color);
-        }
-    });
-
-    /**
-     * Bullet charts
-     */
-    $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {
-        type: 'bullet',
-
-        init: function (el, values, options, width, height) {
-            var min, max, vals;
-            bullet._super.init.call(this, el, values, options, width, height);
-
-            // values: target, performance, range1, range2, range3
-            this.values = values = normalizeValues(values);
-            // target or performance could be null
-            vals = values.slice();
-            vals[0] = vals[0] === null ? vals[2] : vals[0];
-            vals[1] = values[1] === null ? vals[2] : vals[1];
-            min = Math.min.apply(Math, values);
-            max = Math.max.apply(Math, values);
-            if (options.get('base') === undefined) {
-                min = min < 0 ? min : 0;
-            } else {
-                min = options.get('base');
-            }
-            this.min = min;
-            this.max = max;
-            this.range = max - min;
-            this.shapes = {};
-            this.valueShapes = {};
-            this.regiondata = {};
-            this.width = width = options.get('width') === 'auto' ? '4.0em' : width;
-            this.target = this.$el.simpledraw(width, height, options.get('composite'));
-            if (!values.length) {
-                this.disabled = true;
-            }
-            this.initTarget();
-        },
-
-        getRegion: function (el, x, y) {
-            var shapeid = this.target.getShapeAt(el, x, y);
-            return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
-        },
-
-        getCurrentRegionFields: function () {
-            var currentRegion = this.currentRegion;
-            return {
-                fieldkey: currentRegion.substr(0, 1),
-                value: this.values[currentRegion.substr(1)],
-                region: currentRegion
-            };
-        },
-
-        changeHighlight: function (highlight) {
-            var currentRegion = this.currentRegion,
-                shapeid = this.valueShapes[currentRegion],
-                shape;
-            delete this.shapes[shapeid];
-            switch (currentRegion.substr(0, 1)) {
-                case 'r':
-                    shape = this.renderRange(currentRegion.substr(1), highlight);
-                    break;
-                case 'p':
-                    shape = this.renderPerformance(highlight);
-                    break;
-                case 't':
-                    shape = this.renderTarget(highlight);
-                    break;
-            }
-            this.valueShapes[currentRegion] = shape.id;
-            this.shapes[shape.id] = currentRegion;
-            this.target.replaceWithShape(shapeid, shape);
-        },
-
-        renderRange: function (rn, highlight) {
-            var rangeval = this.values[rn],
-                rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),
-                color = this.options.get('rangeColors')[rn - 2];
-            if (highlight) {
-                color = this.calcHighlightColor(color, this.options);
-            }
-            return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
-        },
-
-        renderPerformance: function (highlight) {
-            var perfval = this.values[1],
-                perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),
-                color = this.options.get('performanceColor');
-            if (highlight) {
-                color = this.calcHighlightColor(color, this.options);
-            }
-            return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,
-                Math.round(this.canvasHeight * 0.4) - 1, color, color);
-        },
-
-        renderTarget: function (highlight) {
-            var targetval = this.values[0],
-                x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),
-                targettop = Math.round(this.canvasHeight * 0.10),
-                targetheight = this.canvasHeight - (targettop * 2),
-                color = this.options.get('targetColor');
-            if (highlight) {
-                color = this.calcHighlightColor(color, this.options);
-            }
-            return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);
-        },
-
-        render: function () {
-            var vlen = this.values.length,
-                target = this.target,
-                i, shape;
-            if (!bullet._super.render.call(this)) {
-                return;
-            }
-            for (i = 2; i < vlen; i++) {
-                shape = this.renderRange(i).append();
-                this.shapes[shape.id] = 'r' + i;
-                this.valueShapes['r' + i] = shape.id;
-            }
-            if (this.values[1] !== null) {
-                shape = this.renderPerformance().append();
-                this.shapes[shape.id] = 'p1';
-                this.valueShapes.p1 = shape.id;
-            }
-            if (this.values[0] !== null) {
-                shape = this.renderTarget().append();
-                this.shapes[shape.id] = 't0';
-                this.valueShapes.t0 = shape.id;
-            }
-            target.render();
-        }
-    });
-
-    /**
-     * Pie charts
-     */
-    $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {
-        type: 'pie',
-
-        init: function (el, values, options, width, height) {
-            var total = 0, i;
-
-            pie._super.init.call(this, el, values, options, width, height);
-
-            this.shapes = {}; // map shape ids to value offsets
-            this.valueShapes = {}; // maps value offsets to shape ids
-            this.values = values = $.map(values, Number);
-
-            if (options.get('width') === 'auto') {
-                this.width = this.height;
-            }
-
-            if (values.length > 0) {
-                for (i = values.length; i--;) {
-                    total += values[i];
-                }
-            }
-            this.total = total;
-            this.initTarget();
-            this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);
-        },
-
-        getRegion: function (el, x, y) {
-            var shapeid = this.target.getShapeAt(el, x, y);
-            return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
-        },
-
-        getCurrentRegionFields: function () {
-            var currentRegion = this.currentRegion;
-            return {
-                isNull: this.values[currentRegion] === undefined,
-                value: this.values[currentRegion],
-                percent: this.values[currentRegion] / this.total * 100,
-                color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],
-                offset: currentRegion
-            };
-        },
-
-        changeHighlight: function (highlight) {
-            var currentRegion = this.currentRegion,
-                 newslice = this.renderSlice(currentRegion, highlight),
-                 shapeid = this.valueShapes[currentRegion];
-            delete this.shapes[shapeid];
-            this.target.replaceWithShape(shapeid, newslice);
-            this.valueShapes[currentRegion] = newslice.id;
-            this.shapes[newslice.id] = currentRegion;
-        },
-
-        renderSlice: function (valuenum, highlight) {
-            var target = this.target,
-                options = this.options,
-                radius = this.radius,
-                borderWidth = options.get('borderWidth'),
-                offset = options.get('offset'),
-                circle = 2 * Math.PI,
-                values = this.values,
-                total = this.total,
-                next = offset ? (2*Math.PI)*(offset/360) : 0,
-                start, end, i, vlen, color;
-
-            vlen = values.length;
-            for (i = 0; i < vlen; i++) {
-                start = next;
-                end = next;
-                if (total > 0) {  // avoid divide by zero
-                    end = next + (circle * (values[i] / total));
-                }
-                if (valuenum === i) {
-                    color = options.get('sliceColors')[i % options.get('sliceColors').length];
-                    if (highlight) {
-                        color = this.calcHighlightColor(color, options);
-                    }
-
-                    return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);
-                }
-                next = end;
-            }
-        },
-
-        render: function () {
-            var target = this.target,
-                values = this.values,
-                options = this.options,
-                radius = this.radius,
-                borderWidth = options.get('borderWidth'),
-                shape, i;
-
-            if (!pie._super.render.call(this)) {
-                return;
-            }
-            if (borderWidth) {
-                target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),
-                    options.get('borderColor'), undefined, borderWidth).append();
-            }
-            for (i = values.length; i--;) {
-                if (values[i]) { // don't render zero values
-                    shape = this.renderSlice(i).append();
-                    this.valueShapes[i] = shape.id; // store just the shapeid
-                    this.shapes[shape.id] = i;
-                }
-            }
-            target.render();
-        }
-    });
-
-    /**
-     * Box plots
-     */
-    $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {
-        type: 'box',
-
-        init: function (el, values, options, width, height) {
-            box._super.init.call(this, el, values, options, width, height);
-            this.values = $.map(values, Number);
-            this.width = options.get('width') === 'auto' ? '4.0em' : width;
-            this.initTarget();
-            if (!this.values.length) {
-                this.disabled = 1;
-            }
-        },
-
-        /**
-         * Simulate a single region
-         */
-        getRegion: function () {
-            return 1;
-        },
-
-        getCurrentRegionFields: 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;
-        },
-
-        render: function () {
-            var target = this.target,
-                values = this.values,
-                vlen = values.length,
-                options = this.options,
-                canvasWidth = this.canvasWidth,
-                canvasHeight = this.canvasHeight,
-                minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),
-                maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),
-                canvasLeft = 0,
-                lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,
-                size, unitSize;
-
-            if (!box._super.render.call(this)) {
-                return;
-            }
-
-            if (options.get('raw')) {
-                if (options.get('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 = quartile(values, 1);
-                q2 = quartile(values, 2);
-                q3 = quartile(values, 3);
-                iqr = q3 - q1;
-                if (options.get('showOutliers')) {
-                    lwhisker = rwhisker = undefined;
-                    for (i = 0; i < vlen; i++) {
-                        if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {
-                            lwhisker = values[i];
-                        }
-                        if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {
-                            rwhisker = values[i];
-                        }
-                    }
-                    loutlier = values[0];
-                    routlier = values[vlen - 1];
-                } else {
-                    lwhisker = values[0];
-                    rwhisker = values[vlen - 1];
-                }
-            }
-            this.quartiles = [q1, q2, q3];
-            this.lwhisker = lwhisker;
-            this.rwhisker = rwhisker;
-            this.loutlier = loutlier;
-            this.routlier = routlier;
-
-            unitSize = canvasWidth / (maxValue - minValue + 1);
-            if (options.get('showOutliers')) {
-                canvasLeft = Math.ceil(options.get('spotRadius'));
-                canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));
-                unitSize = canvasWidth / (maxValue - minValue + 1);
-                if (loutlier < lwhisker) {
-                    target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,
-                        canvasHeight / 2,
-                        options.get('spotRadius'),
-                        options.get('outlierLineColor'),
-                        options.get('outlierFillColor')).append();
-                }
-                if (routlier > rwhisker) {
-                    target.drawCircle((routlier - minValue) * unitSize + canvasLeft,
-                        canvasHeight / 2,
-                        options.get('spotRadius'),
-                        options.get('outlierLineColor'),
-                        options.get('outlierFillColor')).append();
-                }
-            }
-
-            // box
-            target.drawRect(
-                Math.round((q1 - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight * 0.1),
-                Math.round((q3 - q1) * unitSize),
-                Math.round(canvasHeight * 0.8),
-                options.get('boxLineColor'),
-                options.get('boxFillColor')).append();
-            // left whisker
-            target.drawLine(
-                Math.round((lwhisker - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight / 2),
-                Math.round((q1 - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight / 2),
-                options.get('lineColor')).append();
-            target.drawLine(
-                Math.round((lwhisker - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight / 4),
-                Math.round((lwhisker - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight - canvasHeight / 4),
-                options.get('whiskerColor')).append();
-            // right whisker
-            target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight / 2),
-                Math.round((q3 - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight / 2),
-                options.get('lineColor')).append();
-            target.drawLine(
-                Math.round((rwhisker - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight / 4),
-                Math.round((rwhisker - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight - canvasHeight / 4),
-                options.get('whiskerColor')).append();
-            // median line
-            target.drawLine(
-                Math.round((q2 - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight * 0.1),
-                Math.round((q2 - minValue) * unitSize + canvasLeft),
-                Math.round(canvasHeight * 0.9),
-                options.get('medianColor')).append();
-            if (options.get('target')) {
-                size = Math.ceil(options.get('spotRadius'));
-                target.drawLine(
-                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
-                    Math.round((canvasHeight / 2) - size),
-                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
-                    Math.round((canvasHeight / 2) + size),
-                    options.get('targetColor')).append();
-                target.drawLine(
-                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),
-                    Math.round(canvasHeight / 2),
-                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),
-                    Math.round(canvasHeight / 2),
-                    options.get('targetColor')).append();
-            }
-            target.render();
-        }
-    });
-
     // Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
     // This is accessible as $(foo).simpledraw()