Skip to content

Instantly share code, notes, and snippets.

@pauljm
Last active December 25, 2015 15:39
Show Gist options
  • Save pauljm/7000013 to your computer and use it in GitHub Desktop.
Save pauljm/7000013 to your computer and use it in GitHub Desktop.
Histogram Scala/Twirl/HTML
@* Helper to draw <font> tags *@
@font(size: Option[Int] = Some(12), bold: Option[Boolean] = Some(false), color: Option[String] = None) = {<!--
--><font face='@Html(ctx.fontFace)'@{ if (color.isDefined) s" color='${color.get}'" else "" } style='@if(size.isDefined) { font-size: @{size.get}px; } @if(bold.isDefined) { font-weight: @{ if (bold.get) "bold" else "normal"}; }'><!--
-->}
@* Draw a spacer cell with text inside so Outlook doesn't ignore it *@
@spacerCell(width: Option[Any] = None, height: Option[Int] = None, rowspan: Int = 1, colspan: Int = 1, bgcolor: Option[String] = None) = {
<td rowspan=@rowspan colspan=@colspan@{ if (width.isDefined) s" width='${width.get}'" else "" }@{ if (height.isDefined) s" height='${height.get}'" else "" }@{ if (bgcolor.isDefined) s" bgcolor='${bgcolor.get}'" else "" } style='@{ if (height.isDefined) s"font-size: ${height.get}px; line-height: ${height.get}px;" else "font-size: 0; line-height: 0;" }'>&nbsp;</td>
}
@* Add commas to numbers 1,000 or greater *@
@formattedInt(i: Int) = @{ i.toString.reverse.grouped(3).mkString(",").reverse }
@* Draw a histogram *@
@histogram(labels: Seq[String], upValues: Seq[Int], downValues: Seq[Int],
heightIncrement: Int, numIncrements: Int, spacing: Int, labelHeight: Int,
upTotalLabel: String, downTotalLabel: String) = {
<table cellpadding=0 cellspacing=0 width="100%" style='text-align: center;'>
@* Top row provides pading and sets column widths *@
<tr>
@spacerCell(width = Some(spacing), height = Some(spacing), bgcolor = Some("#E4F1F5"))
@for(i <- (0 until labels.length)) {
@spacerCell(width = Some(28), bgcolor = Some("#E4F1F5")) @* Columns divide available space *@
@spacerCell(width = Some(spacing), bgcolor = Some("#E4F1F5")) @* Padding between columns *@
}
@* Write total and label for upward histogram. (Downward histogram total is written with first row of down histogram.) *@
@histogramTotalCells(numIncrements, spacing, "#6DB2C8", "#E4F1F5", upValues, upTotalLabel)
</tr>
@* Draw upward histogram, with bars spanning multiple rows *@
@for(i <- (0 until numIncrements)) {
@histogramRow(i, true, upValues, heightIncrement, numIncrements, spacing, "#6DB2C8", "#E4F1F5", upTotalLabel)
}
@* Draw bucket labels *@
<tr>
@spacerCell(Some(spacing), Some(labelHeight))
@for(label <- labels) {
<td align='center' valign='middle'>@font(size = Some(11))@label</font></td>
@spacerCell()
}
@spacerCell(colspan = 4) @* Cell between total and label *@
</tr>
@* Draw downward histogram, with bars spanning multiple rows. Write total at right. *@
@for(i <- (0 until numIncrements)) {
@histogramRow(i, false, downValues, heightIncrement, numIncrements, spacing, "#E68265", "#F9E9E3", downTotalLabel)
}
@* Bottom padding *@
<tr>
@spacerCell(width = None, height = Some(spacing), colspan = 2 * labels.length + 1, bgcolor = Some("#F9E9E3"))
</tr>
</table>
}
@* Draw a row of the histogram table *@
@histogramRow(row: Int, up: Boolean, values: Seq[Int],
heightIncrement: Int, numIncrements: Int, spacing: Int, color: String,
bgcolor: String, totalLabel: String) = {
<tr>
@* Left-hand padding *@
@spacerCell(width = Some(spacing), height = Some(heightIncrement), bgcolor = Some(bgcolor))
@* Draw bars *@
@for(i <- (0 until values.size)) {
@* Each column has two cells, one for the bar and one for the space above/below the bar *@
@defining(((values(i).toDouble / values.max.toDouble) * numIncrements).ceil.toInt) { bucketIncrements =>
@defining(bucketIncrements * heightIncrement >= 15) { roomForLabel =>
@if(bucketIncrements > 0 &&
(up && row == numIncrements - bucketIncrements || ! up && row == 0)) {
<td bgcolor='@{color}' rowspan=@bucketIncrements valign='@{ if (up) "top" else "bottom" }'>@if(roomForLabel){ @font(size = Some(9), color = Some("#FFFFFF"))@{values(i)}</font> }</td>
}
@if(bucketIncrements < numIncrements &&
(up && row == 0 || ! up && row == bucketIncrements)) {
<td bgcolor='@{bgcolor}' rowspan=@{numIncrements - bucketIncrements} valign='@{ if (up) "bottom" else "top" }'>@if(! roomForLabel){ @font(size = Some(9))@{values(i)}</font> }</td>
}
}
}
@* Padding between bars *@
@if(row == 0) {
@spacerCell(rowspan = numIncrements, bgcolor = Some(bgcolor))
}
}
@* For downward histogram, write total at right. (Upward histogram total is written in top padding row of table.) *@
@if(row == 0 && ! up) {
@histogramTotalCells(numIncrements, spacing, color, bgcolor, values, totalLabel)
}
</tr>
}
@* Draw the total counts to the right of a set of histogram bars *@
@histogramTotalCells(numIncrements: Int, spacing: Int, color: String,
bgcolor: String, values: Seq[Int], totalLabel: String) = {
<td width=97 rowspan=@{numIncrements + 1} align='right' valign='middle' bgcolor='@{bgcolor}'>
@font(size = Some(32), bold = Some(true), color = Some(color))@formattedInt(values.sum)</font>
</td>
@spacerCell(width = Some(spacing), rowspan = numIncrements + 1, bgcolor = Some(bgcolor))
<td width=97 rowspan=@{numIncrements + 1} align='left' valign='middle' bgcolor='@{bgcolor}'>
@font(size = Some(16), color = Some(color))@{totalLabel}</font>
</td>
@spacerCell(width = Some(spacing), rowspan = numIncrements + 1, bgcolor = Some(bgcolor))
}
@* Draw a histogram based on data in stats.volumeOneWeek *@
@histogram(
stats.volumeOneWeek.buckets.slice(0, 7).map { startDate =>
Seq("", "M", "Tu", "W", "Th", "F", "Sa", "Su")(startDate.getDayOfWeek)
},
stats.volumeOneWeek.out,
stats.volumeOneWeek.in,
3, // Height increment of histogram bars
20, // Number of increments in full bar
12, // Padding around histogram and spacing between bars
20, // Height of bucket label row
"sent",
"received"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment