A newer version is available at the documentation home.

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 feedback or would like to suggest an improvement for this manual, please contact support at https://www.cuba-platform.com/support/topics.

If you find an error in this document, please specify the section number and attach a small piece of surrounding text to help us find it.

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 configuration property, which has the AbstractChart type.

Charts can be described in a screen XML-descriptor. To do this, you should connect the corresponding namespace:

<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.

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).

All charts can be exported from the running application as a picture or a source date. 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.

charts export menu 1

The export menu can be customized to limit user access to the chart data. Custom export menu can contain only image format(s), 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:

charts export menu 2

1.3. Connecting Data

There are two ways how you can pass data to a chart: through the DataProvider interface or using the datasource mechanism.

  • The DataProvider interface has a standard implementation: ListDataProvider class. It contains a list of DataItem instances from which the data for the chart will be taken. There are several standard implementations of DataItem interface:

    • EntityDataItem takes an instance of any entity.

    • MapDataItem is a set of key-value pairs.

    • SimpleDataItem takes an instance of any public class.

An instance of DataProvider is passed to the setDataProvider() method of chart configuration. This approach to providing chart data is the most universal, but it requires creating instances of DataProvider and DataItem in a screen controller.

  • A CollectionDatasource type datasource can be assigned to a Chart component by invoking the setDatasource() 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 both 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 the chart:pieChart component, you should define the valueField and titleField 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.

1.4. Events

It is possible to configure handling of different event types. The following listener types are available:

  • AxisZoomListener - chart axis scaling.

  • ChartClickListener - click on the canvas.

  • RightClickListener - 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.

  • LegendItemHideListener - hiding a legend item.

  • LegendItemShowListener - showing a legend item.

  • LegendItemClickListener - click on a legend item.

  • SliceClickListener - click on a slice in a pie chart.

  • SliceRightClickListener - right-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.

  • ZoomListener - scaling of the canvas.

Event handling examples are available in Using Events.

1.5. Example of Working with Charts

This chapter shows how you can use the chart display subsystem.

1.5.1. Setting up the Application Project

  1. Run CUBA Studio, create new project and name it sampler.

  2. Open Project propertiesEdit and select the charts component in the list of App components; save changes. Confirm when Studio will suggest recreating Gradle scripts.

  3. Select RunDeploy. At this point, the application will be assembled and deployed to the Tomcat application server located at build/tomcat.

  4. Select BuildCreate 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.5.2. Creating Chart with Data from an Entity

For the first example 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.5.2.1. Creating an Entity
  1. Open the Entities tab in CUBA Studio and click New entity button.

  2. In the New entity dialog type CountryGrowth in the Class name field, choose Not persistent for Entity type and click OK button.

  3. Using Entity Designer add attributes:

    • country of the type String

    • year2014 of the type Double

    • year2015 of the type Double

  4. 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.

  5. Click OK button to save the entity and close the designer screen.

  6. In the Entities tab click Generate DB scripts button and save scripts.

  7. Create the application database by selecting RunCreate database.

1.5.2.2. Creating Chart
1.5.2.2.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/column3d-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.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"
                              view="_local">
            <query>
                <![CDATA[select e from sampler$CountryGrowth e]]>
            </query>
        </collectionDatasource>
    </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): &lt;b&gt;[[value]]&lt;/b&gt;"
                             fillAlphas="0.9"
                             lineAlpha="0.2"
                             title="2014"
                             type="COLUMN"
                             valueField="year2014"/>
                <chart:graph id="graph2015"
                             balloonText="GDP grow in [[category]] (2015): &lt;b&gt;[[value]]&lt;/b&gt;"
                             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 from 0 to 90.

  • 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 the DataItem listed in a DataProvider instance, or names of the entity attributes from the datasource. To use html tags you must escape them.

  • depth3D - chart thickness. When used in combination with the angle 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 the DataItem objects listed in a DataProvider 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 the chart:axis element.

    • The position attribute defines position of the value axis relative to the chart.

    • Setting stackType to BOX_3D makes the chart display columns one behind the other.

  • chart:graphs - an element that contains the collection of chart:graph elements; the graph is described by the chart:graph element.

    • The type attribute defines the type of the graph and can be: line, column, step line, smoothed line, olhc and candlestick.

    • The valueField attribute defines a key from the list of pairs contained in the DataItem objects listed in a DataProvider 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.5.2.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.5.2.3. Result
  1. Open the Main Menu tab in CUBA Studio and click edit button for web-menu.xml.

  2. Choose application item and click new button.

  3. In Create menu item dialog choose column3d-chart for id field and click add.

  4. Select RunStart application server.

After logging in and opening the screen from the application menu you will see the chart like below:

column3d chart
Figure 1. Column 3D Chart

