HTML::Dashboard(3pm) | User Contributed Perl Documentation | HTML::Dashboard(3pm) |
HTML::Dashboard - Spreadsheet-like formatting for HTML tables, with data-dependent coloring and highlighting: formatted reports
use HTML::Dashboard; my $dash = HTML::Dashboard->new(); $dash->set_data_without_captions( [ [ 'A', 2, 'foo' ], [ 'B', 0, 'bar' ], [ 'C', 1, 'baz' ], [ 'D', 8, 'mog' ], [ 'E', 4, 'duh' ] ] ); $dash->set_captions( qw( Code Number Name ) ); $dash->set_cell_low( 1, sub { $_[0] < 1 }, 'lime' ); $dash->set_cell_hi( 1, sub { $_[0] > 5 }, style => "background-color: red; font-weight: bold" ); print $dash->as_HTML();
This module tries to achieve spreadsheet-like formatting for HTML tables.
Rather than having to build up an HTML table from data, row by row and cell by cell, applying formatting rules at every step, this module allows the user to specify a set of simple rules with the desired formatting options. The module will evaluate the rules and apply the formatting options as necessary.
The following features are supported:
As an example, the code in the synopsis above yields the following HTML table (only visible in HTML):
More examples can be found on the author's project page: http://www.beyondcode.org/projects/dashboard/gallery.html
Please read the Rationale section below to understand the purpose of this module.
Use "set_data_without_captions" if the array contains only data, without captions. Use "set_data_with_captions" if the array contains captions in the first row (as is common, e.g., for data returned from database queries). Captions can be specified or overridden using "set_captions" (cf. below).
The data set is only accessed by reference, i.e. it is not copied. This should be advantageous for large data sets, but will lead to strange results if the data set changes after having been set, but before any one of the output routines is called.
In the resulting text string, columns are separated by tabs (\t), rows are separated by single newlines (\n). Tabs, newlines, and backslashes in the data are escaped through a preceding backslash (\).
No HTML-escaping of data (i.e. of cell content) is performed. If required, specify an appropriate formatter for the data to perform any conversions.
Both functions can be called with an optional integer argument. If no argument is supplied, all rows are returned. If an integer argument in the range
0 <= $page < $dash->pagecount()
is supplied, only the rows in the specified page (plus captions, if any) are returned. If a page outside the legal range is specified, a warning is emitted and all rows are returned. (Do not forget to call "$dash->set_pagesize(...)" before using this feature. By default, the pagesize is set to infinity, i.e. all rows are returned.)
Note that the comparator will be called as a regular routine! This implies in particular that the comparator must parse @_ itself - arguments will not be passed through the "global" variables $a and $b as for the "sort" built-in.
Example:
$dash->set_sort( sub { my ( $x, $y ) = @_; $x->[0] <=> $y->[0] } )
This sorts the rows numerically on the contents of the first column.
There are three groups of formatting options:
The last group is more complicated, because not only do the actual formatting options have to be set, but also the "trigger" and the range of table cells to which it is supposed to be applied.
Formatting options can be set using three different ways:
When using the "style" and "class" methods, a "style" or "class" argument is included into the appropriate HTML tags, and set to the supplied value. Note that repeated calls to these functions are additive, not exclusive. In other words, the following two code samples are equivalent:
$dash->set_even_row( style => 'background-color: yellow' ); $dash->set_even_row( style => 'font-size: x-large' );
is equivalent to:
$dash->set_even_row( style => 'background-color: yellow; font-size: x-large' );
(The module will supply semicolons between different style directives when merging the results from repeated calls.)
To erase previous style directives, assign "undef" explicitly: "$dash->set_even_row( style => undef )".
The single-argument version is intended as a short-cut and has a slightly different meaning, depending on the group of formatting option it is applied to. When applied to a direct HTML option (i.e. when used with "set_table()", "set_tr()", "set_th()", or "set_td()"), the argument is pasted unmodified into the corresponding HTML tag. When used with any other option, the argument is interpreted as the desired background color for the cell, row, or column. The specified background color will be applied as an explicit "style" argument, not as a "bgcolor" argument. In other words, the following calls are (almost) equivalent:
$dash->set_first_row( 'cyan' ); $dash->set_first_row( style => 'background-color: cyan' );
It is legal to set conflicting formatting options and will not prevent generation of HTML output. However, no guarantees are made about the appearance of the dashboard in the browser in this case.
In the following, "[format]" always stand for formatting options in any one of the three legal syntax variants as discussed above!
General HTML Options
Striped Reports
Options for first and last prevail over options for even and odd. Options for columns prevail over options for rows.
Conditional Formatting (Triggers)
Formatting options in this group are only applied if a "trigger" evaluates to true. Therefore, the functions below all take a function reference as argument, besides the actual formatting options.
All triggers have a "priority" from highest (hi), over intermediate (med) to lowest (low). If multiple triggers evaluate to true for a certain part of the dashboard (say, a cell), then only the formatting option with the highest priority is applied.
The intended application is to show whether a set of data is "in the green" or "in the red". Given the prioritization logic of the triggers, this can be easily achieved, without the need for exclusive bounds or conditions across the set of triggers, using code like this:
$dash->set_row_low( sub{ ...; $x < 3 }, 'green' ); $dash->set_row_med( sub{ ...; $x < 7 }, 'yellow' ); $dash->set_row_hi( sub{ ...; $x > 10 }, 'red' );
Options set with triggers are merged (do not clobber) with options set for first/last and even/odd. (This allows one to have a striped report, and use triggers to change the text color only.)
Options with high (hi) priority prevail over (clobber) options with intermediate (med) priority, which prevail over options with low priority. Options for cells prevail over options for columns, which prevail over options for rows.
A formatter set with the first function is given the contents of the data in the current cell, while a collater set with the second function is given the entire row (as array).
Examples:
$dash->set_format( 1, sub { my ( $x ) = @_; sprintf( "%.2f", $x ) } ) $dash->set_collate( 1, sub { my ( $r ) = @_; $r[1] . ':' . $r[2] } )
It was important to me to define a module that would be easy to use, with reasonable defaults and a reasonably small API.
In particular, I wanted a solution which would free the user entirely from having to deal with (i.e. explicitly loop over) individual rows and cells. Furthermore, the user should not have to specify information that is already present in the data (such as the number of rows and columns). Finally, I wanted to free the user from having to address individual cells (e.g. by their location) to provide formatting instructions.
All this required a rule-based system --- you specify the high-level rules, the module makes sure they are applied as necessary.
Below are some further questions that have been asked --- with answers:
Why not just use CSS? Answer: All of this is done through CSS. The difficulty is deciding to which cells to apply the CSS style directives (if this is to be done in a data dependent manner). This module does just that, by inserting the correct CSS "class" arguments into the appropriate cell tags (etc).
Why not go with a templating solution? Answer: Templates establish the layout of a table from the outset, which makes it hard to do cell-content-dependent formatting from within the template. And it is simply not convenient, and not in the spirit of the thing, to build templates with lots of conditional code in the template. (I know, having used eg. "HTML::Template" quite extensively.) Given the data-dependent nature of the problem, the table must be built-up row by row and cell by cell individually, applying triggers and formatters as we go along. This is what this module does --- and since we are already must touch each cell individually, we might as well print its HTML as we go along. Using templates in the implementation would not help.
Why not use Excel, PDF, or what have you? Because I want to deliver my reports via the web, so I specifically want HTML output. (Duh!)
Why the name? Because I wanted something more specific and tangible than "FormattedReport" or some such. The name points to the source of the idea for this module: corporate metrics dashboards. What managers want to see are the key metrics of the business (sales, orders, what-have-you), with outliers highlighted to make it easy to see which metrics are "in the green" and which are "in the red". This module allows you to do just that. (And more.)
Several ideas:
I maintain a "gallery" of examples (with code) on my website at: http://www.beyondcode.org/projects/dashboard/gallery.html
The module HTML::Tabulate seems close in intent to the present module and may be an alternative. (The API is much larger than the one for the present module and I am not entirely sure how it works.)
Several modules provide very thin wrappers around the actual HTML of a table, they include HTML::Table, HTML::EasyTable, HTML::ElementTable.
To generate tables directly from SQL queries, check out Class::DBI::Plugin::FilterOnClick.
Philipp K. Janert, <janert at ieee dot org>, http://www.beyondcode.org
Copyright (C) 2007 by Philipp K. Janert
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
2022-10-15 | perl v5.36.0 |