X-Git-Url: https://git.sesse.net/?p=remoteglot;a=blobdiff_plain;f=www%2Fjs%2Fjquery.sparkline.js;h=e1caac9155f5c38d3983002e137d6a7014fbbf19;hp=721e03b76b9b7bca11c25552f3aeae17abe87773;hb=9aca38462cc044ef362fe17207e9fd6bc34a3465;hpb=d6e53996bae7bd8b01dfb6ed8e61a573bd9157cb diff --git a/www/js/jquery.sparkline.js b/www/js/jquery.sparkline.js index 721e03b..e1caac9 100644 --- a/www/js/jquery.sparkline.js +++ b/www/js/jquery.sparkline.js @@ -59,10 +59,6 @@ *

Sparkline:

* $('.sparkline').sparkline(); * -* For line charts, x values can also be specified: -*

Sparkline: 1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5

-* $('#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'}) * @@ -115,23 +111,7 @@ * 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 @@ -145,59 +125,14 @@ * 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 */ @@ -217,7 +152,7 @@ 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; /** @@ -227,7 +162,7 @@ return { // Settings common to most/all chart types common: { - type: 'line', + type: 'bar', lineColor: '#00f', fillColor: '#cdf', defaultPixelsPerValue: 3, @@ -250,25 +185,6 @@ 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(' {{prefix}}{{y}}{{suffix}}') - }, // Defaults for bar charts bar: { barColor: '#3366cc', @@ -286,68 +202,6 @@ colorMap: undefined, tooltipFormat: new SPFormat(' {{prefix}}{{value}}{{suffix}}') }, - // Defaults for tristate charts - tristate: { - barWidth: 4, - barSpacing: 1, - posBarColor: '#6f6', - negBarColor: '#f44', - zeroBarColor: '#999', - colorMap: {}, - tooltipFormat: new SPFormat(' {{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(' {{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'} } - } }; }; @@ -1347,356 +1201,6 @@ } }; - /** - * 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 */ @@ -1953,599 +1457,6 @@ } }); - /** - * 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()