.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "HTML::Dashboard 3pm" .TH HTML::Dashboard 3pm "2014-03-08" "perl v5.18.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" HTML::Dashboard \- Spreadsheet\-like formatting for HTML tables, with data\-dependent coloring and highlighting: formatted reports .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use HTML::Dashboard; \& \& my $dash = HTML::Dashboard\->new(); \& \& $dash\->set_data_without_captions( [ [ \*(AqA\*(Aq, 2, \*(Aqfoo\*(Aq ], \& [ \*(AqB\*(Aq, 0, \*(Aqbar\*(Aq ], \& [ \*(AqC\*(Aq, 1, \*(Aqbaz\*(Aq ], \& [ \*(AqD\*(Aq, 8, \*(Aqmog\*(Aq ], \& [ \*(AqE\*(Aq, 4, \*(Aqduh\*(Aq ] ] ); \& \& $dash\->set_captions( qw( Code Number Name ) ); \& $dash\->set_cell_low( 1, sub { $_[0] < 1 }, \*(Aqlime\*(Aq ); \& $dash\->set_cell_hi( 1, sub { $_[0] > 5 }, \& style => "background\-color: red; font\-weight: bold" ); \& \& print $dash\->as_HTML(); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This module tries to achieve spreadsheet-like formatting for \s-1HTML\s0 tables. .PP Rather than having to build up an \s-1HTML\s0 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. .PP The following features are supported: .IP "\(bu" 4 User-defined formatting of first, last, even, and odd rows or columns. .IP "\(bu" 4 Conditional formatting, based on the contents of each cell. .IP "\(bu" 4 Sorting (on any column or combination of columns, with user defined sort-order). .IP "\(bu" 4 Pagination of the data set. .IP "\(bu" 4 Definition of \*(L"views\*(R", i.e. restriction of the set of columns shown. .IP "\(bu" 4 User-defined column captions. .IP "\(bu" 4 On-the-fly formatting and collating of the data. .PP As an example, the code in the synopsis above yields the following \s-1HTML\s0 table (only visible in \s-1HTML\s0): .PP More examples can be found on the author's project page: http://www.beyondcode.org/projects/dashboard/gallery.html .PP Please read the Rationale section below to understand the purpose of this module. .SH "PUBLIC MEMBER FUNCTIONS" .IX Header "PUBLIC MEMBER FUNCTIONS" .SS "Constructor" .IX Subsection "Constructor" .IP "HTML::Dashboard\->\fInew()\fR" 4 .IX Item "HTML::Dashboard->new()" Constructs a new dashboard object. By default, this generates an \s-1HTML\s0 table with \f(CW\*(C`border=\*(Aq1\*(Aq\*(C'\fR and sets the background color of all even rows to light grey (#eeeeee). These defaults can be overridden (cf. below). .SS "Setting Data" .IX Subsection "Setting Data" .ie n .IP "$dash\->set_data_without_captions( $data )" 4 .el .IP "\f(CW$dash\fR\->set_data_without_captions( \f(CW$data\fR )" 4 .IX Item "$dash->set_data_without_captions( $data )" .PD 0 .ie n .IP "$dash\->set_data_with_captions( $data )" 4 .el .IP "\f(CW$dash\fR\->set_data_with_captions( \f(CW$data\fR )" 4 .IX Item "$dash->set_data_with_captions( $data )" .PD Takes a \fIreference\fR to an array of \fIarray references\fR of rows (i.e. a two-dimensional array). All rows \fImust\fR contain the same number of columns. .Sp Use \f(CW\*(C`set_data_without_captions\*(C'\fR if the array contains only data, without captions. Use \f(CW\*(C`set_data_with_captions\*(C'\fR 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 \&\f(CW\*(C`set_captions\*(C'\fR (cf. below). .Sp The data set is only accessed by reference, i.e. it is \fInot\fR 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. .SS "Output" .IX Subsection "Output" .ie n .IP "$dash\->\fIas_text()\fR" 4 .el .IP "\f(CW$dash\fR\->\fIas_text()\fR" 4 .IX Item "$dash->as_text()" .PD 0 .ie n .IP "$dash\->as_text( $page )" 4 .el .IP "\f(CW$dash\fR\->as_text( \f(CW$page\fR )" 4 .IX Item "$dash->as_text( $page )" .PD Returns the data as tab-delimited text string, after content formatters (or collaters), sorting, views, and pagination have been applied. No other formatting directives (e.g. odd/even rows, or hi/med/low triggers) are applied. The string will include captions (if they have been set). .Sp In the resulting text string, columns are separated by tabs (\et), rows are separated by single newlines (\en). Tabs, newlines, and backslashes in the data are escaped through a preceding backslash (\e). .ie n .IP "$dash\->\fIas_HTML()\fR" 4 .el .IP "\f(CW$dash\fR\->\fIas_HTML()\fR" 4 .IX Item "$dash->as_HTML()" .PD 0 .ie n .IP "$dash\->as_HTML( $page )" 4 .el .IP "\f(CW$dash\fR\->as_HTML( \f(CW$page\fR )" 4 .IX Item "$dash->as_HTML( $page )" .PD Returns the data as a single \s-1HTML\s0 string. The string contains an \s-1HTML\s0 table, from the opening \f(CW\*(C`
\*(C'\fR, and \f(CW\*(C` | \*(C'\fR tags).
.IP "\(bu" 4
Options to generate \*(L"striped reports\*(R" (i.e. tables, where the formatting
is dependent on the row\- or column-index).
.IP "\(bu" 4
Options which are only applied when a data-dependent condition is fulfilled.
.PP
The last group is more complicated, because not only do the actual formatting
options have to be set, but also the \*(L"trigger\*(R" and the range of table cells
to which it is supposed to be applied.
.PP
Formatting options can be set using three different ways:
.IP "1." 4
Single argument: e.g. \f(CW\*(C`$dash\->set_table( "border=\*(Aq1\*(Aq" )\*(C'\fR or
\&\f(CW\*(C`$dash\->set_first_row( \*(Aqred\*(Aq )\*(C'\fR.
.IP "2." 4
As explicit \s-1CSS\s0 style directive: e.g.
\&\f(CW\*(C`$dash\->set_th( style => \*(Aqfont\-size: x\-large\*(Aq )\*(C'\fR or
\&\f(CW\*(C`$dash\->set_even_row( style => \*(Aqbackground\-color: yellow\*(Aq )\*(C'\fR.
.IP "3." 4
By naming a \s-1CSS\s0 class: e.g.
\&\f(CW\*(C`$dash\->set_td( class => \*(Aqhighlighted\*(Aq )\*(C'\fR or
\&\f(CW\*(C`$dash\->set_even_col( class => \*(Aqevencol\*(Aq )\*(C'\fR. (Obviously, the
class set in this way should be defined in a stylesheet referenced
by the \s-1HTML\s0 page containing the dashboard.)
.PP
When using the \*(L"style\*(R" and \*(L"class\*(R" methods, a \*(L"style\*(R" or \*(L"class\*(R"
argument is included into the appropriate \s-1HTML\s0 tags, and set to the
supplied value. Note that repeated calls to these functions are
additive, \fInot\fR exclusive. In other words, the following two code
samples are equivalent:
.PP
.Vb 2
\& $dash\->set_even_row( style => \*(Aqbackground\-color: yellow\*(Aq );
\& $dash\->set_even_row( style => \*(Aqfont\-size: x\-large\*(Aq );
.Ve
.PP
is equivalent to:
.PP
.Vb 1
\& $dash\->set_even_row( style => \*(Aqbackground\-color: yellow; font\-size: x\-large\*(Aq );
.Ve
.PP
(The module will supply semicolons between different style directives
when merging the results from repeated calls.)
.PP
To erase previous style directives, assign \f(CW\*(C`undef\*(C'\fR explicitly:
\&\f(CW\*(C`$dash\->set_even_row( style => undef )\*(C'\fR.
.PP
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 \s-1HTML\s0 option (i.e.
when used with \f(CW\*(C`set_table()\*(C'\fR, \f(CW\*(C`set_tr()\*(C'\fR, \f(CW\*(C`set_th()\*(C'\fR, or \f(CW\*(C`set_td()\*(C'\fR),
the argument is pasted unmodified into the corresponding \s-1HTML\s0 tag.
When used with any other option, the argument is interpreted as the
\&\fIdesired background color\fR for the cell, row, or column. The specified
background color will be applied as an explicit \*(L"style\*(R" argument, \fInot\fR
as a \*(L"bgcolor\*(R" argument. In other words, the following calls are (almost)
equivalent:
.PP
.Vb 2
\& $dash\->set_first_row( \*(Aqcyan\*(Aq );
\& $dash\->set_first_row( style => \*(Aqbackground\-color: cyan\*(Aq );
.Ve
.PP
It is legal to set conflicting formatting options and will not prevent
generation of \s-1HTML\s0 output. However, no guarantees are made about the
appearance of the dashboard in the browser in this case.
.PP
\&\fBIn the following, \f(CB\*(C`[format]\*(C'\fB always stand for formatting
options in any one of the three legal syntax variants as discussed above!\fR
.PP
\fIGeneral \s-1HTML\s0 Options\fR
.IX Subsection "General HTML Options"
.ie n .IP "$dash\->set_table( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_table( \f(CW[format]\fR )" 4
.IX Item "$dash->set_table( [format] )"
.PD 0
.ie n .IP "$dash\->set_tr( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_tr( \f(CW[format]\fR )" 4
.IX Item "$dash->set_tr( [format] )"
.ie n .IP "$dash\->set_th( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_th( \f(CW[format]\fR )" 4
.IX Item "$dash->set_th( [format] )"
.ie n .IP "$dash\->set_td( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_td( \f(CW[format]\fR )" 4
.IX Item "$dash->set_td( [format] )"
.ie n .IP "$hash_ref = $dash\->\fIget_table()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_table()\fR" 4
.IX Item "$hash_ref = $dash->get_table()"
.ie n .IP "$hash_ref = $dash\->\fIget_tr()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_tr()\fR" 4
.IX Item "$hash_ref = $dash->get_tr()"
.ie n .IP "$hash_ref = $dash\->\fIget_th()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_th()\fR" 4
.IX Item "$hash_ref = $dash->get_th()"
.ie n .IP "$hash_ref = $dash\->\fIget_td()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_td()\fR" 4
.IX Item "$hash_ref = $dash->get_td()"
.PD
If set, these options are always included into all tags. This is mostly
useful to style the entire table, or cells in the header row.
.PP
\fIStriped Reports\fR
.IX Subsection "Striped Reports"
.ie n .IP "$dash\->set_first_row( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_first_row( \f(CW[format]\fR )" 4
.IX Item "$dash->set_first_row( [format] )"
.PD 0
.ie n .IP "$dash\->set_odd_row( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_odd_row( \f(CW[format]\fR )" 4
.IX Item "$dash->set_odd_row( [format] )"
.ie n .IP "$dash\->set_even_row( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_even_row( \f(CW[format]\fR )" 4
.IX Item "$dash->set_even_row( [format] )"
.ie n .IP "$dash\->set_last_row( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_last_row( \f(CW[format]\fR )" 4
.IX Item "$dash->set_last_row( [format] )"
.ie n .IP "$hash_ref = $dash\->\fIget_first_row()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_first_row()\fR" 4
.IX Item "$hash_ref = $dash->get_first_row()"
.ie n .IP "$hash_ref = $dash\->\fIget_odd_row()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_odd_row()\fR" 4
.IX Item "$hash_ref = $dash->get_odd_row()"
.ie n .IP "$hash_ref = $dash\->\fIget_even_row()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_even_row()\fR" 4
.IX Item "$hash_ref = $dash->get_even_row()"
.ie n .IP "$hash_ref = $dash\->\fIget_last_row()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_last_row()\fR" 4
.IX Item "$hash_ref = $dash->get_last_row()"
.ie n .IP "$dash\->set_first_col( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_first_col( \f(CW[format]\fR )" 4
.IX Item "$dash->set_first_col( [format] )"
.ie n .IP "$dash\->set_odd_col( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_odd_col( \f(CW[format]\fR )" 4
.IX Item "$dash->set_odd_col( [format] )"
.ie n .IP "$dash\->set_even_col( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_even_col( \f(CW[format]\fR )" 4
.IX Item "$dash->set_even_col( [format] )"
.ie n .IP "$dash\->set_last_col( ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_last_col( \f(CW[format]\fR )" 4
.IX Item "$dash->set_last_col( [format] )"
.ie n .IP "$hash_ref = $dash\->\fIget_first_col()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_first_col()\fR" 4
.IX Item "$hash_ref = $dash->get_first_col()"
.ie n .IP "$hash_ref = $dash\->\fIget_odd_col()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_odd_col()\fR" 4
.IX Item "$hash_ref = $dash->get_odd_col()"
.ie n .IP "$hash_ref = $dash\->\fIget_even_col()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_even_col()\fR" 4
.IX Item "$hash_ref = $dash->get_even_col()"
.ie n .IP "$hash_ref = $dash\->\fIget_last_col()\fR" 4
.el .IP "\f(CW$hash_ref\fR = \f(CW$dash\fR\->\fIget_last_col()\fR" 4
.IX Item "$hash_ref = $dash->get_last_col()"
.PD
Options set with these functions are applied to rows or columns as
appropriate. Note that first, last, even, and odd is understood with
reference to the page or the view, \fInot\fR the total data set.
.Sp
Options for first and last prevail over options for even and odd.
Options for columns prevail over options for rows.
.PP
\fIConditional Formatting (Triggers)\fR
.IX Subsection "Conditional Formatting (Triggers)"
.PP
Formatting options in this group are only applied if a \*(L"trigger\*(R"
evaluates to true. Therefore, the functions below all take a function
reference as argument, besides the actual formatting options.
.PP
All triggers have a \*(L"priority\*(R" 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.
.PP
The intended application is to show whether a set of data is \*(L"in the
green\*(R" or \*(L"in the red\*(R". 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:
.PP
.Vb 3
\& $dash\->set_row_low( sub{ ...; $x < 3 }, \*(Aqgreen\*(Aq );
\& $dash\->set_row_med( sub{ ...; $x < 7 }, \*(Aqyellow\*(Aq );
\& $dash\->set_row_hi( sub{ ...; $x > 10 }, \*(Aqred\*(Aq );
.Ve
.ie n .IP "$dash\->set_row_hi( sub{ my ( $row_ref ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_row_hi( sub{ my ( \f(CW$row_ref\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_row_hi( sub{ my ( $row_ref ) = @_; ... }, [format] )"
.PD 0
.ie n .IP "$dash\->set_row_med( sub{ my ( $row_ref ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_row_med( sub{ my ( \f(CW$row_ref\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_row_med( sub{ my ( $row_ref ) = @_; ... }, [format] )"
.ie n .IP "$dash\->set_row_low( sub{ my ( $row_ref ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_row_low( sub{ my ( \f(CW$row_ref\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_row_low( sub{ my ( $row_ref ) = @_; ... }, [format] )"
.PD
If the triggers evaluates to true, the formatting option is applied
to the entire row. The argument to the trigger is an array-ref to
the current row. (Additional arguments: index of row in page, and
index of row in data set.)
.ie n .IP "$dash\->set_col_hi( $col, sub{ my ( $cell ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_col_hi( \f(CW$col\fR, sub{ my ( \f(CW$cell\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_col_hi( $col, sub{ my ( $cell ) = @_; ... }, [format] )"
.PD 0
.ie n .IP "$dash\->set_col_med( $col, sub{ my ( $cell ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_col_med( \f(CW$col\fR, sub{ my ( \f(CW$cell\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_col_med( $col, sub{ my ( $cell ) = @_; ... }, [format] )"
.ie n .IP "$dash\->set_col_low( $col, sub{ my ( $cell ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_col_low( \f(CW$col\fR, sub{ my ( \f(CW$cell\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_col_low( $col, sub{ my ( $cell ) = @_; ... }, [format] )"
.PD
The first argument to this function is the index of the column \fIin the
data set\fR (not in the view!) to which the formatting should be applied.
If the triggers evaluates to true, the formatting option is applied to
all cells in the column. The argument to the trigger is the contents of
the current cell in the specified column.(Additional arguments: the
index in the view and in the data set.)
.ie n .IP "$dash\->set_cell_hi( $col, sub{ my ( $cell ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_cell_hi( \f(CW$col\fR, sub{ my ( \f(CW$cell\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_cell_hi( $col, sub{ my ( $cell ) = @_; ... }, [format] )"
.PD 0
.ie n .IP "$dash\->set_cell_med( $col, sub{ my ( $cell ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_cell_med( \f(CW$col\fR, sub{ my ( \f(CW$cell\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_cell_med( $col, sub{ my ( $cell ) = @_; ... }, [format] )"
.ie n .IP "$dash\->set_cell_low( $col, sub{ my ( $cell ) = @_; ... }, ""[format]"" )" 4
.el .IP "\f(CW$dash\fR\->set_cell_low( \f(CW$col\fR, sub{ my ( \f(CW$cell\fR ) = \f(CW@_\fR; ... }, \f(CW[format]\fR )" 4
.IX Item "$dash->set_cell_low( $col, sub{ my ( $cell ) = @_; ... }, [format] )"
.PD
The first argument to this function is the index of the column \fIin the
data set\fR (not in the view!) to which the formatting should be applied.
If the triggers evaluates to true, the formatting option is applied to
the current cell only. The argument to the trigger is the contents of
the current cell in the specified column.(Additional arguments: the
index in the view and in the data set.)
.PP
Options set with triggers are \fImerged\fR (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.)
.PP
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.
.SS "Content Formatters"
.IX Subsection "Content Formatters"
.ie n .IP "$dash\->set_format( $column, sub { ... } )" 4
.el .IP "\f(CW$dash\fR\->set_format( \f(CW$column\fR, sub { ... } )" 4
.IX Item "$dash->set_format( $column, sub { ... } )"
.PD 0
.ie n .IP "$dash\->set_collate( $column, sub { ... } )" 4
.el .IP "\f(CW$dash\fR\->set_collate( \f(CW$column\fR, sub { ... } )" 4
.IX Item "$dash->set_collate( $column, sub { ... } )"
.PD
If set, the registered function is called for each row. Its output
is used as contents for the current row's cell in the column with
index \f(CW$column\fR.
.Sp
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).
.Sp
Examples:
.Sp
.Vb 2
\& $dash\->set_format( 1, sub { my ( $x ) = @_; sprintf( "%.2f", $x ) } )
\& $dash\->set_collate( 1, sub { my ( $r ) = @_; $r[1] . \*(Aq:\*(Aq . $r[2] } )
.Ve
.SH "RATIONALE"
.IX Header "RATIONALE"
It was important to me to define a module that would be easy to use,
with reasonable defaults and a reasonably small \s-1API.\s0
.PP
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.
.PP
All this required a rule-based system \-\-\- you specify the high-level
rules, the module makes sure they are applied as necessary.
.PP
Below are some further questions that have been asked \-\-\- with answers:
.PP
Why not just use \s-1CSS\s0? Answer: All of this \fIis\fR done through \s-1CSS.\s0 The
difficulty is deciding to which cells to apply the \s-1CSS\s0 style directives
(if this is to be done in a data dependent manner). This module does
just that, by inserting the correct \s-1CSS \s0\*(L"class\*(R" arguments into the
appropriate cell tags (etc).
.PP
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. \f(CW\*(C`HTML::Template\*(C'\fR 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 \s-1HTML\s0 as we go along.
Using templates in the implementation would not help.
.PP
Why not use Excel, \s-1PDF,\s0 or what have you? Because I want to deliver
my reports via the web, so I specifically want \s-1HTML\s0 output. (Duh!)
.PP
Why the name? Because I wanted something more specific and tangible
than \*(L"FormattedReport\*(R" 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 \*(L"in the green\*(R" and which are \*(L"in the red\*(R".
This module allows you to do just that. (And more.)
.SH "TO DO"
.IX Header "TO DO"
Several ideas:
.IP "\(bu" 4
Instead of setting the actual data, it would be nice to set merely a
query (and a \s-1DB\s0 handle) and let the dashboard pull its own data from
the \s-1DB.\s0
.IP "\(bu" 4
When there are subsequent rows, which have identical entries in some
columns it can be neat to suppress (leave blank) the repeated entries
(e.g. \f(CW\*(C`set_skip_repeats( @skip_cols )\*(C'\fR and \f(CW\*(C`get_skip_repeats()\*(C'\fR).
.IP "\(bu" 4
When setting data using an array-ref, it would be nice to specify an
optional integer parameter \f(CW$extend_by\fR, which would extend the range
of accessible columns. These new columns would be empty, but could be
used with \f(CW\*(C`set_collate()\*(C'\fR to build new column values on the fly. (This
is never necessary when using a \s-1DB\s0 query, since one can always include
constants in the \f(CW\*(C`SELECT\*(C'\fR clause.)
.SH "SEE ALSO"
.IX Header "SEE ALSO"
I maintain a \*(L"gallery\*(R" of examples (with code) on my website at:
http://www.beyondcode.org/projects/dashboard/gallery.html
.PP
The module HTML::Tabulate seems close in intent to the present
module and may be an alternative. (The \s-1API\s0 is much larger than the
one for the present module and I am not entirely sure how it works.)
.PP
Several modules provide very thin wrappers around the actual
\&\s-1HTML\s0 of a table, they include HTML::Table, HTML::EasyTable,
HTML::ElementTable.
.PP
To generate tables directly from \s-1SQL\s0 queries, check out
Class::DBI::Plugin::FilterOnClick.
.SH "AUTHOR"
.IX Header "AUTHOR"
Philipp K. Janert, |
---|