1.5.3. 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.5.3.1. Creating Chart
1.5.3.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 the DataItem objects listed in a DataProvider 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 the chart: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 to REGULAR makes the chart display a rolling value. Setting this attribute to none refers to a non-rolling value.

    • The gridAlpha defines opacity of grid lines.

  • chart:graphs - an element that contains the collection of chart:graph elements; the graph is described by the chart:graph element.

    • The type attribute defines the type of the graph and can be: line, column, step line, smoothed line, olhc and candlestick.

    • The valueField attribute defines a key from the list of pairs contained in the DataItem objects listed in a DataProvider 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 to true causes drawing the chart right from the value axis. The default value for this attribute is false. 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.5.3.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 serialChart = (SerialChart) chart.getConfiguration();
        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.5.3.2. Result
  1. Open the Main Menu tab in CUBA Studio and click edit button for web-menu.xml.

  2. Choose application item and click new button.

  3. In Create menu item dialog choose stackedarea-chart for id field and click add.

  4. Select RunStart application server.

After logging in and opening the screen from the application menu you will see the chart like below:

stackedarea chart
Figure 2. Stacked Area Chart

1.5.4. 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 Chart chart;

Then add a listener at the bottom of the init(Map<String, Object> params) method:

chart.addGraphItemClickListener(event -> {
        CountryGrowth countryGrowth = (CountryGrowth) event.getItem();
        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 RunRestart application server and log in to the system. Open the screen and click one of the columns.

chart with event
Figure 3. Chart that handles graph item click event

1.5.5. 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]));
    }

    SerialChart serialChartConfiguration = (SerialChart) serialChart.getConfiguration();
    serialChartConfiguration.setDataProvider(serialChartDataProvider);
}
chart custom json

And now we can change the chart’s configuration. As an example, let’s add a title:

serialChart.setCustomJson("{\n" +
        " \"titles\": [\n" +
        " {\n" +
        " \"size\": 15,\n" +
        " \"text\": \"Chart Title\"\n" +
        " }\n" +
        " ]\n" +
        "}");
chart custom json title

You can also set JSON configuration in the XML:

<chart:serialChart id="serialChart">
    <chart:customJson>
        <![CDATA[
        {
            "titles": [
                {
                    "size": 15,
                    "text": "Chart Title"
                }
            ]
        }
        ]]>
    </chart:customJson>
    <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.6. Chart Types

There are several chart types supported by CUBA platform.

charts hierarchy dia
Figure 4. Chart Types Hierarchy

1.6.1. 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.

line chart
Figure 5. SerialChart as Line Chart
column chart
Figure 6. SerialChart as Column Chart

1.6.2. PieChart

The PieChart component allows you to create pie/donut charts.

pie chart
Figure 7. PieChart

1.6.3. XYChart

The XYChart component allows you to create XY/bubble/scatter charts. The charts support multiple axes with simple or logarithmic scales.

xy chart
Figure 8. XYChart

1.6.4. FunnelChart

The FunnelChart component allows you to create funnel/pyramid charts.

funnel chart
Figure 9. FunnelChart

1.6.5. RadarChart

The RadarChart component allows you to create radar/polar charts.

radar chart
Figure 10. RadarChart

1.6.6. AngularGaugeChart

The AngularGaugeChart component allows you to create gauge charts.

gauge chart
Figure 11. GaugeChart

1.6.7. GanttChart

The GanttChart component allows you to create Gantt charts.

gantt chart
Figure 12. GanttChart

1.6.8. 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 with datasets
Figure 13. StockChart with multiple data sets

Stock chart can display a different kind of annotations on the graph or on the axis. These annotations are called stock events.

stock chart with stockevents
Figure 14. StockChart with StockEvents

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.

stock chart with panels
Figure 15. StockChart with multiple StockPanels

1.7. Replacing AmCharts Version

An instance of AmCharts library included in CUBA platform can be replaced with another one. To do this:

  1. Download charts and stock charts from AmCharts site.

  2. Merge amcharts folder from both archives into one.

  3. Copy amcharts folder to {project.rootDir}/modules/web/web/VAADIN/resources

  4. 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.

