<?xml version="1.0" encoding="UTF-8"?>

<sample>

  <name>customvisualization</name>
  <title>Custom Visualization Components Sample</title>
  <description>Shows how JavaScript based visualizations could be included in reports using the Custom Visualization Component.</description>

  <mainFeature ref="customvisualization"/>
  
  <!-- customvisualization -->
  
  <feature name="customvisualization" title="Custom Visualization Components">
    <description>
Shows how to render a custom visualization in a report, using the custom visualization component shipped with the JasperReports library.
    </description>
    <since>6.7.0</since>
    <documentedBy>
      <author>
    	<name>Giulio Toffoli</name>
    	<email>gt78@users.sourceforge.net</email>
      </author>
    </documentedBy>
    <content>
<b>Custom Visualization Component Overview</b>    
<br/>
<br/>
The Custom Visualization Component allows to render an SVG image generated by using JavaScript code.<br/>
Its main goal is to leverage JavaScript visualization libraries (such as d3.js) in order
to produce content to be rendered in the report.<br/>
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.<br/>
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.<br/>
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.<br/>
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.
<br/>
<br/>
<subtitle name="schema">Custom Visualization Component Schema</subtitle>
<br/>
<br/>
Below is the main part of the custom visualization component schema.
As any other component element, the <code>evaluationTime</code> and <code>evaluationGroup</code> attributes are provided:

<pre><![CDATA[<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>]]></pre>


<subtitle name="schema">Main Properties</subtitle>
<br/>
<br/>
Since the custom visualization component works like a wrapper, its definition is very generic and based on
simple properties (<code>itemProperty</code>). There are four common properties that can be used with
any custom visualization component:
<ul>
    <li><code>script</code> - the location of the JavaScript file implementing the component</li>
    <li><code>module</code> - (optional) the name of the JavaScript module to be loaded by using RequireJs (if not specified,
    the base name of the JavaScript file without extensions will be assumed as name of the module)</li>
    <li><code>css</code> - (optional) the location of a CSS file eventually used by the component</li>
    <li><code>renderAsPng</code> - (optional) a boolean value that can be used when the content produced is not an SVG image</li>
</ul>

All the configured properties will be passed to the JavaScript function in charge of rendering the visualization.<br/>
The value for the properties can be either a static value or a value defined by means of an expression.
<br/>
<br/>
<subtitle name="schema">Configuring Data Series</subtitle>
<br/>
<br/>
One or more series of data may be provided to the script implementing the visualization by means of <code>cvData</code>
elements:<br/>

<pre><![CDATA[<element name="cvData">
  <complexType>
    <sequence>
      <element ref="jr:dataset" minOccurs="0" maxOccurs="1"/>
      <element ref="cvc:item" minOccurs="0" maxOccurs="unbounded"/>
    </sequence>
  </complexType>
</element>]]></pre>

A <code>cvData</code> can collect its data either from a subdataset, or from a hardcoded list of <code>cvc:item</code>. 
Each <code>cvc:item</code> is defined by a set of <code>ItemProperty</code> elements.<br/>The name of each item property to
be set for each <code>cvc:item</code> depends by the component we are working with.<br/>
<br/>
The Sparkline sample uses a subdataset to populate a simple series of values. In this case each <code>cvc:item</code>
has a single <code>ItemProperty</code> called <i>value</i>.<br/>

<br/>
<br/>
<subtitle name="customvisualization_components">Custom Visualization Component Samples</subtitle>
<br/>
<br/>
This sample contains the implementation of 6 custom visualizations:
<ul>
<li><b>Simple Rectangle</b> - A very simple visualization to explain the basics of creating your own Custom Visualization Component.<br/><br/></li>
<li><b>D3 Rectanle</b> - An improved version of Simple Rectangle which use d3.js. The component accepts a configuration parameter and
displays vertical lines based on provided data.<br/><br/></li>
<li><b>Figures</b> - A d3.js based visualization to represent a quantity by using figures.<br/>
    <img src="figures.png"/><br/><br/>
</li>
<li><b>Radial Progress</b> - A d3.js based visualization to display a percentage value with a circle<br/>
    <img src="radialprogress.png"/><br/><br/>
</li>
<li><b>Sparkline</b> - A d3.js based minimalist line chart which displays data coming from a sub-dataset<br/>
    <img src="sparkline.png"/><br/><br/>
</li>
<li><b>LeafLet Markers</b> - A map with markers implemented by using the LeafLet.js mapping library<br/>
    <img src="leafletmarkers.png"/><br/><br/>
</li>
</ul>

The source code of the custom visualizations can be found in the
<code>demo/samples/customvisualization/components</code> folder.<br/>
Each custom visualization is composed by one or more JavaScript files that are combined and optimized by using RequireJs.<br/>
This optimization process creates a single minified JavaScript file which represents the custom visualization component
referenced inside the report template by means of the <code>script</code> property described above.<br/><br/>
To generate the components from the sources, in a command prompt/terminal window set the current folder to <code>demo/samples/customvisualization</code>
within the JasperReports source project and run the <code>&gt; ant components</code> command.<br/>
The generated components will be saved in <code>demo/samples/customvisualization/build/components</code>, each in its own directory.

<br/>
<br/>
<subtitle name="customvisualization_sample">Creating Your Own Custom Visualization Component</subtitle>
<br/>
<br/>
To implement a new Custom Visualization Component we need to define a JavaScript module that returns an anonymous function implementing the component logic.<br/>
This module will be then optimized and combined with the JavaScript libraries used by the component (if any) with the RequireJs optimizer (r.js).<br/>
The build process is configured in a file called <code>build.js</code> in which dependencies, module name and other information are specified.<br/>
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.<br/>
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.<br/>
<br/>
Let's create a simple component named <i>simplerectangle</i> which displays a simple SVG rectangle.<br/>
We start by creating a file called <i>simplerectangle.js</i>. The content of this file would be something like:<br/>
<pre>
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 );
  };
});
</pre>
The <code>instanceData</code> object passed to our function holds all the properties and data series defined in the component configuration.<br/>
The simplest instanceData object would look like:<br/>
<pre>
{  
   "module":"simplerectangle",
   "id":"element1412794598",
   "width":802,
   "height":475,
   "isInteractiveViewer":"false",
   "script_uri":"simplerectangle/simplerectangle.min.js",
   "series":[]
}
</pre>

<br/>
In order to generate the RequireJS module, we create a <code>build.js</code> file as follow:
<pre>
({
  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"
})
</pre>
We list the files to combine in <code>paths</code>, in the form of<br/>
<code>module: 'path_to_file'</code>
In this example we have only one file called <code>basic.js</code>, the extension .js is omitted.<br/>
The <code>wrap</code> option is used to be sure that this component will work properly in evnironments like JasperReports IO and JasperReports Server interactive viewers.<br/>
<br/>
To generate the final component we can use different tools (i.e. Java or Node).<br/>
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.  <code>demo/samples/customvisualization/components/basic</code> within the JasperReports source project) then run the command:<br/>
<br/>
<code>&gt; node ../../libraries/requirejs/r-2.3.5.js -o build.js</code><br/>
<br/>
To compile the file using Java, the Rhino JavaScript engine is used. Here is the command to run:<br/>
<br/>
<code>&gt; java -cp /path/to/rhino.jar org.mozilla.javascript.tools.shell.Main -opt -1 ../../libraries/requirejs/r-2.3.5.js -o build.js</code><br/>
<br/>
The full reference of the <code>build.js</code> file is available at <a href="https://github.com/requirejs/r.js/blob/master/build/build.js">https://github.com/requirejs/r.js/blob/master/build/build.js</a><br/>
<br/>
We will use this newly create component in a JRXML with the following code:<br/>
<pre><![CDATA[<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>]]></pre>
<br/>
<br/>
Our component creates a rectangle by using pure JavaScript and currently it does not use any data coming from the report.<br/>
Let's improve it and start rendering real data. We will create a new component named <code>d3rectangle</code> and use a
JavaScript library to simplify the way we generate our SVG code.<br/>
D3.js is an extremely powerful library to display data by generating SVG. We start by declaring a dependency to d3.js in our
<code>build.js</code> file as follow:<br/>
<pre>
({
  optimize: 'none',
  baseUrl: '',
  paths: {
    <strong>'d3': 'd3': '../../libraries/d3/d3-5.5.0.min',</strong>
    '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"
})
</pre>
The D3 function needs to be specified in our module definition in the following way:<br/>
<pre>
define('d3rectangle', [<strong>'d3'</strong>], function (<strong>d3</strong>) {

  return function (instanceData) {
            ...
</pre>
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:
<ul>
    <li><code>value</code> - which will be used to determine the horizontal position of our line</li>
    <li><code>color</code> - a string defining the color used to plot the line</li>
</ul>
We will also provide a property to set the background color for our rectangle, which we will call <code>background</code>.<br/>
Here is the code of our d3 based visualization:<br/>
<pre>
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);             

  };
});
</pre>
In order to use our new component, we will have to set the <code>background</code> property and define a sub-dataset to provide the values for the lines:<br/>
<pre><![CDATA[<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>]]>
</pre>


<br/>
<br/>
<subtitle name="customvisualization_sample">Custom Visualization JRXML Samples</subtitle>
<br/>
<br/>
This sample contains 6 JRXML files, one for each custom visualization component

<ol start="1">
<li><subtitle name="simplerectangle_report">Simple Rectangle</subtitle>
<br/>
<br/>
This report template contains the Simple Rectangle component described in the section above, which creates a simple rectangle
without displaying any specific data.
</li>
</ol>

<ol start="2">
<li><subtitle name="d3rectangle_report">D3 Rectangle</subtitle>
<br/>
<br/>
This report template contains the D3 Rectangle component described in the section above, which creates a rectangle
with a configurable background color and a set of lines provided by means on a sub-dataset.
</li>
</ol>

<ol start="3">
<li><subtitle name="figures_report">Figures</subtitle>
<br/>
<br/>
This report template shows how to use the Figures component with different configuration options.<br/>
The report does not use any data; for each component a static value is set for the property "itemsValue".
</li>
</ol>

<ol start="4">
<li><subtitle name="radial_progress_report">Radial Progress</subtitle>
<br/>
<br/>
This report template shows how to use the Radial Progress component with different configuration options.<br/>
The report does not use any data; for each component a static value is set for the property "value".
</li>
</ol>
<ol start="5">
<li><subtitle name="sparkline_report">Sparkline</subtitle>
<br/>
<br/>
This report template shows how to use the Sparkline component with different configuration options.<br/>
The report does not use any data; for each component a sub-dataset is feed with static JSON data by using an expression.
</li>
</ol>
<ol start="6">
<li><subtitle name="shipments_report">LeafLet Markers</subtitle>
<br/>
<br/>
This report template shows how to use the LeafLet Markers component. Marker locations are read by a JSON file provided with the sample.<br/>
Differently from the other samples, this one uses the property <code>saveAsPng</code> since the JavaScript code does not produce
an SVG, but a more complex HTML visualization.
<br/>
</li>
</ol>

<br/>
<br/>
<b>Running the Sample</b>
<br/>
<br/>
Running the sample requires the <a href="http://ant.apache.org/">Apache Ant</a> library. Make sure that <code>ant</code> is already installed on your system (version 1.5 or later).
<br/>
In a command prompt/terminal window set the current folder to <code>demo/samples/customvisualization</code> within the JasperReports source project and run the <code>&gt; ant test view</code> command.
<br/>
It will generate all supported document types containing the sample report in the <code>demo/samples/customvisualization/build/reports</code> directory. 
<br/>
Then the report will open in the JasperReports internal viewer.
    </content>
  </feature>
</sample>
