| JasperReports Ultimate Guide - Samples - Schema - Configuration - Functions - FAQ - API (Javadoc)
|
|
|
|
|
| JasperReports - Custom Visualization Components Sample (version master-SNAPSHOT) | |
|
|
|
|
|
|
| Main Features in This Sample | |
|
| Custom Visualization Components |
|
|
|
||||
| top | |||||
|
|
|||||
![]() | Custom Visualization Components | Documented by Giulio Toffoli | |||
|
|
|||||
|
| Description / Goal |
| Shows how to render a custom visualization in a report, using the custom visualization component shipped with the JasperReports library. | ||
|
| Since |
| 6.7.0 | ||
|
|
|||||
|
|
Custom Visualization Component Overview
The Custom Visualization Component allows to render an SVG image generated by using JavaScript code. Its main goal is to leverage JavaScript visualization libraries (such as d3.js) in order to produce content to be rendered in the report. This component does not produce any content itself, instead it acts as bridge between the JasperReports library and the JavaScript module provided by the user, which at the end is responsible to produce the visualization. In case the report is exported to HTML, the JavaScript code is executed directly inside the final document. This allows to take full advantage of the browser functionalities. When the report is exported to other file formats (such as PDF or MS Word), the component takes care of rendering the SVG image produced by the JavaScript code, behaving like a regular image element. If the script does not produce SVG image, but more complex HTML, the visualization can be rendered as PNG image when exported to formats different from HTML. Custom Visualization Component Schema Below is the main part of the custom visualization component schema. As any other component element, the evaluationTime and evaluationGroup attributes are provided:
<element name="customvisualization" substitutionGroup="jr:component">
<complexType>
<complexContent>
<extension base="jr:componentType">
<sequence>
<element name="itemProperty" type="c:ItemProperty" minOccurs="0" maxOccurs="unbounded" />
<element ref="cvc:cvData" minOccurs="0" maxOccurs="unbounded" />
</sequence>
<attribute name="evaluationTime" type="jr:basicEvaluationTime" use="optional" default="Now"/>
<attribute name="evaluationGroup" type="string" use="optional"/>
<attribute name="processingClass" type="string" use="optional"/>
<attribute name="onErrorType" use="optional" default="Error">
<simpleType>
<restriction base="string">
<enumeration value="Error"/>
<enumeration value="Blank"/>
<enumeration value="Icon"/>
</restriction>
</simpleType>
</attribute>
</extension>
</complexContent>
</complexType>
</element>
Main Properties
Since the custom visualization component works like a wrapper, its definition is very generic and based on simple properties ( itemProperty). There are four common properties that can be used with
any custom visualization component:
The value for the properties can be either a static value or a value defined by means of an expression. Configuring Data Series One or more series of data may be provided to the script implementing the visualization by means of cvData
elements:
<element name="cvData">
<complexType>
<sequence>
<element ref="jr:dataset" minOccurs="0" maxOccurs="1"/>
<element ref="cvc:item" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
A cvData can collect its data either from a subdataset, or from a hardcoded list of cvc:item.
Each cvc:item is defined by a set of ItemProperty elements.
The name of each item property to be set for each cvc:item depends by the component we are working with.
The Sparkline sample uses a subdataset to populate a simple series of values. In this case each cvc:item
has a single ItemProperty called value.
Custom Visualization Component Samples This sample contains the implementation of 6 custom visualizations:
demo/samples/customvisualization/components folder.
Each custom visualization is composed by one or more JavaScript files that are combined and optimized by using RequireJs. This optimization process creates a single minified JavaScript file which represents the custom visualization component referenced inside the report template by means of the script property described above.
To generate the components from the sources, in a command prompt/terminal window set the current folder to demo/samples/customvisualization
within the JasperReports source project and run the > ant components command.
The generated components will be saved in demo/samples/customvisualization/build/components, each in its own directory.
Creating Your Own Custom Visualization Component To implement a new Custom Visualization Component we need to define a JavaScript module that returns an anonymous function implementing the component logic. This module will be then optimized and combined with the JavaScript libraries used by the component (if any) with the RequireJs optimizer (r.js). The build process is configured in a file called build.js in which dependencies, module name and other information are specified.
Before starting, it is important to keep in mind that Custom Visualization Components are not able to stretch, which means that the allocated space in the report for the component is defined at design time and will not change based on what is rendered. This is the same behavior of other elements such charts and images. It is also important to notice that producing an SVG image provides much better results over complex HTML content, which would need to be rendered as a PNG image. Let's create a simple component named simplerectangle which displays a simple SVG rectangle. We start by creating a file called simplerectangle.js. The content of this file would be something like:
define('simplerectangle', [], function () {
return function (instanceData) {
var w = instanceData.width, // The width of the element
h = instanceData.height; // The height of the element
var container = window.document.getElementById(instanceData.id);
// Create the SVG Document
var svgDocument = window.document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgDocument.setAttributeNS(null, "width", w);
svgDocument.setAttributeNS(null, "height", h);
// Create the SVG Rectangle
var rectangle = window.document.createElementNS("http://www.w3.org/2000/svg", "rect");
rectangle.setAttributeNS(null, "x", 0);
rectangle.setAttributeNS(null, "y", 0);
rectangle.setAttributeNS(null, "width", w);
rectangle.setAttributeNS(null, "height", h);
rectangle.setAttributeNS(null, "fill", "red");
// Add the rectangle to the SVG
svgDocument.appendChild( rectangle );
// Add the SVG to the container
container.appendChild( svgDocument );
};
});
The instanceData object passed to our function holds all the properties and data series defined in the component configuration.
The simplest instanceData object would look like:
{
"module":"simplerectangle",
"id":"element1412794598",
"width":802,
"height":475,
"isInteractiveViewer":"false",
"script_uri":"simplerectangle/simplerectangle.min.js",
"series":[]
}
In order to generate the RequireJS module, we create a build.js file as follow:
({
optimize: 'none',
baseUrl: '',
paths: {
'simplerectangle': 'simplerectangle'
},
wrap: {
start: "(function(root){\n\nvar define = root.define;\n\n",
end: "\n\n}(typeof __visualize__ != 'undefined' ? __visualize__ : (typeof __jrio__ != 'undefined' ? __jrio__ : window)));"
},
name: "simplerectangle",
out: "simplerectangle.min.js"
})
We list the files to combine in paths, in the form of
module: 'path_to_file'
In this example we have only one file called basic.js, the extension .js is omitted.
The wrap option is used to be sure that this component will work properly in evnironments like JasperReports IO and JasperReports Server interactive viewers.
To generate the final component we can use different tools (i.e. Java or Node). To compile the file using Node, be sure node is installed, then in a command prompt/terminal window set the current folder to the folder in which you created your component (i.e. demo/samples/customvisualization/components/basic within the JasperReports source project) then run the command:
> node ../../libraries/requirejs/r-2.3.5.js -o build.js
To compile the file using Java, the Rhino JavaScript engine is used. Here is the command to run: > java -cp /path/to/rhino.jar org.mozilla.javascript.tools.shell.Main -opt -1 ../../libraries/requirejs/r-2.3.5.js -o build.js
The full reference of the build.js file is available at https://github.com/requirejs/r.js/blob/master/build/build.js
We will use this newly create component in a JRXML with the following code: <componentElement>
<reportElement x="0" y="80" width="802" height="475" uuid="ba29f458-9e56-4017-b65d-8de18ac7470e" />
<cvc:customvisualization
xmlns:cvc="http://www.jaspersoft.com/cvcomponent"
xsi:schemaLocation="http://www.jaspersoft.com/cvcomponent http://www.jaspersoft.com/cvcomponent/component.xsd"
evaluationTime="Report">
<cvc:itemProperty name="module" value="simplerectangle"/>
<cvc:itemProperty name="script" value="simplerectangle/simplerectangle.min.js"/>
</cvc:customvisualization>
</componentElement>
Our component creates a rectangle by using pure JavaScript and currently it does not use any data coming from the report. Let's improve it and start rendering real data. We will create a new component named d3rectangle and use a
JavaScript library to simplify the way we generate our SVG code.
D3.js is an extremely powerful library to display data by generating SVG. We start by declaring a dependency to d3.js in our build.js file as follow:
({
optimize: 'none',
baseUrl: '',
paths: {
'd3': 'd3': '../../libraries/d3/d3-5.5.0.min',
'd3rectangle': 'd3rectangle'
},
wrap: {
start: "(function(root){\n\nvar define = root.define;\n\n",
end: "\n\n}(typeof __visualize__ != 'undefined' ? __visualize__ : (typeof __jrio__ != 'undefined' ? __jrio__ : window)));"
},
name: "d3rectangle",
out: "d3rectangle.min.js"
})
The D3 function needs to be specified in our module definition in the following way:
define('d3rectangle', ['d3'], function (d3) {
return function (instanceData) {
...
At this point the d3 library is at our disposal. We will display a set of vertical lines inside our rectangle. To do that, we will
need to provide some data to the component by means of series. We expect our series to have two fields:
background.
Here is the code of our d3 based visualization:
define('d3rectangle', ['d3'], function (d3) {
return function (instanceData) {
var w = instanceData.width, // The width of the element
h = instanceData.height; // The height of the element
bgColor = instanceData.background;
// If no property called background has been provided, let's use a default gray background color.
if (typeof bgColor === 'undefined') {
bgColor = '#efefef';
}
// Add the SVG to the dom...
var svg = d3.select('#' + instanceData.id).append('svg')
.attr('width', w)
.attr('height', h);
// Add the rectangle...
var rectangle = svg.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', w)
.attr('height', h)
.attr('fill', bgColor);
// Define a scale to map the width of the component with the values range
var hscale = d3.scaleLinear()
.range([10, instanceData.width-10]) // we leave 10px padding on left and right
.domain([
d3.min(instanceData.series[0], function(d) { return +d.value; }),
d3.max(instanceData.series[0], function(d) { return +d.value; })
]);
// Add the lines
svg.append("g").selectAll("line")
.data(instanceData.series[0])
.enter()
.append('line')
.attr('x1', function(d) { return hscale(+d.value); } )
.attr('y1', 0)
.attr('x2', function(d) { return hscale(+d.value); } )
.attr('y2', h)
.attr('stroke', function(d) { return d.color; })
.attr('stroke-width', 3);
};
});
In order to use our new component, we will have to set the background property and define a sub-dataset to provide the values for the lines:
<componentElement>
<reportElement x="0" y="80" width="802" height="475" uuid="ba29f458-9e56-4017-b65d-8de18ac7470e" />
<cvc:customvisualization
xmlns:cvc="http://www.jaspersoft.com/cvcomponent"
xsi:schemaLocation="http://www.jaspersoft.com/cvcomponent http://www.jaspersoft.com/cvcomponent/component.xsd"
evaluationTime="Report">
<cvc:itemProperty name="module" value="d3rectangle"/>
<cvc:itemProperty name="script" value="d3rectangle/d3rectangle.min.js"/>
<cvc:itemProperty name="background" value="#eeeeee"/>
<cvc:cvData>
<dataset>
<datasetRun subDataset="Sample Dataset" uuid="0e1d87a7-9376-4927-9b1e-30835421a98a">
<dataSourceExpression>new net.sf.jasperreports.engine.data.JsonDataSource(
new StringBufferInputStream(
"[{ value: 20, color: 'red'}," +
"{ value: 35, color: 'green'}," +
"{ value: 78, color: 'blue'}," +
"{ value: 92, color: 'yellow'}]") )
</dataSourceExpression>
</datasetRun>
</dataset>
<cvc:item>
<cvc:itemProperty name="value" value="0">
<valueExpression>$F{value}</valueExpression>
</cvc:itemProperty>
<cvc:itemProperty name="color" value="0">
<valueExpression>$F{color}</valueExpression>
</cvc:itemProperty>
</cvc:item>
</cvc:cvData>
</cvc:customvisualization>
</componentElement>
Custom Visualization JRXML Samples This sample contains 6 JRXML files, one for each custom visualization component
Running the Sample Running the sample requires the Apache Ant library. Make sure that ant is already installed on your system (version 1.5 or later).
In a command prompt/terminal window set the current folder to demo/samples/customvisualization within the JasperReports source project and run the > ant test view command.
It will generate all supported document types containing the sample report in the demo/samples/customvisualization/build/reports directory.
Then the report will open in the JasperReports internal viewer. |
||||
|
|
|||||
|
|
| © 2001- Cloud Software Group, Inc. www.jaspersoft.com |