CubaAmchartsScene cubaAmchartsScene = (CubaAmchartsScene) WebComponentsHelper.unwrap(chart);
cubaAmchartsScene.setJson("{\"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.

    map demo click
  • Adding markers. Marker may be either fixed or draggable by user. Markers can process mouse clicks and send corresponding events to the screen code.

    map demo marker
  • Displaying polylines and polygons.

    map demo polygon display
  • Drawing polygons.

    map demo polygon draw
  • Heat map rendering.

    map demo heatmap

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 the MapViewer.Type: roadmap, satellite, hybrid, terrain. Default is roadmap.

  • vendor - map service provider. Currently the only supported value is google.

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:

    • setZoom() - sets the map zoom level.

    • setCenter() - sets the map center point.

    • setVisibleAreaBoundLimitsEnabled() - enables visible area limitation mode.

    • setVisibleAreaBoundLimits() - sets boundaries of the visible area of the map.

    • 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.

    • setMaxZoom() - sets the maximum available zoom level.

    • setMinZoom() - sets the minimum available zoom level.

    • setDraggable() - enables/disables map dragging mode.

    • setKeyboardShortcutsEnabled() - enables/disables keyboard shortcuts.

    • setScrollWheelEnabled() - enables/disables map zoom with a mouse scroll wheel.

    • setMapType() - defines map type.

  • Map component interfaces (can be found in com.haulmont.charts.gui.map.model package):

    • 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 the createGeoPoint()`method of the `MapViewer interface. For example:

      GeoPoint center = map.createGeoPoint(53.490905, -2.249558);
      map.setCenter(center);
    • 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 the createMarker() and addMarker()`methods of the `MapViewer 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);
    • Polyline - a component that displays a polyline. You can use the createPolyline() and addPolyline() methods of the MapViewer interface to create this object and put it on a map. For example:

      List<GeoPoint> coordinates = new ArrayList<>();
      coordinates.add(map.createGeoPoint(53.49, -2.54));
      coordinates.add(map.createGeoPoint(53.49, -2.22));
      coordinates.add(map.createGeoPoint(53.89, -2.22));
      coordinates.add(map.createGeoPoint(53.99, -2.94));
      Polyline polyline = map.createPolyline(coordinates);
      map.addPolyline(polyline);
    • Polygon - a component that displays a polygon. You can use the createPolygon() and addPolygonOverlay() methods of the MapViewer interface to create this object and put it on a map. For example:

      List<GeoPoint> coordinates = new ArrayList<>();
      coordinates.add(map.createGeoPoint(53.49, -2.54));
      coordinates.add(map.createGeoPoint(53.49, -2.22));
      coordinates.add(map.createGeoPoint(53.89, -2.22));
      coordinates.add(map.createGeoPoint(53.99, -2.94));
      Polygon p = map.createPolygon(coordinates, "#9CFBA9", 0.6, "#2CA860", 1.0, 2);
      map.addPolygonOverlay(p);
    • InfoWindow - a map component that displays information in a pop-up window. You can use the createInfoWindow() and openInfoWindow() methods of the MapViewer 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(new MarkerClickListener() {
          @Override
          public void onClick(MarkerClickEvent 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);
          }
      });
    • 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 the createHeatMapLayer() and addHeatMapLayer() methods of the MapViewer 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.00));
      data.add(map.createGeoPoint(53.451, -2.00));
      data.add(map.createGeoPoint(53.452, -2.00));
      data.add(map.createGeoPoint(53.453, -2.00));
      data.add(map.createGeoPoint(53.454, -2.00));
      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.

    • DrawingOptions - auxiliary drawing component. Only polygon drawing is currently supported. Drawing mode can be enabled by passing an instance of DrawingOptions to the MapViewer. 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);
  • Event listeners (located in the com.haulmont.charts.gui.map.model.listeners) package):

    • MapMoveListener - user drags a map with a mouse button pressed.

    • MapClickListener - user clicks on a map.

    • MarkerClickListener - user clicks on a marker.

    • MarkerDragListener - user drags a marker.

    • InfoWindowClosedListener - user closes an information window.

    • PolygonCompleteListener - user creates a polygon in map editing mode.

    • PolygonEditListener - user edits a polygon (moves or adds a vertex to an existing polygon).

    • 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.

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

PivotTable

The component is implemented for the Web Client only.

PivotTable 1

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 the pivotTable, 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 the caption attribute defined, as the `caption’s value will be used as the key.

    • the function element is used as the value for the derivedProperty.

  • hiddenProperties - the list of attributes that should not be displayed in the UI. Its value can be either a properties key or a generated attribute’s name (i.e. the derivedProperties key). Applicable for editable pivotTable only.

  • columns - the list of attributes to be used as table columns. Its value can be either a properties key or a generated attribute’s name.

  • rows - the list of attributes to be used as table rows. Its value can be either a properties key or a generated attribute’s name.

  • 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 - if true, the mode value is ignored in favor of the javaScript code from the enclosed function 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 a properties key or a generated attribute’s name. Only for non-editable pivotTable.

  • aggregationProperties - the list of attributes that should be displayed in the dropdown lists of aggregators. Its value can be either a properties key or a generated attribute’s name. Only for editable pivotTable.

  • aggregations - defines the collection of aggregators that should be displayed in the dropdown list of available aggregators in the UI.

    • 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 enclosed property element. Only for editable pivotTable.

  • exclusions - a key-value map where the key is the names of attributes (either a properties key or a generated attribute’s name), and the value is the list of these attributes' values to be excluded from rendering. Only for editable pivotTable.

  • inclusions - a key-value map where the key is the names of attributes (either a properties key or a generated attribute’s name), and the value is the list of these attributes' values to be rendered. Only for editable pivotTable.

  • 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 its type attribute.

  • 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.

pivotTable attributes

  • datasource - sets a data source defined in the dsContext section of the screen XML descriptor. The collectionDatasource type is required.

  • editable - if true, the elements for manipulation with data will be displayed in the UI, otherwise only the data will be displayed.

  • menuLimit - maximum number of values displayed in the double-click menu. If the number of records is exceeded, the corresponding message appears. Only for editable pivotTable.

  • renderer - enables setting one of the predefined data renderers. Only for non-editable pivotTable.

  • autoSortUnusedProperties - defines if unused attributes should be sorted in the UI. Only for editable pivotTable.

  • unusedPropertiesVertical - defines if unused attributes should be displayed vertically (if true) or horizontally (if false, 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.



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:

PivotTable 2

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>
PivotTable 3
. . .