Thursday, February 17, 2011

Data Dynamics Reports: One touch printing on the web

Preface
Some time ago I blogged around ideas on no-touch printing on the web in ActiveReports. A lot of the new features were added in both of ActiveReports and Data Dynamics Reports since from that blog post was published. Particularly we have updated PDF export capabilities so that they allow performing one touch printing easily. In this article I will explain it in details.

The problem
Let's imagine that we have the simple Html page. It hosts the list of the product categories(obtained from Northwind database, Categories table) and "Print" button. We need to implement the following functionality: a user selects the category, clicks Print, the server returns the PDF document that shows the list of the products from the selected category(obtained from Northwind database, Products table), PDF document starts printing immediately - a user should get the print dialog of PDF viewer and the document should not be opened in the viewer.

One-touch printing in action
Let's create the web-site that implements the functionality described in "Problem" section:
products.xml(change the extension to Rdlx) is the report that accepts category id parameter and displays the list of the products accordingly. Copy products.rdlx in the root folder of the web-site.
Now copy default.htm in the root folder of the web-site and let's look at the page body:

<body>
<label>Select the category to print the list of the product of:</label><br />
<select id="categoryList">
<option value="1">Beverages</option>
<option value="2">Condiments</option>
<option value="3">Confections</option>
<option value="4">Dairy Products</option>
<option value="5">Grains/Cereals</option>
<option value="6">GMeat/Poultry</option>
<option value="7">Produce</option>
<option value="8">Seafood</option>
</select>
<input id="btnPrint" type="button" value="Print" />
<script>
$("#btnPrint").click(function() {
var catId = $("#categoryList").val();
$("#pdfContentPlaceHolder").attr("src", "GetData.aspx?catID="+catId);
});
</script>
<iframe style="visibility:hidden" id="pdfContentPlaceHolder" width="0" height="0" />
</body>

So, in the handler of of Print button click we set the source of the invisible frame to the data that are returned by GetData.aspx page. Once the document is loaded in the frame, the printing should start immediately. How is it achieved? Copy GetData.aspx in the root folder of the web-site and let's look at its Page_Load code:

void Page_Load(object sender, EventArgs e)
{
int catId;
if(!int.TryParse(Request.QueryString["catId"], out catId))
{
Response.Write("Invalid category Id parametere value! No output you will get");
return;
}
var fi = new FileInfo(Server.MapPath("~/Products.rdlx"));
var def = new ReportDefinition(fi);
var runtime = new ReportRuntime(def);
runtime.Parameters[0].CurrentValue = catId;
var pdf = new PdfRenderingExtension();
var streams = new MemoryStreamProvider();
var settings = (pdf as IConfigurable).GetSupportedSettings().GetSettings();
settings["PrintOnOpen"] = "true";
runtime.Render(pdf, streams, settings);
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "inline; filename=products.pdf");
using(var stream = streams.GetPrimaryStream().OpenStream())
{
var len = (int)stream.Length;
var bytes = new byte[len];
stream.Read(bytes, 0, len);
Response.BinaryWrite(bytes);
}
}

The code is quite trivial, there are two relatively new features in use though:

  • MemoryStreamProvider allows to export the reports to the memory instead of the disk files. It is pretty convenient for web-scenarios where you don't want to use file system aggressively.

  • We set PrintOnOpen setting of PDF export to true. It will force PDF document to start printing immediately once it is loaded in the invisible frame on default.htm

The task is completed.


ActiveReports
It is possible to use the same technology in ActiveReports. The setting for PDF export filter document option is called OnlyForPrint, it is hidden in the intellisence, but you can use it:

PdfExport pdf = new PdfExport();
pdf.PdfDocumentOptions.OnlyForPrint=true;

Tuesday, February 8, 2011

DDR: Using data visualizers to build a thermometer chart

Preface
Data Dynamics Reports does not include circular gauge and meters controls. We did not add them with good reason - they tend to be misleading and and take a lot of space on the screen. Instead we provide Bullet and Sparkline graphs that can visualize data quite effectively. However, as one of our customers rightfully mentioned, the sales folks adore meters controls - speedometer, thermometer, etc. and it would be good to have these controls in the product. This article shows how to compose a thermometer chart by using wonderful built-in feature called "DataBar visualizer".

The problem
Let's imagine that we are about to build the patients temperature report that is sent to chief of a hospital department every morning. The report shows the table that consists of two columns: patient name and patient temperature that was measured at 6am. The chief demands that the temperature value is visualized by a gauge, like this one:

The thermometer has 3 ranges:

  • [0;35] brushed with blue color - patient has problems or already dead.

  • [35;37] brushed with green color - patient is feeling well!

  • [37;43] brushed with red color - patient has fever or about to die.

The yellow marker visualizes the temperature value.


