Creating your Custom Visualization Components v6.0.x

Jaspersoft Community 'Read-Only' as of July 8, 2022

Transition to New TIBCO Community Just Weeks Away

You can still search, review wiki content, and review discussions in read-only mode. Please email community@tibco.com with questions or issues requiring TIBCO review or response.

This Wiki Page is a work in progress

Creating a custom visualization component means to write a javascript file that renders an SVG shape. This script is then optimized to be used inside a report.
Jaspersoft Studio provides a wizard to help you start with all the necessary files that will compose you javascript, included a build file.

In this chapter, we will create from scratch a new template and we will use it in Jaspersoft Studio to build our report.

Tutorial material

All the code described in this tutorial is available here: custom_template_tutorial.tgz.

Some theory 1: RequireJS and creation of optimized scripts

In order to load and run the javascript that renders your custom visualization, the component uses RequireJS (http://requirejs.org/) a small javascript library useful to assure that different scripts in the same HTML document do not conflict. This is particularly important in complex environment such as JasperReports Interactive Viewer, JasperReports Server and Visualize.js.

To make the use and configuration of the components simple, all the code and optionally libraries you may want to use to produce your visualizations are merged in a single optimized and uglyfied javascript file. A special script called r.js (https://github.com/jrburke/r.js) takes all the necessary files that make up your component and produce this single file. The files that make up your component are specified in a file called build.js.

As we will see later in this tutorial, Jaspersoft Studio has a wizard to automatically generate this build.js file to include popular libraries like D3.js and RaphaelJS.

The file that is produced, usually ending by .min.js will represent your component. Most of the time you will also have a second file for styling your component, which is a css file.

Some theory 2: Datasets and Properties

In order to plan our work to design our new component, let's take a look what data it will be able to use, coming from the report. The component element, once placed inside a report, can be configured by means of a set of properties (key/value) and Item Data. Item Data are used to collect set of Items, which are also composed by properties.

The value of each property can be a static text or the result of an expression. The value of the property is converted to a string when the component is printed, so the use of complex objects as property value is discouraged, even if still possible when, for instance, the specific property is meant to be consumed by a custom processing class.

The component and Items properties required by a specific custom visualization template are defined by the template designer, who will assume to get the information required by her/his custom visualization. In example, if we plan to create a visualization that shows points on a map, we may decide to have a component property to let the user specify the map background color, let's say backgroundColor, and three properties: label, latitude, longitude for the Items of the Data Item.

When the report is executed, the data collected is stored in a special object called Configuration, which will be serialized in a JSON structure and passed to the javascript function in charge to produce the visualization. In particular this javascript function must create new SVG tag. When exporting in HTML, this tag is automatically rendered by the browser. When the report is exported in other formats, the reporting engine uses PhantomJS to execute the javascript code and extract the SVG. The SVG image will then be included in formats like PDF, or converted in an high quality PNG image in formats like MS Excel, Words, etc..

There are three important and reserved properties that you need to be aware of:

Property name
Description
Expression Type
Mandatory
script

Location of the javascript file of the component

String | File | URL | InputStream

Yes
css (Optional) location of a css file to style the component String | File | URL | InputStream No
module (Optional) the name of the requirejs module used to render the component String Only if the script is not a String or a File

script: the script property is Mandatory. It specifies from where to load the script used by the component. The script must be an optimized script generated using r.js. It will be loaded by requireJS. The property can be a simple string like "mycomponent.min.js", or a java object (when provided by means of an expression) of type String, File, URL or InputStream, it works in the same way as the Image Expression Element for regular JasperReports image elements.

css: the css property works like script, but it is used to specify a css file. The content of this file will be injected inside a <style> tag directly in the generated HTML. Later in this tutorial you will learn how to make sure that the styles are applied only to a specific component.

module: this property is a simple string that tells the component which RequireJS module must be invoked to render the component. If not specified, the module name will be deducted from the name of the script (by stripping .js or .min.js). I.e. if the name of the script provided is mycomponent.min.js, the module will default to mycomponent . If the script property does not reference a file (i.e. it is an InputStream) and this property is not set, an exception will be thrown by the component ("No 'module' property defined for a Custom Visualization Component.").

Creating the component

After the theory, let's start with the practice. The creation of the component is decoupled from the report design.There are several approaches to create it. The best approach is to create a simple web page and create a module containing the relevant code that will make up the script. This will also simplify the subsequent deployment.

Note: The previous version of this tutorial were based on a very complex D3js chart ( http://bost.ocks.org/mike/nations/ ). To keep the tutorial simple enough, we changed the chart. An advanced tutorial will be written for the old example.

Jasperosft Studio provides a wizard to make you up and running quickly. The wizard simply generates a small sample custom visualization component based either on the D3 javascript library and RaphaelJS SVG javascript library. We will use it in this tutorial and will make some changes to see how to pass data from the custom component that will be configured inside the report.

Select File > New > Other... from the menu, and select Custom Visualization Component from the Jaspersoft Studio category.

Specify a name for the project. This name will also be used for our new project and also for our javascript file: for this reason, spaces are not allowed, a good practice is also to keep the name all lowercase. In this tutorial we will use the name tutorial.

To proceed we also need to select a base project to start with, select the first one called "Circle Sample based on D3.js Library".

In the following steps, D3.js will be downloaded (it is not shipped with Jaspersoft Studio), and you will be asked to agree on its license to proceed.
Click Finish at the end of the wizard.

Jaspersoft Studio will create a new project with the given name. Please note that a project is not really necessary to create a component, you can copy all the files in a folder inside an existing project, but this will keep our work more organized.

In the picture is summarized the set of files created by the wizard:

build.js is a javascript file containing a require.js configuration. It is used to assemble all the required javascript libraries and the component specific code inside a single minified and uglyfied javascript, which represents the component script (in other words the one shipped along the report).

d3_Circle_sample.jrxml is a simple jrxml which uses our component. It is essentially a test report that uses the newly created component

d3.min.js is the D3js library downlaoded by Jaspersoft Studio and mentioned inside build.js

tutorial.css is a CSS file used to style the SVG created by the script. This css is not mandatory, but very useful to easily customize the look and feel of a component

tutorial.js is the most important file here. It is a require.js module that renders our SVG, it is the file that we will work with to change the behavior of our custom component.

To be able to run the sample, we need to compile the component: the compilation process will merge the d3.min.js and the tutoria.js files in a singe file (accordingly to what is specified inside build.js).

To compile right click the project folder and select Build All Components or (even better), right click the build.js file, right click and select Build Component. The first option (Build All Components) will run the compilation process for all the build.js files available in the project, a convenient way to build several components kept in the same project.

When a build.js is built, Jaspersoft Studio executes behind the scenes the r.js script (http://requirejs.org/docs/optimization.html) against the selected build.js. The output of the building process is shown in the console view:

The result is a new file called tutorial.min.js which will appear in the project folder. Depending by the size and complexity of the involved libraries and scripts, the compilation process may take several seconds.

Before proceed in customizing our component, let's see what the sample produces by running the sample (d3_Circle_sample.jrxml). Open this report and preview it. This report contains a custom visualization component element preconfigured to use tutorial.min.js as script, tutorial.css as css file and reference the module d3Circle, which is the name of the requirejs module defined inside tutoria.js.

The sample is kept trivial on purpose, it does not use any data and just draws a circle.

Let's take a look a deeper look at the code starting from the tutorial.js

Hint: Jaspersoft Studio is not the most suitable application to write javascript code, and by default the files are open with the default editor set on your computer to edit javascript files. To open the code in Studio with the default text editor, right click the file and select Open Width > Text Editor

define('d3Circle',['d3'], function (d3) {
     return function (instanceData) { 
        var w = instanceData.width,
            h = instanceData.height;
 
        var margin = 20;
        var diameter = Math.min(w,h) - margin;
 
        var svg = d3.select("#" + instanceData.id).insert("svg")
                    .attr("id", instanceData.id + "svg")
                    .attr("width", w)
                    .attr("height", h);
 
        var circle = svg.append("circle")
                        .attr("cx", w/2)
                        .attr("cy", h/2)
                        .attr("r", diameter/2);
     };
});

tutoria.js defines a new requirejs module called d3Circle. 'define' is the requirejs function to define a new module. The first argument is the module name, the second is an array with the module dependencies, the third argument is a function that in case of the Custom Visualization Component returns another function which take an object called instanceData as argument. This object contains a set of properties that can be used by the script to build the SVG. In the following table is summarized the content of this object.

Property name
Type
Description
Example
id String It is the element id of the DIV inside which the SVG must be created element1311624546
width integer The width of the DIV (which may be used as width of the SVG) 555
height integer The height of the DIV (which may be used as height of the SVG) 376
isInteractiveViewer String This property tells if the report is currently executed inside an interactive report viewer. It can be either "true" or "false" false
series Array It is an array of series, which will then contain, if present, the records of each series
script_uri String The name of the script that renders this component. This property is used internally by Visualize.js

If other properties have been defined in the component element, they will show up in this object. This is the first way to pass values from the component setup in the report and the script that will render it.

Looking at the code, results now clear why width and height of the drawn circle are taken from the instanceData.

CSS and element ID

To style the visualization is convenient to use the css file (even if inline style can be dynamically generated also by the script). In order to be able to style individually each SVG in our report, we need to reference an element id. The element id available in the instanceData object is the element id of the DIV containing the SVG, and is generated at run time, so it cannot be hardcoded in the static css file. For this reason, the css provided with the component is processed by the component itself, which replace the occurrences of /*eleid*/ with something like #element123456 (which is the css syntax to reference a specific element id).

In example the css:

/*elid*/svg circle {
fill: #F000FF;
}

will become

#element123456svg circle {
fill: #F000FF;
}

This solves the problem of referencing exactly the content of each custom component instance in our css, but this is not enough. As you can see in the css code above we did not add any space after the element id and the tag name svg. Usually, to style all the svg elements inside a div you would write "#element123456 svg" (note the space before svg). Anyway, when the SVG is extracted to be exported in PDF and the other formats (excluded HTML) if the style does not belong directly to the SVG, it is not correctly applied. To prevent this, we give an id to the SVG tag (i.e "element123456svg"), so we will style directly the SVG tag (and not the content of the wrapping DIV). The id assignment must be done by our script. In tutorial.js this is done with the following line of code (highlighted in blue):

var svg = d3.select("#" + instanceData.id).insert("svg").attr("id", instanceData.id + "svg")

Reference

Feedback