initStyles = function() { addCSS(defaultStyles); }; $(initStyles); pending = []; $.fn.sparkline = function (userValues, userOptions) { return this.each(function () { var options = new $.fn.sparkline.options(this, userOptions), $this = $(this), render, i; render = function () { var values, width, height, tmp, mhandler, sp, vals; if (userValues === 'html' || userValues === undefined) { vals = this.getAttribute(options.get('tagValuesAttribute')); if (vals === undefined || vals === null) { vals = $this.html(); } values = vals.replace(/(^\s*\s*$)|\s+/g, '').split(','); } else { values = userValues; } width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width'); if (options.get('height') === 'auto') { if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) { // must be a better way to get the line height tmp = document.createElement('span'); tmp.innerHTML = 'a'; $this.html(tmp); height = $(tmp).innerHeight() || $(tmp).height(); $(tmp).remove(); tmp = null; } } else { height = options.get('height'); } if (!options.get('disableInteraction')) { mhandler = $.data(this, '_jqs_mhandler'); if (!mhandler) { mhandler = new MouseHandler(this, options); $.data(this, '_jqs_mhandler', mhandler); } else if (!options.get('composite')) { mhandler.reset(); } } else { mhandler = false; } if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) { if (!$.data(this, '_jqs_errnotify')) { alert('Attempted to attach a composite sparkline to an element with no existing sparkline'); $.data(this, '_jqs_errnotify', true); } return; } sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height); sp.render(); if (mhandler) { mhandler.registerSparkline(sp); } }; if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) { if (!options.get('composite') && $.data(this, '_jqs_pending')) { // remove any existing references to the element for (i = pending.length; i; i--) { if (pending[i - 1][0] == this) { pending.splice(i - 1, 1); } } } pending.push([this, render]); $.data(this, '_jqs_pending', true); } else { render.call(this); } }); }; $.fn.sparkline.defaults = getDefaults(); $.sparkline_display_visible = function () { var el, i, pl; var done = []; for (i = 0, pl = pending.length; i < pl; i++) { el = pending[i][0]; if ($(el).is(':visible') && !$(el).parents().is(':hidden')) { pending[i][1].call(el); $.data(pending[i][0], '_jqs_pending', false); done.push(i); } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) { // element has been inserted and removed from the DOM // If it was not yet inserted into the dom then the .data request // will return true. // removing from the dom causes the data to be removed. $.data(pending[i][0], '_jqs_pending', false); done.push(i); } } for (i = done.length; i; i--) { pending.splice(done[i - 1], 1); } }; /** * User option handler */ $.fn.sparkline.options = createClass({ init: function (tag, userOptions) { var extendedOptions, defaults, base, tagOptionType; this.userOptions = userOptions = userOptions || {}; this.tag = tag; this.tagValCache = {}; defaults = $.fn.sparkline.defaults; base = defaults.common; this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix); tagOptionType = this.getTagSetting('type'); if (tagOptionType === UNSET_OPTION) { extendedOptions = defaults[userOptions.type || base.type]; } else { extendedOptions = defaults[tagOptionType]; } this.mergedOptions = $.extend({}, base, extendedOptions, userOptions); }, getTagSetting: function (key) { var prefix = this.tagOptionsPrefix, val, i, pairs, keyval; if (prefix === false || prefix === undefined) { return UNSET_OPTION; } if (this.tagValCache.hasOwnProperty(key)) { val = this.tagValCache.key; } else { val = this.tag.getAttribute(prefix + key); if (val === undefined || val === null) { val = UNSET_OPTION; } else if (val.substr(0, 1) === '[') { val = val.substr(1, val.length - 2).split(','); for (i = val.length; i--;) { val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, '')); } } else if (val.substr(0, 1) === '{') { pairs = val.substr(1, val.length - 2).split(','); val = {}; for (i = pairs.length; i--;) { keyval = pairs[i].split(':', 2); val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, '')); } } else { val = normalizeValue(val); } this.tagValCache.key = val; } return val; }, get: function (key, defaultval) { var tagOption = this.getTagSetting(key), result; if (tagOption !== UNSET_OPTION) { return tagOption; } return (result = this.mergedOptions[key]) === undefined ? defaultval : result; } }); $.fn.sparkline._base = createClass({ disabled: false, init: function (el, values, options, width, height) { this.el = el; this.$el = $(el); this.values = values; this.options = options; this.width = width; this.height = height; this.currentRegion = undefined; }, /** * Setup the canvas */ initTarget: function () { var interactive = !this.options.get('disableInteraction'); if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) { this.disabled = true; } else { this.canvasWidth = this.target.pixelWidth; this.canvasHeight = this.target.pixelHeight; } }, /** * Actually render the chart to the canvas */ render: function () { if (this.disabled) { this.el.innerHTML = ''; return false; } return true; }, /** * Return a region id for a given x/y co-ordinate */ getRegion: function (x, y) { }, /** * Highlight an item based on the moused-over x,y co-ordinate */ setRegionHighlight: function (el, x, y) { var currentRegion = this.currentRegion, highlightEnabled = !this.options.get('disableHighlight'), newRegion; if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) { return null; } newRegion = this.getRegion(el, x, y); if (currentRegion !== newRegion) { if (currentRegion !== undefined && highlightEnabled) { this.removeHighlight(); } this.currentRegion = newRegion; if (newRegion !== undefined && highlightEnabled) { this.renderHighlight(); } return true; } return false; }, /** * Reset any currently highlighted item */ clearRegionHighlight: function () { if (this.currentRegion !== undefined) { this.removeHighlight(); this.currentRegion = undefined; return true; } return false; }, renderHighlight: function () { this.changeHighlight(true); }, removeHighlight: function () { this.changeHighlight(false); }, changeHighlight: function (highlight) {}, /** * Fetch the HTML to display as a tooltip */ getCurrentRegionTooltip: function () { var options = this.options, header = '', entries = [], fields, formats, formatlen, fclass, text, i, showFields, showFieldsKey, newFields, fv, formatter, format, fieldlen, j; if (this.currentRegion === undefined) { return ''; } fields = this.getCurrentRegionFields(); formatter = options.get('tooltipFormatter'); if (formatter) { return formatter(this, options, fields); } if (options.get('tooltipChartTitle')) { header += '
' + options.get('tooltipChartTitle') + '
\n'; } formats = this.options.get('tooltipFormat'); if (!formats) { return ''; } if (!$.isArray(formats)) { formats = [formats]; } if (!$.isArray(fields)) { fields = [fields]; } showFields = this.options.get('tooltipFormatFieldlist'); showFieldsKey = this.options.get('tooltipFormatFieldlistKey'); if (showFields && showFieldsKey) { // user-selected ordering of fields newFields = []; for (i = fields.length; i--;) { fv = fields[i][showFieldsKey]; if ((j = $.inArray(fv, showFields)) != -1) { newFields[j] = fields[i]; } } fields = newFields; } formatlen = formats.length; fieldlen = fields.length; for (i = 0; i < formatlen; i++) { format = formats[i]; if (typeof format === 'string') { format = new SPFormat(format); } fclass = format.fclass || 'jqsfield'; for (j = 0; j < fieldlen; j++) { if (!fields[j].isNull || !options.get('tooltipSkipNull')) { $.extend(fields[j], { prefix: options.get('tooltipPrefix'), suffix: options.get('tooltipSuffix') }); text = format.render(fields[j], options.get('tooltipValueLookups'), options); entries.push('
' + text + '
'); } } } if (entries.length) { return header + entries.join('\n'); } return ''; }, getCurrentRegionFields: function () {}, calcHighlightColor: function (color, options) { var highlightColor = options.get('highlightColor'), lighten = options.get('highlightLighten'), parse, mult, rgbnew, i; if (highlightColor) { return highlightColor; } if (lighten) { // extract RGB values parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color); if (parse) { rgbnew = []; mult = color.length === 4 ? 16 : 1; for (i = 0; i < 3; i++) { rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255); } return 'rgb(' + rgbnew.join(',') + ')'; } } return color; } }); barHighlightMixin = { changeHighlight: function (highlight) { var currentRegion = this.currentRegion, target = this.target, shapeids = this.regionShapes[currentRegion], newShapes; // will be null if the region value was null if (shapeids) { newShapes = this.renderRegion(currentRegion, highlight); if ($.isArray(newShapes) || $.isArray(shapeids)) { target.replaceWithShapes(shapeids, newShapes); this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) { return newShape.id; }); } else { target.replaceWithShape(shapeids, newShapes); this.regionShapes[currentRegion] = newShapes.id; } } }, render: function () { var values = this.values, target = this.target, regionShapes = this.regionShapes, shapes, ids, i, j; if (!this.cls._super.render.call(this)) { return; } for (i = values.length; i--;) { shapes = this.renderRegion(i); if (shapes) { if ($.isArray(shapes)) { ids = []; for (j = shapes.length; j--;) { shapes[j].append(); ids.push(shapes[j].id); } regionShapes[i] = ids; } else { shapes.append(); regionShapes[i] = shapes.id; // store just the shapeid } } else { // null value regionShapes[i] = null; } } target.render(); } };