/* A quick module for generating flot charts from an HTML table. Options can * be passed directly to flot using the data-module-* attributes. The tables * are currently expected to be marked up as follows: * * * * * * * * * * * * * * * * ... * *
X AxisSeries A LegendSeries B Legend
X ValueSeries A Y ValueSeries B Y Value
* * Points are pulled out of the th/td elements using innerHTML or by looking * for a data-value attribute. This is useful when a more readable value * needs to be used in the elements contents (eg. dates). A data-type attribute * can also be applied to parse the value. Only data-type="date" is currently * supported and expects data-value to be a unix timestamp. */ this.ckan.module('plot', function (jQuery, _) { return { /* Holds the jQuery.plot() object when created */ graph: null, /* Holds the canvas container when created */ canvas: null, /* Default options */ options: { xaxis: {}, yaxis: {}, legend: {position: 'nw'}, colors: ['#ffcc33', '#ff8844'] }, /* Sets up the canvas element and parses the table. * * Returns nothing. */ initialize: function () { jQuery.proxyAll(this, /_on/); if (!this.el.is('table')) { throw new Error('CKAN module plot can only be called on table elements'); } this.setupCanvas(); // Because the canvas doesn't render correctly unless visible we must // listen for events that reveal the canvas and then try and re-render. // Currently the most common of these is the "shown" event triggered by // the tabs plugin. this.sandbox.body.on("shown", this._onShown); this.data = this.parseTable(this.el); this.draw(); }, /* Removes event handlers when the module is removed from the DOM. * * Returns nothing. */ teardown: function () { this.sandbox.body.off("shown", this._onShown); }, /* Creates the canvas wrapper and removes the table from the document. * * Returns nothing. */ setupCanvas: function () { this.canvas = jQuery('
'); this.el.replaceWith(this.canvas); }, /* Attempts to draw the chart if the canvas is visible. If not visible the * graph does not render correctly. So we keep trying until it is. * * Examples * * module.draw(); * * Returns nothing. */ draw: function () { if (!this.drawn && this.canvas.is(':visible')) { this.graph = jQuery.plot(this.canvas, this.data, this.options); } }, /* Parses an HTML table element to build the data array for the chart. * The thead element provides the axis and labels for the series. The * first column in the tbody is used for the x-axis and subsequent * columns are the series. * * table - A table element to parse. * * Examples * * module.parseTable(module.el); * * Returns data object suitable for use in jQuery.plot(). */ parseTable: function (table) { var data = []; var _this = this; var headings = table.find('thead tr:first th').map(function () { return this.innerHTML; }); table.find('tbody tr').each(function (row) { var element = jQuery(this); var x = []; x[row] = _this.getValue(element.find('th')); element.find('td').each(function (series) { var value = _this.getValue(this); var label = headings[series + 1]; data[series] = data[series] || {data: [], label: label}; data[series].data[row] = [x[row], value]; }); }); return data; }, /* Retrieves the value from a td/th element. This first looks for a * data-value attribute on the element otherwise uses the element * text contents. * * A data-type attribute can also be provided to tell the module how * to deal with the element. By default we let jQuery.data() handle * the parsing but this can provide additional data. See .parseValue() * for more info. * * cell - An element to extract a value from. * * Examples * * var element = jQuery('Ten'); * module.getValue(element); //=> 10 * * var element = jQuery('20'); * module.getValue(element); //=> 20 * * var element = jQuery('1343747094'); * module.getValue(element); //=> * * Returns the parsed value. */ getValue: function (cell) { var item = cell instanceof jQuery ? cell : jQuery(cell); var type = item.data('type') || 'string'; var value = item.data('value') || item.text(); return this.parseValue(value, type); }, /* Provides the ability to further format a value. * * If date is provided as a type then it expects value to be a unix * timestamp in seconds. * * value - The value extracted from the element. * type - A type string, currently only supports "date". * * Examples * * module.parseValue(10); // => 10 * module.parseValue("cat"); // => "cat" * module.parseValue(1343747094, 'date'); // => * * Returns the parsed value. */ parseValue: function (value, type) { if (type === 'date') { value = new Date(parseInt(value, 10) * 1000); if (!value) { value = 0; } } return value; }, /* Event handler for when tabs are toggled. Determines if the canvas * resides in the shown element and attempts to re-render. * * event - The shown event object. * * Returns nothing. */ _onShown: function (event) { if (!this.drawn && jQuery.contains(jQuery(event.target.hash)[0], this.canvas[0])) { this.draw(); } } }; });