DataBar visualizer in action.
The rest of the article walks through the process of building the report. For convenience sake the walkthrough starts from the existing report layout that only includes the data are set.

  • Open PatientsTemperature.xml(change .xml to .rdlx) by using either DataDynamics.Reports.Designer.exe application or Visual Studio.

  • Add the table report item in the report body. Remove the 3rd column and the footer of the table. Set table's DataSetName property to "Temperature" . Set the the 1st column, details row cell value to "=[Patient]"

  • Add the Rectangle Report Item in the table's 2nd column, details row cell. Set the rectangle's background color to Green and the name to "rectOuter". This rectangle will show the 2nd range of the thermometer.

  • Add the nested rectangle in rectOuter. Set the rectangle's name to "rectNested", the location to (0in,0in), the size to the same value as rectOuter has. Now the magic begins.

  • Set the properties of the rectNested BackgroundImage: Source:DataBase, Value:=DataBar(35,0,43,0,'Blue'), MIMEType:image/png, BackgroundRepeat:NoRepeat. What happens here? It's not allowed to set the rectangle's background image by using the data visulalizer editor, like for a textbox, but in fact the rectangle supports data visualizers! What do the DataBar arguments mean? 35 is the boundary of the 1st range, 0 is the minimum temperature value, 43 is maximum temperature value, 0 is the zero coordinate, Blue is the color for the 1st range according to the requirements. The documentation describes the arguments meaning in details. Now preview the report. Can you see how the magic works? The rectNested's background image takes the space according to DataBar Value argument. The rest of rectNested is transparent which makes rectOuter's background partially visible. Now our thermomemeter shows 2 ranges. Fantastic!

  • Add the nested rectangle in rectNested. Set rectangle's name to "rectNestedNested", location to 0in,0in), size to the same value as rectOuter and rectNested have. As you might deduce rectNestedNested will show the 3rd Red range of our thermometer. Let's set it's background image accordingly:

  • Source:DataBase, Value:=DataBar(43,0,43,37,"Red"), MIMEType:image/png, BackgroundRepeat:NoRepeat. In DataBar function we set the zero coordinate to 37 so that the red background starts from the 2nd range right boundary. The magic described in (5) works for the 3rd range as well.

  • Now let's add the temperature value marker. It is done by using...drumroll please...rectangle that has DataBar invoke in background image expressions. Add the nested rectangle in rectNestedNested. Set the following properties for this newly added rectangle: Location.Left=0, Size.Width=the same value as the parents rectangles have. Set Location.Top and Size.Height to the appropriate values for the marker. Source:DataBase, Value:=DataBar(Fields!Temperature.Value,0,43,0,"Yellow"), MIMEType:image/png, BackgroundRepeat:NoRepeat.

  • Now select rectOuter, rectNested, rectNestedNested and set their rounding radius property to some value, i.e. 0.1in. It will make our pseudo-thermometer look closer to what was shown in the picture above. PatientsTemperature_Final.xml(change .xml to .rdlx) is the sample of the final report version and here is the output sample


is this picture informative? Yep, 3 of our 5 patients have fever and it seems that we forgot to move Mr. Jonathan Murraiin to morgue..Whoops!


Other scenarios
By using the same technique you can emulate bullet chart that uses traffic lights colors as described here.

DDR Excel Export: rendering chart report item as Excel chart object by using the Power of Templates

Preface
Excel Export in Data Dynamics Reports uses the amazing technology called “Templates” behind the scene. When a report is exported in Excel, we first build the intermediate XLS document that contains the placeholders for the actual data. This intermediate document is called “Template”.
Then we obtain the data that report normally shows and insert them in the template. The attentive reader will ask - So what? Why is this technology amazing? The answer is we expose the template to the real world: it is possible to obtain the template, modify it and pass to Excel Export. As the result the output may be tuned by creating the custom data placeholders: formulas, pivot tables and so on. In this article we will see how to solve on of the common problems with Excel export by using the Power of Templates.


The problem: chart output in Excel Export
If a report contains chart report item, then it is shown as the image in the exported XLS Document. It is not comfortable - Excel has the great charts support and it would be nice to see the DDR chart shown as Excel Chart in the output. Let’s look at hypothetical example. The application displays the attached DelayReport.rdlx(change xml to rdlx) by using the windows forms viewer and allows users to export in Excel(they just click “XLS” button and the resulting document is opened once exportation is done). The report consists of the table and the pie chart that show the data of employees delay statistic. By default the chart is transformed to the picture. The application users are not happy. They demand the Excel Pie Chart in the output. Let’s see what you can do step by step.

Templates power in action

  • Open the attached DelayReport.rdlx in the report designer - either in standalone application or visual studio integrated editor.

  • Select Report->Generate Excel Template menu item. Save the template in the appropriate location. Open the generated template in Excel.

  • The cell contains “<#Chart1#>” text is the placeholder where the chart picture is going to be inserted, so remove this text, unmerge the cell and decrease its height if it’s needed.

  • The cell contains “<#txtReason#>” text is the placeholder for “Reason” column of the table. The values from Reason column will be transformed to the range of cells. This range will start from “<#txtReason#>” cell position and grow further. Let’s name this range: select “<#txtReason#>” cell and define the new named range - in Excel 2007/2010 you can go to Formulas tab, click “Define name”, leave the default values in the popup dialog and click OK.

  • The cell contains “<#txtCasesNo#>” text is the placeholder for “CasesNo” column of the table. Name the range it will produce by using the same way as in (4).

  • Add the Pie chart on the appropriate place(Excel 2007/2010 - Insert tab, Pie chart). Right click on the chart, choose “Select Data...” and remove the default Legend Entry(Series) value.

  • Click Add on Legend Entries(Series) editor. Set Series Name to “Delays”. This will be chart title which equals to one in the original report. Then set Series Values to “=Sheet1.txtCasesNo”. This way you map the chart data to the range created on step (5).

  • Click Edit on Horizontal (Category) Axis Labels. Set labels range to “=Sheet1!txtReason”. This way you map the chart labels to the range created on step (4).

  • Note that the chart data range is set automatically. Click OK. Save the template. The attached template.xls is the sample of the described modifications result.

  • Test the exportation with the modified template. For example open the report by using DataDynamics.Reports.Preview.exe, choose Export->Excel in the toolbar. Set Template property in the popup dialog to the template path, select the output file name, click export. The attached output.xls shows the example of the output.

  • Now in your hypothetical application adjust the code of “XLS” button click handler so that the customized template is used for exportation. Use TemplateStream property.

The tip of the iceberg
What is described here is just the small piece of the great functionality that is provided by Excel Export Templates. Basically you can tune the output with any available Excel feature.