diff options
Diffstat (limited to '')
-rw-r--r-- | priv/static/js/metricsgraphics/charts/table.js | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/priv/static/js/metricsgraphics/charts/table.js b/priv/static/js/metricsgraphics/charts/table.js new file mode 100644 index 0000000..3081d8c --- /dev/null +++ b/priv/static/js/metricsgraphics/charts/table.js @@ -0,0 +1,220 @@ +/* +Data Tables + +Along with histograms, bars, lines, and scatters, a simple data table can take you far. +We often just want to look at numbers, organized as a table, where columns are variables, +and rows are data points. Sometimes we want a cell to have a small graphic as the main +column element, in which case we want small multiples. sometimes we want to + +var table = New data_table(data) + .target('div#data-table') + .title({accessor: 'point_name', align: 'left'}) + .description({accessor: 'description'}) + .number({accessor: ''}) + +*/ + +MG.data_table = function(args) { + 'use strict'; + this.args = args; + this.args.standard_col = { width: 150, font_size: 12, font_weight: 'normal' }; + this.args.columns = []; + this.formatting_options = [ + ['color', 'color'], + ['font-weight', 'font_weight'], + ['font-style', 'font_style'], + ['font-size', 'font_size'] + ]; + + this._strip_punctuation = function(s) { + var punctuationless = s.replace(/[^a-zA-Z0-9 _]+/g, ''); + var finalString = punctuationless.replace(/ +?/g, ''); + return finalString; + }; + + this._format_element = function(element, value, args) { + this.formatting_options.forEach(function(fo) { + var attr = fo[0]; + var key = fo[1]; + if (args[key]) element.style(attr, + typeof args[key] === 'string' || + typeof args[key] === 'number' ? + args[key] : args[key](value)); + }); + }; + + this._add_column = function(_args, arg_type) { + var standard_column = this.args.standard_col; + var args = merge_with_defaults(MG.clone(_args), MG.clone(standard_column)); + args.type = arg_type; + this.args.columns.push(args); + }; + + this.target = function() { + var target = arguments[0]; + this.args.target = target; + return this; + }; + + this.title = function() { + this._add_column(arguments[0], 'title'); + return this; + }; + + this.text = function() { + this._add_column(arguments[0], 'text'); + return this; + }; + + this.bullet = function() { + /* + text label + main value + comparative measure + any number of ranges + + additional args: + no title + xmin, xmax + format: percentage + xax_formatter + */ + return this; + }; + + this.sparkline = function() { + return this; + }; + + this.number = function() { + this._add_column(arguments[0], 'number'); + return this; + }; + + this.display = function() { + var args = this.args; + + chart_title(args); + + var target = args.target; + var table = d3.select(target).append('table').classed('mg-data-table', true); + var colgroup = table.append('colgroup'); + var thead = table.append('thead'); + var tbody = table.append('tbody'); + var this_column; + var this_title; + + var tr, th, td_accessor, td_type, td_value, th_text, td_text, td; + var col; + var h; + + tr = thead.append('tr'); + + for (h = 0; h < args.columns.length; h++) { + var this_col = args.columns[h]; + td_type = this_col.type; + th_text = this_col.label; + th_text = th_text === undefined ? '' : th_text; + th = tr.append('th') + .style('width', this_col.width) + .style('text-align', td_type === 'title' ? 'left' : 'right') + .text(th_text); + + if (args.show_tooltips && this_col.description && mg_jquery_exists()) { + th.append('i') + .classed('fa', true) + .classed('fa-question-circle', true) + .classed('fa-inverse', true); + + $(th.node()).popover({ + html: true, + animation: false, + content: this_col.description, + trigger: 'hover', + placement: 'top', + container: $(th.node()) + }); + } + } + + for (h = 0; h < args.columns.length; h++) { + col = colgroup.append('col'); + if (args.columns[h].type === 'number') { + col.attr('align', 'char').attr('char', '.'); + } + } + + for (var i = 0; i < args.data.length; i++) { + tr = tbody.append('tr'); + for (var j = 0; j < args.columns.length; j++) { + this_column = args.columns[j]; + td_accessor = this_column.accessor; + td_value = td_text = args.data[i][td_accessor]; + td_type = this_column.type; + + if (td_type === 'number') { + //td_text may need to be rounded + if (this_column.hasOwnProperty('round') && !this_column.hasOwnProperty('format')) { + // round according to the number value in this_column.round + td_text = d3.format('0,.' + this_column.round + 'f')(td_text); + } + + if (this_column.hasOwnProperty('value_formatter')) { + // provide a function that formats the text according to the function this_column.format. + td_text = this_column.value_formatter(td_text); + } + + if (this_column.hasOwnProperty('format')) { + // this is a shorthand for percentage formatting, and others if need be. + // supported: 'percentage', 'count', 'temperature' + + if (this_column.round) { + td_text = Math.round(td_text, this_column.round); + } + + var this_format = this_column.format; + var formatter; + + if (this_format === 'percentage') formatter = d3.format('.0%'); + if (this_format === 'count') formatter = d3.format(',.0f'); + if (this_format === 'temperature') formatter = function(t) { + return t + '°'; }; + + td_text = formatter(td_text); + } + + if (this_column.hasOwnProperty('currency')) { + // this is another shorthand for formatting according to a currency amount, which gets appended to front of number + td_text = this_column.currency + td_text; + } + } + + td = tr.append('td') + .classed('table-' + td_type, true) + .classed('table-' + td_type + '-' + this._strip_punctuation(td_accessor), true) + .attr('data-value', td_value) + .style('width', this_column.width) + .style('text-align', td_type === 'title' || td_type === 'text' ? 'left' : 'right'); + + this._format_element(td, td_value, this_column); + + if (td_type === 'title') { + this_title = td.append('div').text(td_text); + this._format_element(this_title, td_text, this_column); + + if (args.columns[j].hasOwnProperty('secondary_accessor')) { + td.append('div') + .text(args.data[i][args.columns[j].secondary_accessor]) + .classed("secondary-title", true); + } + } else { + td.text(td_text); + } + } + } + + return this; + }; + + return this; +}; |