Preface
This document describes two functional modules of the CUBA platform, which display charts and geographic maps respectively. These subsystems are implemented in the same application component – charts – and thus can only be included in an application project together.
Charts and map display functionality is currently available only for the web client.
Target Audience
This manual is intended for developers building applications using CUBA platform. It is assumed that the reader is familiar with the Developer’s Manual, which is available at https://www.cuba-platform.com/manual.
Additional Materials
This guide, as well as any other documentation on CUBA platform, is available at https://www.cuba-platform.com/manual.
CUBA charts display subsystem implementation is based on AmCharts library, therefore familiarity with this library may be beneficial. See http://www.amcharts.com.
Feedback
If you have any suggestions for improving this manual, feel free to report issues in the source repository on GitHub. If you see a spelling or wording mistake, a bug or inconsistency, don’t hesitate to fork the repo and fix it. Thank you!
1. Displaying Charts
CUBA platform charts display subsystem supports various chart types: pie charts, line plots, bubble charts, radar charts, funnel charts, stock charts and more. It is also possible to export charts. Most chart types support zoom and scrolling. The charts are supported in web client only.
AmCharts library which is the basis of the chart display subsystem is distributed under a license, which allows its free use if you keep the link to the library website. Alternatively, you can purchase an AmCharts license for your project and remove the link.
1.1. Add Charts Dependency
To use charts in your project, activate the charts item in the App components list on the Project properties page of CUBA Studio.
1.2. Configuring Charts
Charts are displayed using the Chart
component acting as a universal canvas. Chart type is defined by the subtype interface that inherits the Chart
interface.
Charts can be described both in a screen XML-descriptor or in a screen controller. To do this, you should connect the corresponding namespace
to the descriptor:
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...>
XML elements corresponding to different chart types:
-
chart:xyChart
- XYChart -
chart:serialChart
- SerialChart -
chart:pieChart
- PieChart -
chart:funnelChart
- FunnelChart -
chart:gaugeChart
- AngularGaugeChart -
chart:radarChart
- RadarChart -
chart:ganttChart
- GanttChart -
chart:stockChart
- StockChart
Each chart type has its own set of attributes and methods, which replicate the functionality of the corresponding charts from AmCharts library. Documentation on the properties and methods of the charts is available at docs.amcharts.com/3/javascriptcharts.
The following elements can be used for declarative configuration of all types of charts:
-
chart:allLabels
- contains thelabel
elements with label text and its properties. Labels can be placed on a certain position on the chart, for example:<chart:allLabels> <chart:label x="200" y="700" text="You can place a label at any position on the chart" color="DARKBLUE" align="CENTER" rotation="-30"/> </chart:allLabels>
-
chart:balloon
- sets the configurations of balloons (tooltips) of the chart that follow the mouse cursor when you roll-over the data items. For example:<chart:graphs> <chart:graph balloonText="[[category]]: [[value]] m/s" bullet="ROUND" fillAlphas="0.3" valueField="value"/> </chart:graphs> <chart:balloon adjustBorderColor="false" color="WHITE" horizontalPadding="10" verticalPadding="8"/>
The balloon text is defined by the
balloonText
attribute of each chart graph.-
additionalFields
attributeInterpolation of chart data is available for all fields used in the chart, such as
titleField
,valueField
,category
,value
,description
,percents
,open
etc, as well as HTML tags.You can also fetch more entity attributes from the data provider using the
additionalFields
attribute. This attribute allows you to add the passed entity attributes to the chart query and send the extracted data to the UI, so that you can use the entity attribute names directly in the chart configuration.In the example below
title
is the graph title,category
is the value on the category axis,value
is the value on the value axis, andoptional
is theIncomeExpenses
entity attribute fetched to be interpolated in theballoonText
:<chart:serialChart additionalFields="optional" addClassNames="true" categoryField="year" datasource="incomeExpensesDs" startDuration="1"> <chart:graphs> <chart:graph alphaField="alpha" balloonText="<span style='font-size:12px;'>[[title]] in [[category]]:<br> <span style='font-size:20px;'>[[value]]</span> [[optional]]</span>" dashLengthField="dashLengthColumn" title="Income" type="COLUMN" valueField="income"/> <...> </chart:graphs> </chart:serialChart>
The list of fields can be added declaratively as a comma-separated string:
additionalFields="income,expense,vat"
or programmatically in the screen controller:
List<String> fields = Arrays.asList("income", "expense", "vat"); ganttChart.setAdditionalFields(fields);
-
-
chart:chartScrollbar
(for SerialChart and XYChart) - the chart’s scrollbar.-
You can set the concrete graph to zoom by the scrollbar, for example:
<chart:chartScrollbar graph="g1" autoGridCount="true" scrollbarHeight="30"/>
-
The
chart:chartScrollbarSettings
element enables you to customize the scrollbar’s properties.<chart:chartScrollbarSettings graph="stockGraph" usePeriod="10mm" position="TOP"/>
-
In addition, the GanttChart may have a
chart:valueScrollbar
element for scrolling the value axis, whilechart:chartScrollbar
will be used for zooming the category axis.<chart:valueScrollbar autoGridCount="true" color="BLACK"/> <chart:chartScrollbar autoGridCount="true" color="DARKOLIVEGREEN"/>
-
-
chart:cursor
- an optional element adding a cursor to the chart; the cursor follows the mouse pointer and shows a tooltip with the value of the corresponding point on a chart.<chart:chartCursor cursorAlpha="1" cursorColor="#258cbb" cursorPosition="MOUSE" limitToGraph="g1" pan="true" valueLineAlpha="0.2" valueLineBalloonEnabled="true" valueLineEnabled="true" valueZoomable="true"/>
-
chart:data
- an optional element for data binding used mostly for prototyping. -
chart:export
- an optional element that enables chart export. The default export implementation adds a floating download button on the chart:
-
chart:guides
- horizontal/vertical guidelines.<chart:guides> <chart:guide category="2001" dashLength="2" fillAlpha="0.2" fillColor="#CC0000" inside="true" label="fines for speeding increased" labelRotation="90" toCategory="2003"/> <chart:guide category="2007" dashLength="2" inside="true" label="motorcycle fee introduced" labelRotation="90" lineAlpha="1" lineColor="#CC0000"/> </chart:guides>
-
chart:legend
- an element that defines the chart legend, for example:<chart:legend autoMargins="false" marginRight="20" markerType="CIRCLE" position="RIGHT" valueText="[[category]]: [[value]] %"/>
-
chart:nativeJson
- JSON configuration of the chart.
-
chart:titles
- axis titles, for example:<chart:titles> <chart:title alpha="1" bold="true" color="DARKSLATEGREY" size="20" tabIndex="0" text="Main title"/> <chart:title alpha="0.5" color="BISQUE" size="12" text="Subtitle"/> </chart:titles>
-
chart:responsive
- the chart plugin that makes the chart responsive.It enables scaling-down and -up chart visual features automatically in order to adjust the chart to the screen resolution changes. You can find more information on the
responsive
plugin on the AmCharts website.The
responsive
element should contain the enclosedrules
element where the rules of accommodation are defined. You can make the chart hide or show the legend, axis titles, guides, chart titles, zoom controls, move labels inside plot area and so on:<chart:responsive enabled="true"> <chart:rules> <chart:rule maxWidth="400"> <![CDATA[ { "precision": 2, "legend": { "enabled": false }, "valueAxes": { "inside": true } } ]]> </chart:rule> </chart:rules> </chart:responsive>
Any configuration attribute can be set to null
; in this case the system will use the default value (except the cases specified in the AmCharts documentation).
Configuring charts in a screen controller is performed following the same logic. You can configure a simple property, as well as a composite object set:
pieChart.setWidth("700px");
pieChart.setTitleField("description")
.setValueField("value")
.setStartAngle(312)
.setLegend(new Legend()
.setMarkerType(MarkerType.CIRCLE)
.setPosition(LegendPosition.RIGHT)
.setMarginRight(80))
.addLabels(
new Label()
.setText("Sample Chart")
.setSize(26)
.setBold(true)
.setAlign(Align.CENTER),
new Label()
.setText("extra information")
.setAlign(Align.RIGHT))
.setLabelTickColor(Color.GOLDENROD)
.setColors(Arrays.asList(
Color.valueOf("#446493"),
Color.valueOf("#5E3D2C"),
Color.valueOf("#D0A557")))
.setDatasource(valueDescriptionsDs);
Messages used for displaying charts can be overridden or localized in the main message pack of the web module. Some localizations are available on CUBA GitHub.
1.3. Charts Export
All charts can be exported from the running application as a picture or a source data. The chart:export
element is used to create default export menu that enables the following options:
-
Download as… with available formats: PNG, JPG, SVG, PDF
-
Save as… with available formats: CSV, XLSX, JSON
-
Annotate… which is used to add personal notes and vector shapes to the chart. You can find information on the annotation plugin here.
-
Print that opens the standard print settings window.
The export menu can be customized to limit user access to the chart data, for example:
<chart:export fileName="my-chart" position="TOP_RIGHT">
<chart:menu>
<chart:item label="PNG" title="Save as PNG" format="PNG"/>
<chart:item label="JPG" title="Save as JPG" format="JPG"/>
</chart:menu>
</chart:export>
In this case only direct download buttons for chosen formats will be available:
You can define the following export settings:
-
backgroundColor
- code of the color for the background of the exported image. Default value is#FFFFFF
. -
dataDateFormat
- the format to convert date strings to date objects in data export only. -
dateFormat
- formats the category field in the given date format (data export only). -
enabled
- enables or disables the export functionality. -
exportSelection
- exports the current data selection only. Default value isfalse
. -
exportTitles
- exchanges the data field names with its dedicated title. Default value isfalse
. -
fileListener
- iftrue
, it observes the drag and drop feature and loads the dropped image file into the annotation. Default value isfalse
. -
fileName
- a file name to use for generated export files (an extension will be appended to it based on the export format). -
keyListener
- iftrue
, observes the pressed keys to undo/redo the annotations. -
position
- position of export icon. Possible values:TOP_LEFT
,TOP_RIGHT
(DEFAULT),BOTTOM_LEFT
,BOTTOM_RIGHT
. -
removeImages
- iftrue
, export checks for and removes unnecessary images that area loaded from different domains.
The following properties enable you to customize each export option:
- JPG
-
-
quality
- quality of the resulting image. Possible values0
-1
. Default value is1
.
-
- PNG, JPG, SVG, PDF
-
-
multiplier
- scale factor for the generated image.
-
- CSV
-
-
quotes
- sets whether to enclose strings in double quotes. Default value istrue
. -
delimiter
- a string to use as a column delimiter. Default value is "," (comma). -
escape
- defines whether to escape strings. Default value is true. -
withHeader
- adds header row with column names. Default value istrue
.
-
- XLSX
-
-
dateFormat
- the XLSX date format mask. Do not forget to setparseDates
totrue
in CategoryAxis. -
stringify
- converts all cell content to strings. Default value isfalse
. -
withHeader
- adds header row with column names. Default value istrue
.
-
-
-
pageOrientation
- the page orientation. Default value isPORTRAIT
. -
pageOrigin
- shows / hides the origin of the generated PDF. Default value istrue
. -
pageSize
- the format of PDF list. Default value isA4
.
Additionally, you can override the string for
label.saved.from
message in the main message pack. -
-
-
delay
- delay before triggering print in seconds. -
lossless
- enables or disables image optimization when printing. Default value isfalse
.
-
1.4. Connecting Data
There are three ways how you can pass data to a chart: through the DataProvider
interface, using the datasource mechanism, or the simplified data binding API, which allows adding the data directly using the addData()
method and convenient MapDataItem
constructors for those charts that are not bound to a datasource.
- DataProvider:
-
The
DataProvider
interface has a standard implementation:ListDataProvider
class. It contains a list ofDataItem
instances from which the data for the chart will be taken. There are several standard implementations ofDataItem
interface:-
EntityDataItem
takes an instance of any entity. -
MapDataItem
is a set of key-value pairs. -
SimpleDataItem
takes an instance of anypublic
class.
An instance of
DataProvider
is passed to thesetDataProvider()
method of chart configuration. This approach to providing chart data is the most universal, but it requires creating instances ofDataProvider
andDataItem
in a screen controller. -
- Datasource:
-
A
CollectionDatasource
type datasource can be assigned to aChart
component by invoking thesetDatasource()
method. This approach requires an entity that will represent chart data. It may be convenient when such entity already exists in the application data model and also when chart data should be displayed as a table.Example of Working with Charts illustrates all three approaches to providing chart data.
Entity properties or the values contained in an instance of
DataProvider
which are used for display purposes are defined in the chart attributes. The set of chart attributes may differ for different chart types. For example, for thechart:pieChart
component, you should define thevalueField
andtitleField
attributes. The following types are allowed for attribute values:Integer
,Long
,Double
,String
,Boolean
,Date
.Dynamic addition of data to an existing chart is supported for both the datasource and the data provider mechanisms.
- chart:data element:
-
This option is useful for quick prototyping of charts. The
chart:data
element and its nesteditem
elements enable you to set key-value pairs of data directly in the XML descriptor of the chart, for example:<chart:pieChart id="pieChart" titleField="key" valueField="value"> <chart:data> <chart:item> <chart:property name="key" value="piece of apple pie"/> <chart:property name="value" value="70" type="int"/> </chart:item> <chart:item> <chart:property name="key" value="piece of blueberry pie"/> <chart:property name="value" value="20" type="int"/> </chart:item> <chart:item> <chart:property name="key" value="piece of cherry pie"/> <chart:property name="value" value="10" type="int"/> </chart:item> </chart:data> </chart:pieChart>
1.5. Events
It is possible to configure handling of different event types for each chart type. The following listener types are available for all chart subtypes:
-
LegendItemHideListener
- hiding a legend item. -
LegendItemShowListener
- showing a legend item. -
LegendLabelClickListener
- click on a legend label. -
LegendMarkerClickListener
- click on a legend marker.
More event listeners for the exact chart subtype instance you can find in the corresponding sections of the manual.
Event handling examples are available in Using Events.
In order to migrate the old code that uses event listeners, the Chart
component should be cast to a concrete chart subtype or re-injected with a concrete subtype:
@Inject
private Chart pieChart;
((PieChart)pieChart).addSliceClickListener(event -> {});
Above the listeners, SeriesBasedChart
interface contains zoomOut
, zoomToIndexes
, and zoomToDates
methods for manipulating the chart axis.
The CoordinateChart
interface similarly provides the following methods for the value axis: zoomOutValueAxes
, zoomOutValueAxis
, zoomOutValueAxis
, zoomValueAxisToValues
, and zoomValueAxisToValues
.
1.6. Chart Types
There are several chart types supported by CUBA platform.
The chart interfaces are implemented in the following Chart components:
All these components have NAME
constant, so they can be created using ComponentsFactory
.
1.6.1. AngularGaugeChart
The AngularGaugeChart
component allows you to create gauge charts.
XML name of the component: chart:gaugeChart
.
-
Elements of
chart:gaugeChart
-
-
arrows
- includes the nestedarrow
elements for the chart arrow axes.<chart:arrows> <chart:arrow value="60"/> </chart:arrows>
-
axes
- includes the nestedaxis
elements for the chart axes.<chart:axes> <chart:axis id="blue" axisColor="#67b7dc" axisThickness="3" gridInside="false" inside="false" radius="100%" valueInterval="20" tickColor="#67b7dc"/> <chart:axis labelsEnabled="true" axisColor="#fdd400" axisThickness="3" endValue="160" radius="80%" valueInterval="20" tickColor="#fdd400"/> </chart:axes>
The
band
element enables you to split an axis into several bands, as on the picture above:<chart:axes> <chart:axis axisAlpha="0.2" axisThickness="1" bottomText="60 km/h" bottomTextYOffset="-20" endValue="220" tickAlpha="0.2" valueInterval="20"> <chart:bands> <chart:band color="#84b761" endValue="90" startValue="0"/> <chart:band color="#fdd400" endValue="130" startValue="90"/> <chart:band color="#cc4748" endValue="220" innerRadius="95%" startValue="130"/> </chart:bands> </chart:axis> </chart:axes>
The
endValue
andstartValue
attributes are used to set the range of values on the chart, thevalueInterval
attribute defines the gauge scale marks.
-
-
AngularGaugeChart
event listeners: -
-
ChartClickListener
- click on the canvas. -
ChartRightClickListener
- right click on the canvas.
-
For more details, see AmCharts documentation.
1.6.2. FunnelChart
The FunnelChart
component allows you to create funnel/pyramid charts.
XML name of the component: chart:funnelChart
.
- Data binding:
-
-
You can assign a datasource of a
CollectionDatasource
type to the chart and then define thetitleField
andvalueField
attributes for thefunnelChart
element:<chart:funnelChart id="ratingChart" align="MIDDLE_CENTER" datasource="ratingDs" height="200px" labelPosition="RIGHT" labelText="[[title]]: [[value]]" marginRight="120" maxLabelWidth="110" marginTop="20" titleField="mechanic" valueField="count" width="500px"> </chart:funnelChart>
-
Using the chart:data element.
<chart:funnelChart id="ratingChart" titleField="mechanic" valueField="count"> <chart:data> <chart:item> <chart:property name="mechanic" value="Jack"/> <chart:property name="count" value="1" type="int"/> </chart:item> <chart:item> <chart:property name="mechanic" value="Bob"/> <chart:property name="count" value="2" type="int"/> </chart:item> <chart:item> <chart:property name="mechanic" value="Sam"/> <chart:property name="count" value="3" type="int"/> </chart:item> </chart:data> </chart:funnelChart>
-
-
FunnelChart
event listeners: -
-
SliceClickListener
- click on a slice in a pie chart. -
SlicePullInListener
- shift of a slice of a pie chart into the chart. -
SlicePullOutListener
- shift of a slice of a pie chart out of the chart. -
SliceRightClickListener
- right-click on a slice in a pie chart.
-
For more details, see AmCharts documentation.
1.6.3. GanttChart
The GanttChart
component allows you to create Gantt charts.
XML name of the component: chart:ganttChart
.
-
Elements of
chart:ganttChart
: -
-
categoryAxis
- an element that describes the category axis. -
graph
- an element that contains the collection ofchart:graph
elements; the graph is described by thechart:graph
element.-
the
type
attribute defines the type of the graph and can be: line, column, step line, smoothed line, OHLC and candlestick. -
the
valueField
attribute defines a key from the list of key-value pairs of the datasource or a data provider.
-
-
valueAxis
- value axis of the chart. If the chart data is date- or time-based, you can set the value axis type todate
.
-
-
Attributes of
chart:ganttChart
: -
-
segmentsField
- segments field of the chart. -
additionalSegmentFields
- the list of additional segment fields that correspond to the entity attributes to be fetched from the data provider, similarly to the additionalFields attribute. -
endField
/endDateField
- the end value or the end date of the chart. -
startField
/startDateField
- the start value or the start date of the chart. -
startDate
- the chart start date, if the value axis type isdate
. -
categoryField
- the category field of the chart.
-
- Data binding
-
You can assign a datasource of a
CollectionDatasource
type to the chart. In the example below thestart
andend
attributes of an entity are set for the attributesstartDateField
andendDateField
.<chart:ganttChart id="ganttChart" additionalSegmentFields="task" balloonDateFormat="JJ:NN" brightnessStep="7" categoryField="category" colorField="color" columnWidth="0.5" datasource="taskSpansDs" endDateField="end" height="100%" marginRight="70" period="DAYS" rotate="true" segmentsField="segments" startDate="2016-01-01" startDateField="start" theme="LIGHT" width="100%"> <chart:graph balloonText="<strong>[[task]]</strong>: [[open]] - [[value]]" fillAlphas="1" lineAlpha="1" lineColor="WHITE"/> <chart:valueAxis type="DATE"/> <chart:valueScrollbar autoGridCount="true" color="BLACK"/> <chart:chartCursor cursorAlpha="0" cursorColor="#55bb76" fullWidth="true" valueLineAlpha="0.5" valueBalloonsEnabled="false" valueLineBalloonEnabled="true" valueLineEnabled="true" valueZoomable="true" zoomable="false"/> <chart:export/> </chart:ganttChart>
-
GanttChart
event listeners: -
-
AxisZoomListener
- chart axis scaling. -
CategoryItemClickListener
- click on a category in the category axis. -
ChartClickListener
- click on the canvas. -
ChartRightClickListener
- right click on the canvas. -
CursorPeriodSelectListener
- selection of the display period with a cursor. -
CursorZoomListener
- scaling of the chart area with a cursor. -
GraphClickListener
- click on a graph. -
GraphItemClickListener
- click on a graph item. -
GraphItemRightClickListener
- right click on a graph item. -
ZoomListener
- scaling of the canvas.
-
For more details, see AmCharts documentation.
1.6.4. PieChart
The PieChart
component allows you to create pie/donut charts.
XML name of the component: chart:pieChart
.
- Data binding:
-
-
Using a datasource.
You can assign a datasource of a
CollectionDatasource
type to the chart and then define thetitleField
andvalueField
attributes for thepieChart
element:<chart:pieChart id="pieChart" datasource="countryLitresDs" height="100%" titleField="country" valueField="litres" width="100%"/>
-
Using the chart:data element.
-
-
PieChart
event listeners: -
-
ChartClickListener
- click on the canvas. -
ChartRightClickListener
- right click on the canvas. -
SliceClickListener
- click on a slice in a pie chart. -
SlicePullInListener
- shift of a slice of a pie chart into the chart. -
SlicePullOutListener
- shift of a slice of a pie chart out of the chart. -
SliceRightClickListener
- right-click on a slice in a pie chart.
-
For more details, see AmCharts documentation.
1.6.5. RadarChart
The RadarChart
component allows you to create radar/polar charts.
XML name of the component: chart:radarChart
.
- Data binding:
-
You can assign a datasource of a
CollectionDatasource
type to the chart and then define thecategoryField
attribute for theradarChart
element andvalueField
attribute for the nestedgraph
element:<chart:radarChart id="radarChart" categoryField="country" datasource="countryLitresDs" height="100%" startDuration="2" theme="LIGHT" width="100%"> <chart:graphs> <chart:graph balloonText="[[value]] litres of beer per year" bullet="ROUND" valueField="litres"/> </chart:graphs> </chart:radarChart>
-
RadarChart
event listeners -
-
AxisZoomListener
- chart axis scaling. -
ChartClickListener
- click on the canvas. -
ChartRightClickListener
- right click on the canvas. -
GraphClickListener
- click on a graph. -
GraphItemClickListener
- click on a graph item. -
GraphItemRightClickListener
- right click on a graph item.
-
For more details, see AmCharts documentation.
1.6.6. SerialChart
The SerialChart
component allows you to create line, area, column, bar, step line, smoothed line, candlestick and OHLC charts. The charts support multiple axes with simple or logarithmic scales, the data points can be displayed at equal/irregular intervals or on timeline basis.
XML name of the component: chart:serialChart
.
- Data binding:
-
You can assign a datasource of a
CollectionDatasource
type to the chart and then define thecategoryField
attribute for theserialChart
element andvalueField
attribute for the nestedgraph
element:<chart:serialChart categoryField="date" datasource="dateValueDs"> <chart:graphs> <chart:graph valueField="value" balloonText="[[value]]"> </chart:graph> </chart:graphs> <chart:categoryAxis dashLength="1" minorGridEnabled="true"/> </chart:serialChart>
-
SerialChart
event listeners -
-
AxisZoomListener
- chart axis scaling. -
CategoryItemClickListener
- click on a category in the category axis. -
ChartClickListener
- click on the canvas. -
ChartRightClickListener
- right click on the canvas. -
CursorPeriodSelectListener
- selection of the display period with a cursor. -
CursorZoomListener
- scaling of the chart area with a cursor. -
GraphClickListener
- click on a graph. -
GraphItemClickListener
- click on a graph item. -
GraphItemRightClickListener
- right click on a graph item. -
ZoomListener
- scaling of the canvas.
-
For more details, see AmCharts documentation.
1.6.7. StockChartGroup
The StockChartGroup
component allows you to create stock charts.
Stock chart supports multiple data sets and has a ready to use data set selector. Data sets might be compared one to another.
Stock chart can display a different kind of annotations on the graph or on the axis. These annotations are called stock events.
Stock chart can support any number of stock panels. Each Stock Panel can have any number of graphs. Each Stock Panel is a separate serial chart and is based on SerialChart and so it can do anything this chart can.
-
StockChartGroup
event listeners -
-
DataSetSelectorCompareListener
- listener to dataset selector compare events. -
DataSetSelectorSelectListener
- selection of the dataset selector. -
DataSetSelectorUnCompareListener
- listener to the dataset selector uncompare events. -
PeriodSelectorChangeListener
- selection of the display period with a selector. -
StockChartClickListener
- click on the stock chart area. -
StockChartRightClickListener
- right click on the stock chart area. -
StockEventClickListener
- click on the stock event. -
StockEventRollOutListener
- stock event roll-out. -
StockEventRollOverListener
- stock event roll-over. -
StockGraphClickListener
- click on the stock graph. -
StockGraphItemClickListener
- click on the stock graph item. -
StockGraphItemRightClickListener
- right click on the stock graph item. -
StockGraphItemRollOutListener
- stock graph item roll-out events. -
StockGraphItemRollOverListener
- stock graph item roll-over events. -
StockGraphRollOutListener
- stock graph roll-out events. -
StockGraphRollOverListener
- stock graph roll-over events. -
ZoomListener
- scaling of the canvas. -
ZoomListener
- scaling of the canvas.
-
1.6.8. XYChart
The XYChart
component allows you to create XY/bubble/scatter charts. The charts support multiple axes with simple or logarithmic scales.
XML name of the component: chart:xyChart
.
- Data binding:
-
You can assign a datasource of a
CollectionDatasource
type to the chart and then define thexField
andyFields
attributes for the nestedgraph
elements:<chart:xyChart datasource="pointPairDs" startDuration="1"> <chart:graphs> <chart:graph balloonText="x:[[x]] y:[[y]]" xField="ax" fillToAxis="x" yField="ay"/> <chart:graph balloonText="x:[[x]] y:[[y]]" fillToAxis="y" xField="bx" yField="by"/> </chart:graphs> <chart:valueAxes> <chart:axis id="x" axisAlpha="0" dashLength="1" position="BOTTOM" title="X Axis"/> <chart:axis id="y" axisAlpha="0" dashLength="1" position="LEFT" title="Y Axis"/> </chart:valueAxes> </chart:xyChart>
-
XYChart
event listeners -
-
AxisZoomListener
- chart axis scaling. -
ChartClickListener
- click on the canvas. -
CursorPeriodSelectListener
- selection of the display period with a cursor. -
CursorZoomListener
- scaling of the chart area with a cursor. -
GraphClickListener
- click on a graph. -
GraphItemClickListener
- click on a graph item. -
GraphItemRightClickListener
- right click on a graph item.
-
For more details, see AmCharts documentation.
1.7. Example of Working with Charts
This chapter shows how you can use the chart display subsystem.
1.7.1. Setting up the Application Project
-
Run CUBA Studio, create new project and name it
sampler
. -
Open Project properties → Edit and select the charts component in the list of App components; save changes. Confirm when Studio will suggest recreating Gradle scripts.
-
Select Run → Deploy. At this point, the application will be assembled and deployed to the Tomcat application server located at
build/tomcat
. -
Select Build → Create or update IDEA project files to create project files for IntelliJ IDEA.
Once the steps above are complete, the chart display functionality will be connected to the application and ready to be used.
1.7.2. Creating Chart with Simplified Data Binding
For the first example we will create the most simple chart using the simplified data binding API.
Add the chart component to the screen and use the addData()
method to fill it with data, passing the MapDataItem
instance with a set of key-value pairs as a parameter:
<chart:pieChart id="pieChart"
titleField="key"
valueField="value"/>
pieChart.addData(MapDataItem.of("key", "piece of apple pie",
"value", 70),
MapDataItem.of("key", "piece of blueberry pie",
"value", 20),
MapDataItem.of("key", "piece of cherry pie",
"value", 10));
1.7.3. Creating Chart with Data from an Entity
In this chapter we will create the chart similar to 3D Stacked Column Chart from AmCharts demos. This chart will retrieve data from a database, so the datasource
attribute has to be defined. The JavaScript
source code which amCharts use to define such chart is as follows:
var chart = AmCharts.makeChart("chartdiv", {
"theme": "light",
"type": "serial",
"dataProvider": [{
"country": "USA",
"year2004": 3.5,
"year2005": 4.2
}, {
"country": "UK",
"year2004": 1.7,
"year2005": 3.1
}, {
"country": "Canada",
"year2004": 2.8,
"year2005": 2.9
}, {
"country": "Japan",
"year2004": 2.6,
"year2005": 2.3
}, {
"country": "France",
"year2004": 1.4,
"year2005": 2.1
}, {
"country": "Brazil",
"year2004": 2.6,
"year2005": 4.9
}, {
"country": "Russia",
"year2004": 6.4,
"year2005": 7.2
}, {
"country": "India",
"year2004": 8,
"year2005": 7.1
}, {
"country": "China",
"year2004": 9.9,
"year2005": 10.1
}],
"valueAxes": [{
"stackType": "3d",
"unit": "%",
"position": "left",
"title": "GDP growth rate",
}],
"startDuration": 1,
"graphs": [{
"balloonText": "GDP grow in [[category]] (2004): <b>[[value]]</b>",
"fillAlphas": 0.9,
"lineAlpha": 0.2,
"title": "2004",
"type": "column",
"valueField": "year2004"
}, {
"balloonText": "GDP grow in [[category]] (2005): <b>[[value]]</b>",
"fillAlphas": 0.9,
"lineAlpha": 0.2,
"title": "2005",
"type": "column",
"valueField": "year2005"
}],
"plotAreaFillAlphas": 0.1,
"depth3D": 60,
"angle": 30,
"categoryField": "country",
"categoryAxis": {
"gridPosition": "start"
},
"export": {
"enabled": true
}
});
1.7.3.1. Creating an Entity
-
Open the DATA MODEL tab in CUBA Studio and click New → Entity button.
-
In the New entity dialog type
CountryGrowth
in the Class name field, chooseNot persistent
for Entity type and click OK button. -
Using Entity Designer add attributes:
-
country
of the typeString
-
year2014
of the typeDouble
-
year2015
of the typeDouble
-
-
Open the Source tab to see generated source code:
package com.company.sampler.entity; import com.haulmont.chile.core.annotations.MetaClass; import com.haulmont.chile.core.annotations.MetaProperty; import com.haulmont.cuba.core.entity.AbstractNotPersistentEntity; @MetaClass(name = "sampler$CountryGrowth") public class CountryGrowth extends AbstractNotPersistentEntity { @MetaProperty protected String country; @MetaProperty protected Double year2014; @MetaProperty protected Double year2015; public void setCountry(String country) { this.country = country; } public String getCountry() { return country; } public void setYear2014(Double year2014) { this.year2014 = year2014; } public Double getYear2014() { return year2014; } public void setYear2015(Double year2015) { this.year2015 = year2015; } public Double getYear2015() { return year2015; } }
This class describes non-persistent entity. An instance of this class contains the number of the country GDP growth rate for 2014 and 2015 years.
-
Click OK button to save the entity and close the designer screen.
1.7.3.2. Creating Chart
1.7.3.2.1. Screen XML Descriptor
Open the GENERIC UI tab in CUBA Studio and create a screen in the web module. Enter the value column3d-chart
in the Descriptor field. The fields - Id, Controller Name and Messages Pack will be filled in with appropriate values. Save changes. Open the XML tab and replace its content with the following code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
caption="msg://caption"
class="com.company.sampler.web.screens.Column3dChart"
messagesPack="com.company.sampler.web.screens"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
<dsContext>
<collectionDatasource id="countryGrowthDs"
class="com.company.sampler.entity.CountryGrowth"
refreshMode="NEVER"/>
</dsContext>
<layout>
<chart:serialChart id="chart"
angle="30"
categoryField="country"
datasource="countryGrowthDs"
depth3D="60"
height="100%"
plotAreaFillAlphas="0.1"
startDuration="1"
width="100%">
<chart:categoryAxis gridPosition="START"/>
<chart:valueAxes>
<chart:axis position="LEFT"
stackType="BOX_3D"
title="GDP growth rate"
unit="%"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph id="graph2014"
balloonText="GDP grow in [[category]] (2014): <b>[[value]]</b>"
fillAlphas="0.9"
lineAlpha="0.2"
title="2014"
type="COLUMN"
valueField="year2014"/>
<chart:graph id="graph2015"
balloonText="GDP grow in [[category]] (2015): <b>[[value]]</b>"
fillAlphas="09."
lineAlpha="0.2"
title="2015"
type="COLUMN"
valueField="year2015"/>
</chart:graphs>
<chart:export/>
</chart:serialChart>
</layout>
</window>
The root element of the screen descriptor contains a new xmlns:chart
attribute:
<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...
>
The chart retrieves data from the countryGrowthDs
datasource defined in the datasource
attribute. Names and values are displayed using the country
, year2014
and year2015
attributes of the CountryGrowth
entity; the list of instances for this entity is stored in the datasource.
The chart:serialChart
component contains the following attributes:
-
angle
- defines the chart angle. May have a value from0
to90
. -
balloonText
- defines text for the tooltip that appears when hovering over a column. You can use the following tags:[[value]]
,[[title]]
,[[persents]]
,[[description]]
, as well as keys from theDataItem
listed in aDataProvider
instance, or names of the entity attributes from the datasource. To usehtml
tags you must escape them. -
depth3D
- chart thickness. When used in combination with theangle
attribute, helps to create a 3D effect. -
plotAreaFillAlphas
- opacity of the plot area. -
startDuration
- duration of the animation, in seconds. -
categoryField
- a key from the set of pairs contained in theDataItem
objects listed in aDataProvider
instance; this key is used to determine the labels for the category axis.
The chart:serialChart
component contains the following elements:
-
chart:categoryAxis
- an element that describes the category axis.-
The
gridPosition
attribute specifies if a grid line is placed on the center of a cell or on the beginning of a cell.
-
-
chart:valueAxes
- an element that defines vertical value axes. In our case, only one vertical axis is used; the axis is described by thechart:axis
element.-
The
position
attribute defines position of the value axis relative to the chart. -
Setting
stackType
toBOX_3D
makes the chart display columns one behind the other.
-
-
chart:graphs
- an element that contains the collection ofchart:graph
elements; the graph is described by thechart:graph
element.-
The
type
attribute defines the type of the graph and can be: line, column, step line, smoothed line, ohlc and candlestick. -
The
valueField
attribute defines a key from the list of pairs contained in theDataItem
objects listed in aDataProvider
instance; this key is used to determine the value. -
The
fillAlphas
attribute defines opacity of fill. -
The
lineAlpha
attribute defines opacity of the line (or column border). Value range is 0 - 1.
-
-
chart:export
– an optional element that enables chart export.
1.7.3.2.2. Screen Controller
Open the Controller tab and replace its content with the following code:
package com.company.sampler.web.screens;
import com.company.sampler.entity.CountryGrowth;
import com.haulmont.cuba.gui.components.AbstractWindow;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import javax.inject.Inject;
import java.util.Map;
import java.util.UUID;
public class Column3dChart extends AbstractWindow {
@Inject
private CollectionDatasource<CountryGrowth, UUID> countryGrowthDs;
@Override
public void init(Map<String, Object> params) {
countryGrowthDs.refresh();
countryGrowthDs.includeItem(countryGrowth("USA", 3.5, 4.2));
countryGrowthDs.includeItem(countryGrowth("UK", 1.7, 3.1));
countryGrowthDs.includeItem(countryGrowth("Canada", 2.8, 2.9));
countryGrowthDs.includeItem(countryGrowth("Japan", 2.6, 2.3));
countryGrowthDs.includeItem(countryGrowth("France", 1.4, 2.1));
countryGrowthDs.includeItem(countryGrowth("Brazil", 2.6, 4.9));
countryGrowthDs.includeItem(countryGrowth("Russia", 6.4, 7.2));
countryGrowthDs.includeItem(countryGrowth("India", 8.0, 7.1));
countryGrowthDs.includeItem(countryGrowth("China", 9.9, 10.1));
}
private CountryGrowth countryGrowth(String country, double year2014, double year2015) {
CountryGrowth cg = new CountryGrowth();
cg.setCountry(country);
cg.setYear2014(year2014);
cg.setYear2015(year2015);
return cg;
}
}
The init(Map<String, Object> params)
method populates the countryGrowthDs
datasource with the data. The refresh()
method initializes the datasource. This method should be invoked regardless of the refreshMode="NEVER"
attribute declared in the XML-descriptor.
1.7.3.3. Result
-
Open the Open web menu link at the bottom of the GENERIC UI section in CUBA Studio.
-
Make sure the
application
menu contains newcolumn3d-chart
item. New screen are added to the menu automatically if created in Studio. -
Select Run → Start application server.
After logging in and opening the screen from the application menu you will see the chart like below:
1.7.4. Creating Chart with Data from DataProvider
This chart retrieves data through the DataProvider
created in the controller, so the datasource
attribute is not defined.
1.7.4.1. Creating Chart
1.7.4.1.1. Screen XML Descriptor
Open the Screens tab in CUBA Studio and create a screen in the web module. Enter the value com/company/sampler/web/screens/stackedarea-chart.xml
in the Descriptor field. The fields - Id, Controller Name and Messages Pack will be filled in with appropriate values. Save changes. Open the XML tab and replace its content with the following code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
caption="msg://caption"
class="com.company.sampler.web.screens.StackedAreaChart"
messagesPack="com.company.sampler.web.screens"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
<layout>
<chart:serialChart id="chart"
categoryField="year"
height="100%"
marginLeft="0"
marginTop="10"
plotAreaBorderAlpha="0"
width="100%">
<chart:chartCursor cursorAlpha="0"/>
<chart:legend equalWidths="false"
periodValueText="total: [[value.sum]]"
position="TOP"
valueAlign="LEFT"
valueWidth="100"/>
<chart:valueAxes>
<chart:axis gridAlpha="0.07"
position="LEFT"
stackType="REGULAR"
title="Traffic incidents"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph fillAlphas="0.6"
hidden="true"
lineAlpha="0.4"
title="Cars"
valueField="cars"/>
<chart:graph fillAlphas="0.6"
lineAlpha="0.4"
title="Motorcycles"
valueField="motorcycles"/>
<chart:graph fillAlphas="0.6"
lineAlpha="0.4"
title="Bicycles"
valueField="bicycles"/>
</chart:graphs>
<chart:categoryAxis axisColor="#DADADA"
gridAlpha="0.07"
startOnAxis="true"/>
<chart:export/>
</chart:serialChart>
</layout>
</window>
The root element of the screen descriptor contains a new xmlns:chart
attribute:
<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...
>
chart:serialChart
attributes:
-
categoryField
- a key from the set of pairs contained in theDataItem
objects listed in aDataProvider
instance; this key is used to determine the labels for the category axis.
The elements of chart:serialChart
:
-
chart:chartCursor
- an optional element adding a cursor to the chart; the cursor follows the mouse pointer and shows a tooltip with the value of the corresponding point on a chart.-
The
cursorAlpha
attribute defines opacity of the cursor line.
-
-
chart:legend
- an element that defines the chart legend.-
The
position
attribute defines the location of the legend relative to the chart. -
The
equalWidths
attribute specifies if each of legend entry should be equal to the most wide entry. -
The
periodValueText
attribute defines the text which will be displayed in the value portion of the legend when user is not hovering above any data point. The tags should be made out of two parts - the name of a field (value / open / close / high / low) and the value of the period you want to be show - open / close / high / low / sum / average / count. -
The
valueAlign
attribute defines alignment of the value text. Possible values are "left" and "right". -
The
valueWidth
attribute defines width of the value text.
-
-
chart:valueAxes
- an element that defines vertical value axes. In our case, only one vertical axis is used; the axis is described by thechart:axis
element.-
The
position
attribute defines position of the value axis relative to the chart. -
The
title
attribute defines the title of the value axis. -
Setting
stackType
toREGULAR
makes the chart display a rolling value. Setting this attribute tonone
refers to a non-rolling value. -
The
gridAlpha
defines opacity of grid lines.
-
-
chart:graphs
- an element that contains the collection ofchart:graph
elements; the graph is described by thechart:graph
element.-
The
type
attribute defines the type of the graph and can be: line, column, step line, smoothed line, ohlc and candlestick. -
The
valueField
attribute defines a key from the list of pairs contained in theDataItem
objects listed in aDataProvider
instance; this key is used to determine the value. -
The
fillAlphas
attribute defines opacity of fill. -
The
lineAlpha
attribute defines opacity the line (or column border). Value range is 0 - 1. -
The
hidden
attribute specifies whether the graph is hidden.
-
-
chart:categoryAxis
- an element that describes the category axis.-
Setting
startOnAxis
totrue
causes drawing the chart right from the value axis. The default value for this attribute isfalse
. In this case, there will be a small gap between the value axis and the chart. -
The
gridAlpha
attribute defines opacity of grid lines. -
The
axisColor
attribute defines axis color.
-
-
chart:export
– an optional element that enables chart export.
1.7.4.1.2. Screen Controller
Open the Controller tab and replace its content with the following code:
package com.company.sampler.web.screens;
import com.haulmont.charts.gui.amcharts.model.charts.SerialChart;
import com.haulmont.charts.gui.amcharts.model.data.DataItem;
import com.haulmont.charts.gui.amcharts.model.data.ListDataProvider;
import com.haulmont.charts.gui.amcharts.model.data.MapDataItem;
import com.haulmont.charts.gui.components.charts.Chart;
import com.haulmont.cuba.gui.components.AbstractWindow;
import javax.inject.Inject;
import java.util.Map;
public class StackedAreaChart extends AbstractWindow {
@Inject
private Chart chart;
@Override
public void init(Map<String, Object> params) {
ListDataProvider dataProvider = new ListDataProvider();
dataProvider.addItem(transportCount(1994, 1587, 650, 121));
dataProvider.addItem(transportCount(1995, 1567, 683, 146));
dataProvider.addItem(transportCount(1996, 1617, 691, 138));
dataProvider.addItem(transportCount(1997, 1630, 642, 127));
dataProvider.addItem(transportCount(1998, 1660, 699, 105));
dataProvider.addItem(transportCount(1999, 1683, 721, 109));
dataProvider.addItem(transportCount(2000, 1691, 737, 112));
dataProvider.addItem(transportCount(2001, 1298, 680, 101));
dataProvider.addItem(transportCount(2002, 1275, 664, 97));
dataProvider.addItem(transportCount(2003, 1246, 648, 93));
dataProvider.addItem(transportCount(2004, 1318, 697, 111));
dataProvider.addItem(transportCount(2005, 1213, 633, 87));
dataProvider.addItem(transportCount(2006, 1199, 621, 79));
dataProvider.addItem(transportCount(2007, 1110, 210, 81));
dataProvider.addItem(transportCount(2008, 1165, 232, 75));
dataProvider.addItem(transportCount(2009, 1145, 219, 88));
dataProvider.addItem(transportCount(2010, 1163, 201, 82));
dataProvider.addItem(transportCount(2011, 1180, 285, 87));
dataProvider.addItem(transportCount(2012, 1159, 277, 71));
serialChart.setDataProvider(dataProvider);
}
private DataItem transportCount(int year, int cars, int motorcycles, int bicycles) {
MapDataItem item = new MapDataItem();
item.add("year", year);
item.add("cars", cars);
item.add("motorcycles", motorcycles);
item.add("bicycles", bicycles);
return item;
}
}
The init(Map<String, Object> params)
method submits data to the chart as a rolling value. This type of charts shows the ratio of separate parts to their total value.
1.7.4.2. Result
-
Open the Main Menu tab in CUBA Studio and click edit button for
web-menu.xml
. -
Choose
application
item and click new button. -
In Create menu item dialog choose
stackedarea-chart
for id field and click add. -
Select Run → Start application server.
After logging in and opening the screen from the application menu you will see the chart like below:
1.7.5. Creating Chart with Incremental Data Update
This chart will retrieve data from a datasource, and this data will be updated automatically. When new data is added to the datasource, the chart is not refreshed completely: data points are added on the fly each 2 seconds. This approach will be useful, for example, for creating dynamically updated dashboards.
In this example we will show the dynamic of new orders amounts based on the Order
entity from the Sales sample application.
-
Download the Sales application and add the charts component to it as described in Setting up the Application Project section.
-
Create a new screen in Studio. Call it orders-history, as it will display the history dashboard for new order entries.
-
Add the
serialChart
component to the screen layout. To use the incremental data update feature, we have to create thecollectionDatasource
and bind the chart to it. We will not load the data from the database in this example, instead, the sample data will be generated on the fly, so you don’t need to create a query.Set the
date
property for the category axis and theamount
property for the value axis.<?xml version="1.0" encoding="UTF-8" standalone="no"?> <window xmlns="http://schemas.haulmont.com/cuba/window.xsd" caption="msg://caption" class="com.company.sales.web.screens.OrdersHistory" messagesPack="com.company.sales.web.screens" xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"> <dsContext> <collectionDatasource id="ordersDs" class="com.company.sales.entity.Order" allowCommit="false" refreshMode="NEVER"/> </dsContext> <dialogMode height="600" width="800"/> <layout expand="orderHistoryChart" spacing="true"> <chart:serialChart id="orderHistoryChart" categoryField="date" datasource="ordersDs" width="100%"> <chart:graphs> <chart:graph valueField="amount"/> </chart:graphs> </chart:serialChart> </layout> </window>
-
We will update the chart on the fly using
timer
- a special UI component that will send HTTP-requests to the server side.Open the Properties tab of the screen designer and add the timer by clicking on the Timers button. Set the timer id. Let’s say the data should be updated each 2 seconds, so set the delay to 2000 milliseconds.
In the onTimer field we define the name of Java method -
updateChart
. This method will be invoked each time the timer fires an event. Generate this method in the controller by clicking the >> button and click Apply to save it.Figure 15. Creating a timer -
Switch to the IDE. Before starting to work on the timer logic, inject necessary dependencies:
timeSource
,metadata
, and the datasource instance. We will generate a newOrder
instance with random amount value each time the timer event is fired. The new instance is added to the datasource using theincludeItem()
method.Initialize the chart in the
init()
method using the same logic for creating a randomOrder
instance.public class OrdersHistory extends AbstractWindow { @Inject private Metadata metadata; @Inject private TimeSource timeSource; @Inject private CollectionDatasource<Order, UUID> ordersDs; private Random random = new Random(42); @Override public void init(Map<String, Object> params) { super.init(params); Order initialValue = metadata.create(Order.class); initialValue.setAmount(new BigDecimal(random.nextInt(1000) + 100)); initialValue.setDate(timeSource.currentTimestamp()); ordersDs.includeItem(initialValue); } public void updateChart(Timer source) { Order orderHistory = metadata.create(Order.class); orderHistory.setAmount(new BigDecimal(random.nextInt(1000) + 100)); orderHistory.setDate(timeSource.currentTimestamp());; ordersDs.includeItem(orderHistory); } }
At this stage the chart is already functional, but the datasource size will increase rapidly, so we need to limit the number of items to be displayed.
Figure 16. The data is automatically updated each 2 seconds -
Create a
Queue
of orders. Each time the timer event is fired, the generated item is added to the top of theitemsQueue
. When the queue size exceeds 10 items, the oldest item is excluded.private Queue<Order> itemsQueue = new LinkedList<>();
public void updateChart(Timer source) { Order orderHistory = metadata.create(Order.class); orderHistory.setAmount(new BigDecimal(random.nextInt(1000) + 100)); orderHistory.setDate(timeSource.currentTimestamp());; ordersDs.includeItem(orderHistory); itemsQueue.add(orderHistory); if (itemsQueue.size() > 10) { Order item = itemsQueue.poll(); ordersDs.excludeItem(item); } }
- Result
-
All the data is sent to the browser incrementally. If you open Chrome developer console on the Network tab, you will see that each 2 seconds our web page sends an HTTP request to the backend, and in response to that the backend sends very small JSON message. The JSON contains one
add
and oneremove
operation for the amount value. Thus, we do not re-send all the data.
1.7.6. Using Events
Let us consider the use of events. We will add handling of a graph item click to the screen created in Creating Chart. Open the screen controller in the IDE and inject the chart:
@Inject
private SerialChart serialChart;
Then add a listener at the bottom of the init(Map<String, Object> params)
method. When a chart receives data from DataProvider
, the getDataItemNN()
method should be used to get the item clicked. In this example, the SerialChart
component is bound to the datasource, so another method should be used: getEntityNN()
:
serialChart.addGraphItemClickListener(event -> {
CountryGrowth countryGrowth = (CountryGrowth) event.getEntityNN();
String message = String.format("GDP grow in %s (%s): %.1f%%",
countryGrowth.getCountry(),
event.getGraphId().substring(5),
"graph2014".equals(event.getGraphId()) ? countryGrowth.getYear2014() : countryGrowth.getYear2015());
showNotification(message, NotificationType.HUMANIZED_HTML);
});
To see the results, rebuild the project using Run → Restart application server and log in to the system. Open the screen and click one of the columns.
1.7.7. Configuration using JSON
In order to configure a chart, in addition to assigning XML attributes, you can use a custom JSON described in the AmCharts documentation.
For example, we have a serial chart:
<chart:serialChart id="serialChart">
<chart:valueAxes>
<chart:axis axisAlpha="0" position="LEFT" title="Incidents"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph id="g1" bullet="ROUND" type="COLUMN" valueField="value"/>
</chart:graphs>
<chart:categoryAxis position="TOP" title="Time" labelsEnabled="false"/>
</chart:serialChart>
This chart have some data:
@Inject
protected Chart serialChart;
@Override
public void init(Map<String, Object> params) {
super.init(params);
ListDataProvider serialChartDataProvider = new ListDataProvider();
int[] serialChartChartData = {5, 7, 6, 9, 7, 8, 5, 6, 4, 6, 5, 7, 4, 5, 3, 4, 2, 0};
for (int i = 0; i < redLineChartData.length; i++) {
serialChartDataProvider.addItem(graphData(serialChartChartData[i]));
}
serialChartConfiguration.setDataProvider(serialChartDataProvider);
}
And now we can change the chart’s configuration. As an example, let’s add a title:
serialChart.setNativeJson("{\n" +
" \"titles\": [\n" +
" {\n" +
" \"size\": 15,\n" +
" \"text\": \"Chart Title\"\n" +
" }\n" +
" ]\n" +
"}");
You can also set JSON configuration in the XML:
<chart:serialChart id="serialChart">
<chart:nativeJson>
<![CDATA[
{
"titles": [
{
"size": 15,
"text": "Chart Title"
}
]
}
]]>
</chart:nativeJson>
<chart:valueAxes>
<chart:axis axisAlpha="0" position="LEFT" title="Incidents"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph id="g1" bullet="ROUND" type="COLUMN" valueField="value"/>
</chart:graphs>
<chart:categoryAxis position="TOP" title="Time" labelsEnabled="false"/>
</chart:serialChart>
1.8. Replacing AmCharts Version
An instance of AmCharts library included in CUBA platform can be replaced with another one. To do this:
-
Download charts and stock charts from AmCharts site.
-
Merge
amcharts
folder from both archives into one. -
Copy
amcharts
folder to{project.rootDir}/modules/web/web/VAADIN/webjars
-
Redeploy the application.
To use new attributes added in a new version you need to set custom JSON in your screen controller as shown below.
chart.setNativeJson("{\"valueScrollbar\":{\"autoGridCount\":true}}");
2. Displaying Maps
CUBA platform map display subsystem is based on integration with a third-party map service provider. Currently, only Google Maps service is supported.
2.1. Map Display Capabilities
-
Response to events:
-
Mouse click.
-
Map pan and zoom.
-
Marker click and drag.
-
Close pop-up window.
-
-
Adding markers. Marker may be either fixed or draggable by user. Markers can process mouse clicks and send corresponding events to the screen code.
-
Displaying polylines and polygons.
-
Drawing polygons.
-
Heat map rendering.
2.2. Setting up Application Project
In order to display maps in your application, you should add the charts application component, as it was described for the chart display subsystem. Additionally, you should define the following application properties for the Web Client block:
-
One of the following parameters (see detailed information on these parameters in the Google Maps API documentation):
-
charts.map.apiKey
- a browser key. -
charts.map.clientId
- a client ID.
-
-
Optional parameters:
-
charts.map.defaultZoom
- default zoom level for the map. -
charts.map.defaultLatitude
- default latitude of the map center point. -
charts.map.defaultLongitude
- default longitude of the map center point.
-
Example of a web-app.properties
file:
charts.map.apiKey = my_key
charts.map.defaultZoom = 13.0
charts.map.defaultLatitude = 51.5001
charts.map.defaultLongitude = -0.1262
2.3. MapViewer Component
You can display maps in your application screens using the com.haulmont.charts.gui.components.map.MapViewer
component.
To add the component, declare the chart
namespace in the root element of the screen XML descriptor:
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...>
XML-name of the component: mapViewer
. Component declaration example:
<layout>
<vbox id="mapBox" height="100%">
<chart:mapViewer id="map" width="100%" height="100%"/>
</vbox>
</layout>
You can define the following component parameters in the screen XML-descriptor:
-
id
,width
,height
- standard component properties. -
mapType
- map type corresponding to theMapViewer.Type
options:roadmap
,satellite
,hybrid
,terrain
. Default isroadmap
. -
vendor
- map service provider. Currently the only supported value isgoogle
.
Main configuration of the map and its components is performed in a screen controller. For this, you only need to inject the component declared in the XML-descriptor:
@Inject
private MapViewer map;
@Override
public void init(Map<String, Object> params) {
GeoPoint center = map.createGeoPoint(53.490905, -2.249558);
map.setCenter(center);
}
- Map configuration methods
-
-
fitToBounds()
- sets the minimum map zoom as the one which will be sufficient to show in full an area limited by north-eastern and south-western coordinates. -
removePolygonVertex()
- removes vertex from polygon. -
setCenter()
- sets the map center point. -
setCenterBoundLimits()
- sets map center possible locations bounds. -
setCenterBoundLimitsEnabled()
- sets whether map center possible locations should be limited. -
setDraggable()
- enables/disables map dragging mode. -
setKeyboardShortcutsEnabled()
- enables/disables keyboard shortcuts. -
setMapType()
- defines map type. -
setMaxZoom()
- sets the maximum available zoom level. -
setMinZoom()
- sets the minimum available zoom level. -
setRemoveMessage()
- sets the popup message for vertex removal. -
setScrollWheelEnabled()
- enables/disables map zoom with a mouse scroll wheel. -
setVertexRemovingEnabled()
- toggles vertex removing availability. -
setVisibleAreaBoundLimits()
- sets boundaries of the visible area of the map. -
setVisibleAreaBoundLimitsEnabled()
- enables visible area limitation mode. -
setZoom()
- sets the map zoom level.
-
- Map component interfaces
-
The interfaces listed below can be found in
com.haulmont.charts.gui.map.model
package.-
Circle
- a component that displays a circle. ACircle
properties are similar to aPolygon
, except that its shape is defined by two additional properties: center (GeoPoint
) and radius. You can use thecreateCircle()
andaddCircle()
methods of theMapViewer
interface to create this object and put it on a map.Circle circle = map.createCircle(center, 130.5); circle.setDraggable(true);; circle.setFillOpacity(0.5); map.addCircleOverlay(circle);
-
DrawingOptions
- auxiliary drawing component. Only polygon drawing is currently supported. Drawing mode can be enabled by passing an instance ofDrawingOptions
to theMapViewer
. Example:DrawingOptions options = new DrawingOptions(); PolygonOptions polygonOptions = new PolygonOptions(true, true, "#993366", 0.6); ControlOptions controlOptions = new ControlOptions( Position.TOP_CENTER, Arrays.asList(OverlayType.POLYGON)); options.setEnableDrawingControl(true); options.setPolygonOptions(polygonOptions); options.setDrawingControlOptions(controlOptions); options.setInitialDrawingMode(OverlayType.POLYGON); map.setDrawingOptions(options);
-
GeoPoint
- an auxiliary component, which is not displayed on the map. This component can be used to set such map parameters as the center point, boundaries, or to create more complex map components. The object can be created using thecreateGeoPoint()`method of the `MapViewer
interface. For example:GeoPoint center = map.createGeoPoint(53.490905, -2.249558); map.setCenter(center);
-
HeatMapLayer
- a map layer showing a heat map intended to display data density distribution across different geopoints. Data density is highlighted with color. By default, regions with higher points density are displayed in red and regions with lower density – in green. You can use thecreateHeatMapLayer()
andaddHeatMapLayer()
methods of theMapViewer
interface to create this object and put it on a map. For example:HeatMapLayer heatMapLayer = map.createHeatMapLayer(); List<GeoPoint> data = new ArrayList<>(); data.add(map.createGeoPoint(53.450, -2.090)); data.add(map.createGeoPoint(53.451, -2.095)); data.add(map.createGeoPoint(53.452, -2.092)); data.add(map.createGeoPoint(53.453, -2.093)); data.add(map.createGeoPoint(53.454, -2.093)); data.add(map.createGeoPoint(53.454, -2.092)); data.add(map.createGeoPoint(53.453, -2.092)); heatMapLayer.setData(data); map.addHeatMapLayer(heatMapLayer);
The data used for the heat map layer can be changed using a separate
setData()
method. This change does not require re-adding the layer to the map.
-
InfoWindow
- a map component that displays information in a pop-up window. You can use thecreateInfoWindow()
andopenInfoWindow()
methods of theMapViewer
interface to create this object and put it on a map. For example:InfoWindow w = map.createInfoWindow("Some text"); map.openInfoWindow(w);
Information window can be tied to a marker, for example:
map.addMarkerClickListener(event -> { Marker marker = event.getMarker(); String caption = String.format("Marker clicked: %.2f, %.2f", marker.getPosition().getLatitude(), marker.getPosition().getLongitude()); InfoWindow w = map.createInfoWindow(caption, marker); map.openInfoWindow(w); });
-
Label
- a component to display a text label on the map.Label
can be created and put on a map with thecreateLabel()
andaddLabel()
methods of theMapViewer
interface. It can be removed, in turn, with theremoveLabel()
method. For styling, it supports HTML markdown.The
Label
component has the following attributes:-
value
- string value of the label. If the content type is set toHTML
, the label value will be parsed by the browser. -
position
- an implementation ofGeoPoint
that represents the geographical position of the label. -
contentType
- sets whether label value will be parsed as HTML or not. Can take 2 possible vales:PLAIN_TEXT
andHTML
. -
adjustment
- sets the label adjustment relative to the itsGeoPoint
position marker. -
styleName
- sets additional stylename to the label.Label label = map.createLabel(); label.setValue("<span style=\"color: #ffffff; font-size: 24px;\">White label</span>"); label.setPosition(map.createGeoPoint(42.955, 32.883)); label.setAdjustment(Label.Adjustment.BOTTOM_CENTER); label.setContentType(Label.ContentType.HTML); map.addLabel(label);
-
-
Marker
- a component that marks a location on the map. By default, a standard icon of the map service vendor is used. You can use thecreateMarker()
andaddMarker()
methods of theMapViewer
interface to create this object and put it on a map. For example:Marker marker = map.createMarker("My place", map.createGeoPoint(53.590905, -2.249558), true); marker.setClickable(true); map.addMarker(marker);
The
clearMarkers()
method, in turn, removes all the markers from map.The
MarkerImage
interface is used to set a Marker icon or shadow image.MarkerImage markerImage = map.createMarkerImage("https://www.cuba-platform.com/sites/logo.png"); GeoPoint center = map.createGeoPoint(21.11, -76.20); markerImage.setSize(map.createSize(44, 44)); markerImage.setOrigin(map.createPoint(0, 0)); markerImage.setAnchor(map.createPoint(-5, 50)); Marker marker = map.createMarker("Cuba", center, true, markerImage); map.addMarker(marker);
-
Polyline
- a component that displays a polyline. You can use thecreatePolyline()
andaddPolyline()
methods of theMapViewer
interface to create this object and put it on a map. For example:List<GeoPoint> coordinates = new ArrayList<>(); coordinates.add(map.createGeoPoint(53.4491, -1.9955)); coordinates.add(map.createGeoPoint(53.6200, -1.9539)); coordinates.add(map.createGeoPoint(53.4425, -1.6196)); coordinates.add(map.createGeoPoint(53.1900, -1.4969)); coordinates.add(map.createGeoPoint(53.1926, -1.6197)); Polyline polyline = map.createPolyline(coordinates); polyline.setStrokeWeight(5); polyline.setStrokeOpacity(0.5); polyline.setStrokeColor("#7341f4"); map.addPolyline(polyline);
-
Polygon
- a component that displays a polygon. You can use thecreatePolygon()
andaddPolygonOverlay()
methods of theMapViewer
interface to create this object and put it on a map. For example:List<GeoPoint> coordinates = new ArrayList<>(); coordinates.add(map.createGeoPoint(48.560579, 7.767876)); coordinates.add(map.createGeoPoint(48.561386, 7.782791)); coordinates.add(map.createGeoPoint(48.541940, 7.782861)); coordinates.add(map.createGeoPoint(48.545641, 7.768749)); Polygon p = map.createPolygon(coordinates, "#9CFBA9", 0.6, "#2CA860", 1.0, 2); map.addPolygonOverlay(p);
-
- Event listeners
-
The listener below are located in the
com.haulmont.charts.gui.map.model.listeners
package.-
CircleCenterChangeListener
- user changes the position of a circle center in map editing mode. -
CircleCompleteListener
- user creates a circle in map editing mode. -
CircleRadiusChangeListener
- user changes a circle radius in map editing mode. -
InfoWindowClosedListener
- user closes an information window. -
MapInitListener
- map initialization complete. This listener is invoked once after the first load of the map when all the tiles are loaded and coordinates are available. -
MapMoveListener
- user drags a map with a mouse button pressed. -
MarkerDragListener
- user drags a marker. -
PolygonCompleteListener
- user creates a polygon in map editing mode. -
PolygonEditListener
- user edits a polygon (moves or adds a vertex to an existing polygon).
Left click listeners:
-
CircleClickListener
- user clicks on a circle. -
MapClickListener
- user clicks on a map. -
MarkerClickListener
- user clicks on a marker. -
PolygonClickListener
- user clicks on a polygon.
Right click listeners:
-
CircleRightClickListener
- user right-clicks on a circle. -
MapRightCLickListener
- user right-clicks on a map. -
MarkerRightClickListener
- user right-clicks on a marker. -
PolygonRightClickListener
- user right-clicks on a polygon.
Double click listeners:
-
MarkerDoubleClickListener
- user double-clicks on a marker. -
CircleDoubleClickListener
- user double-clicks on a circle.
-
For a more detailed information about the methods and parameters of map components, please refer to the corresponding JavaDocs.
3. Displaying PivotTable
PivotTable
is a table component with drag-and-drop functionality that enables turning a data set into a summary table and manipulate it using 2D drag-and-drop UI. It is fully available via the CUBA Studio components library.
PivotTable
is based on the external JavaScript library - https://github.com/nicolaskruchten/pivottable. You can find more examples of PivotTable
on its author’s website: http://nicolas.kruchten.com/pivottable/examples/.
XML-name of the component: pivotTable
The component is implemented for the Web Client only.
An example of component definition in an XML-descriptor of a screen:
<chart:pivotTable id="tipsPivotTable"
datasource="tipsDs"
renderer="HEATMAP">
<chart:properties>
<chart:property name="row"/>
<chart:property name="totalBill"/>
<chart:property name="tip"/>
<chart:property name="sex"/>
<chart:property name="smoker"/>
<chart:property name="day"/>
<chart:property name="time"/>
<chart:property name="size"/>
</chart:properties>
<chart:aggregation mode="SUM_OVER_SUM">
<chart:property name="tip"/>
<chart:property name="totalBill"/>
</chart:aggregation>
<chart:rows>
<chart:row value="sex"/>
<chart:row value="smoker"/>
</chart:rows>
<chart:columns>
<chart:column value="day"/>
<chart:column value="time"/>
</chart:columns>
<chart:sortersFunction>
function(attr){
if(attr=="Day"){
return $.pivotUtilities.sortAs(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]);
}
}
</chart:sortersFunction>
</chart:pivotTable>
pivotTable elements
-
properties
- a key-value map with the set of properties to be used in thepivotTable
, where the key is the name of an attribute from the datasource, and the value is its localized caption.
-
derivedProperties
- can be used to add new attributes to the original data set, derived from the existing ones. This element is a key-value map, where the key is the name of a generated attribute, and the value is a JavaScript function that generates this attribute.-
the enclosed
derivedProperty
elements should have thecaption
attribute defined, as the caption’s value will be used as the key. -
the
function
element is used as the value for thederivedProperty
.
-
-
columns
- the list of attributes to be used as table columns. Its value can be either aproperties
key or a generated attribute’s name.
-
columnOrder
- the order in which column data is provided to the renderer.
-
rows
- the list of attributes to be used as table rows. Its value can be either aproperties
key or a generated attribute’s name.
-
rowOrder
- the order in which row data is provided to the renderer.
-
exclusions
- a key-value map where the key is the names of attributes (either aproperties
key or a generated attribute’s name), and the value is the list of these attributes' values to be excluded from rendering. Only for editablepivotTable
.
-
inclusions
- a key-value map where the key is the names of attributes (either aproperties
key or a generated attribute’s name), and the value is the list of these attributes' values to be rendered. Only for editablepivotTable
.
-
filterFunction
- JavaScript function that will be used for filtration.
-
renderers
- defines the collection of rendering functions that should be displayed in the list of available renderers in the UI.-
default
attribute enables setting one of predefined renderers. The selected renderer will be used as default when the component is loaded. -
enclosed
renderer
element enables setting one of predefined renderers using itstype
attribute:AREA_CHART
,BAR_CHART
,COL_HEATMAP
,HEATMAP
,HORIZONTAL_BAR_CHART
,HORIZONTAL_STACKED_BAR_CHART
,LINE_CHART
,ROW_HEATMAP
,SCATTER_CHART
,STACKED_BAR_CHART
,TABLE_BAR_CHART
,TABLE
,TREEMAP
,TSV_EXPORT
.
Only for editable
pivotTable
. -
-
rendererOptions
- defines the renderers' options. Actually only two renderer types can be customized:-
all kinds of
heatmap
. The cell colours can be set by the Javascript code. -
all kinds of charts. Options can be used to set the chart’s size.
-
-
sortersFunction
- JavaScript function that will be used for rows and columns captions sorting.- Aggregation elements of pivotTable
-
-
aggregation
- sets up a function which will aggregate results per cell.aggregation
attributes:-
mode
attribute enables setting one of predefined aggregation functions. -
caption
is a localized value to be displayed in the UI. -
custom
- iftrue
, themode
value is ignored in favor of the javaScript code from the enclosedfunction
element.aggregation
elements: -
function
- contains JavaScript code of an aggregation function. -
property
- the list of attributes to be used as input parameters of the aggregation function. Its value can be either aproperties
key or a generated attribute’s name. Only for non-editable
pivotTable
.For example:
<chart:aggregation mode="SUM_OVER_SUM" custom="true"> <chart:property name="tip"/> <chart:property name="Total Bill"/> </chart:aggregation>
-
-
aggregationProperties
- defines the list of attributes that should be displayed in the dropdown lists of aggregators. Its value can be either aproperties
key or a generated attribute’s name. Only for editablepivotTable
.<chart:aggregationProperties> <chart:property name="tip"/> <chart:property name="totalBill"/> </chart:aggregationProperties>
-
aggregations
- defines the collection of aggregators that should be displayed in the dropdown list of available aggregators in the UI.aggregations
attributes:-
default
attribute enables setting one of predefined aggregation functions. The selected function will be used as default when the component is loaded. -
enclosed
aggregation
element is used in the same way as aggregation except for the enclosedproperty
element. Only for editablepivotTable
.For example:
<chart:aggregations default="COUNT"> <chart:aggregation caption="Count"/> <chart:aggregation mode="SUM_OVER_SUM"/> </chart:aggregations>
-
-
pivotTable attributes
-
datasource
- sets a data source defined in thedsContext
section of the screen XML descriptor. ThecollectionDatasource
type is required.
-
editable
- iftrue
, the elements for manipulation with data will be displayed in the UI, otherwise only the data will be displayed.
-
renderer
- enables setting one of the predefined data renderers. Only for non-editablepivotTable
.
-
autoSortUnusedProperties
- defines if unused attributes should be sorted in the UI. Only for editablepivotTable
.
-
unusedPropertiesVertical
- defines if unused attributes should be displayed vertically (iftrue
) or horizontally (iffalse
, or by default). If set to a number, then if the attributes names' combined length in characters exceeds this number, the attributes will be shown vertically.
Listeners of pivotTable:
-
addCellClickListener
- adds a listener to thePivotTable
cell click events. TheCellClickEvent
is fired only for table renderers (TABLE
,HEATMAP
,TABLE_BAR_CHART
,COL_HEATMAP
,ROW_HEATMAP
).tipsPivotTableUI.addCellClickListener(event -> { showNotification("Value: " + event.getValue() + ",\n" + "Filters applied: " + event.getFilters()); });
-
addRefreshListener
- adds a listener to thePivotTable
refresh events. TheRefreshEvent
is fired only for editablePivotTable
.tipsPivotTableUI.addRefreshListener(event -> { showNotification("Row order :" + event.getRowOrder() + ",\n" + "Inclusions: " + event.getInclusions()); });
The following values are available from the
RefreshEvent
: aggregation, aggregationProperties, columns, columnOrder, exclusions, inclusions, renderer, rowOrder, rows.
- Attributes of pivotTable
-
autoSortUnusedProperties - datasource - editable - height - menuLimit - renderer - unusedPropertiesVertical - width
- Elements of pivotTable
-
aggregation - aggregationProperties - aggregations - columnOrder - columns - derivedProperties - exclusions - filterFunction - hiddenFromAggregations - hiddenFromDragDrop - hiddenProperties - inclusions - properties - rendererOptions - renderers - rowOrder - rows - sortersFunction
- API
3.1. Examples of PivotTable
3.1.1. Custom Aggregator and Derived Properties
Below is an example of the pivotTable
which differs from the example above in the custom aggregator and derived properties added in the Java-controller of the screen.
<chart:pivotTable id="tipsCustomAggregatorPivotTable"
datasource="tipsDs">
<chart:properties>
<chart:property name="row"/>
<chart:property name="totalBill"/>
<chart:property name="tip"/>
<chart:property name="sex"/>
<chart:property name="smoker"/>
<chart:property name="day"/>
<chart:property name="time"/>
<chart:property name="size"/>
</chart:properties>
<chart:aggregation mode="SUM_OVER_SUM" custom="true">
<chart:property name="tip"/>
<chart:property name="Total Bill"/>
</chart:aggregation>
<chart:rows>
<chart:row value="sex"/>
<chart:row value="Smokes"/>
</chart:rows>
<chart:columns>
<chart:column value="day"/>
<chart:column value="time"/>
</chart:columns>
</chart:pivotTable>
The sorting and aggregation functions can be set either in the XML-descriptor or in the Java-controller. In this example JavaScript functions are passed as parameters to the JsFunction
class constructor.
Derived properties can be defined in the screen controller as well.
public class PivotSampleScreen extends AbstractWindow {
@Inject
private PivotTable tipsCustomAggregatorPivotTable;
@Override
public void init(Map<String, Object> params) {
tipsCustomAggregatorPivotTable.setSortersFunction(
new JsFunction("function(attr){if(attr == \"Day\"){return $.pivotUtilities.sortAs([\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\"]);}}"));
tipsCustomAggregatorPivotTable.getAggregation().setFunction(
new JsFunction("$.pivotUtilities.aggregators[\"Sum\"]([\"Tip\"])"));
DerivedProperties derivedProperties = new DerivedProperties();
derivedProperties.addAttribute("Smokes",
new JsFunction("function(record) {return record.smoker == \"Yes\" ? \"True\" : \"False\";}"));
tipsCustomAggregatorPivotTable.setDerivedProperties(derivedProperties);
}
}
The result:
3.1.2. Editable PivotTable
In the example below we make the pivotTable
editable and set the default aggregation function. In the editable mode we can change the appearance (chart type) and the table content (rows and columns) directly in the UI.
<chart:pivotTable id="tipsPivotTableUI"
autoSortUnusedProperties="true"
datasource="tipsDs"
editable="true">
<chart:properties>
<chart:property name="row"/>
<chart:property name="totalBill"/>
<chart:property name="tip"/>
<chart:property name="sex" localizedName="Sex"/>
<chart:property name="smoker"/>
<chart:property name="day"/>
<chart:property name="time"/>
<chart:property name="size"/>
</chart:properties>
<chart:hiddenProperties>
<chart:property name="row"/>
</chart:hiddenProperties>
<chart:aggregationProperties>
<chart:property name="tip"/>
<chart:property name="totalBill"/>
</chart:aggregationProperties>
<chart:aggregations default="COUNT">
<chart:aggregation caption="Count"/>
<chart:aggregation mode="SUM_OVER_SUM"/>
</chart:aggregations>
<chart:renderers default="BAR_CHART"/>
<chart:rows>
<chart:row value="sex"/>
<chart:row value="smoker"/>
</chart:rows>
<chart:columns>
<chart:column value="day"/>
<chart:column value="time"/>
</chart:columns>
<chart:sortersFunction>
function(attr){
if(attr=="Day"){
return $.pivotUtilities.sortAs(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]);
}
}
</chart:sortersFunction>
</chart:pivotTable>