EntityChartProperty<T> chartProperty = new EntityChartProperty<T>(backingBean, propertyName, null);
// bar or line chart
RenderStyle renderStyle = new RenderStyle(RenderStyle.BAR_CHART);
chartProperty.setRenderStyle(renderStyle);
CartesianChart cartesianChart = new CartesianChart();
cartesianChart.setTitle(new ParameterizedMessage("Year-on-year Car Sales", true));
cartesianChart.setStacked(true);
ChartSeries chartSeriesA = new ChartSeries(
I18NName.valueOf("Car Model A", true),
Arrays.asList(200, 300, 500));
ChartSeries chartSeriesB = new ChartSeries(
I18NName.valueOf("Car Model B", true),
Arrays.asList(300, 500, 800));
cartesianChart.addSeries(chartSeriesA);
cartesianChart.addSeries(chartSeriesB);
cartesianChart.setLabels(I18NName.asList(true, "2020", "2021", "2022"));
chartProperty.setCartesianChart(cartesianChart);
// partial behavior to enable drill down
chartProperty.getPartialBehaviorSupport(true).addPartialBehavior(
new PartialBehavior(PartialBehavior.EVENT_ITEM_SELECT));
backingBean.getEntityPropertyList(true).add(chartProperty);
Example 2: create a pie chart
EntityChartProperty<T> chartProperty = new EntityChartProperty<T>(backingBean, propertyName, null);
RenderStyle renderStyle = new RenderStyle(RenderStyle.PIE_CHART);
chartProperty.setRenderStyle(renderStyle);
PieChart pieChart = new PieChart();
pieChart.setTitle(new ParameterizedMessage("Year-on-year Car Sales", true));
ChartSeries chartSeries = new ChartSeries(
I18NName.valueOf("Car Sales", true),
Arrays.asList(500, 800, 1300));
pieChart.addSeries(chartSeries);
pieChart.setLabels(I18NName.asList(true, "2020", "2021", "2022"));
chartProperty.setPieChart(pieChart);
// partial behavior to enable drill down
chartProperty.getPartialBehaviorSupport(true).addPartialBehavior(
new PartialBehavior(PartialBehavior.EVENT_ITEM_SELECT));
backingBean.getEntityPropertyList(true).add(chartProperty);
To support more chart types, see Extensions.
For charting, the X-axis is date periods, and Y-axis is reporting values. Multiple series of values can be shown in one chart, and they can be stacked in bar or line chart. For tabular listing, the table headers are date periods, and table rows are series of values. Clicking items in chart or tabular listing will pop up dialog for drill down.
ReportQueryForm and ReportQueryFormBean are the base classes for reporting. A ReportQueryForm allows users to input or select report data, date periods and report display options. Display options include display format, chart type, whether to stack, legend position and chart dimensions. For the example HR module, ExpenseReportQueryForm extends ReportQueryForm to add employee and ExpenseClaimItem code as query restrictions.
public class ExpenseReportQueryForm extends ReportQueryForm {
private Employee employee;
private String code;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
ExpenseReportQueryFormBean extends ReportQueryFormBean, adding employee, code and groupBy properties. Group by employee or code. The reportDataList and groupBy of ReportQueryForm are integers, and they need to have names for display.
public class ExpenseReportQueryFormBean extends ReportQueryFormBean<ExpenseReportQueryForm> {
@UIDefines({
@UIDefine(name=UI_QUERY_PROPERTIES, value={
@Property(name="groupBy", view={ViewType.ALL},
renderStyle=@RenderStyleDef(style=RenderStyle.SELECT_ONE_MENU)),
@Property(name="employee", view={ViewType.ALL}),
@Property(name="code", view={ViewType.ALL})
})
})
public boolean hasPropertyAnnotations() {
return true;
}
@Override
public List<SelectItem> getPropertySelectItems(EntityProperty<ExpenseReportQueryForm> property) throws SystemException {
// return selectItems for reportDataList and groupBy
}
@Override
protected I18NName getReportDataName(Integer reportData) throws SystemException {
// reportData name
}
@Override
protected NumberDescriptor getReportDataNumberDescriptor(Integer reportData) throws SystemException {
// reportData number type
}
@Override
protected I18NName getGroupByName(Integer groupBy) throws SystemException {
// groupBy choice name
}
@Override
protected void buildCriteriaQuery(CriteriaBuilder criteriaBuilder, CriteriaQuery<Object[]> criteriaQuery,
T reportQueryForm, List<Integer> reportDataList, DatePeriod datePeriod, int periodIndex) {
// build query criteria for the report data list
}
@Override
protected List<I18NName> getGroupByValueDisplayNames(T queryForm,
List<Comparable> groupByValues,
Map<Comparable, PersistenceEntity> groupByValueEntityMap) throws SystemException {
// display names of group by values, employee names or codes
}
@Override
protected Predicate getRestriction(CriteriaBuilder criteriaBuilder, CriteriaQuery<Object[]> criteriaQuery,
int reportData, int groupBy, Object groupByValue) {
// get restriction for the reportData and groupBy value
}
@Override
protected DatePeriodInfo getDefaultDatePeriodInfo() throws SystemException {
// default date period for ReportQueryForm
}
@Override
public HelpPathInfo getHelpPathInfo(PersistenceDataBackingBean<ExpenseReportQueryForm> backingBean) {
// help URL path
}
}
See the example HR module on how to implement these methods.
Building query criteria is the main task of reporting. If groupBy is not null, add the groupBy to the query criteria. If groupBy is selected, only one reportData is allowed. For the example HR module, if there are 10 employees and expense report is grouping by employee, then there will be 10 series of values, one for each employee. If there are too many series of values, tabular list is a better options for report display, which can be exported as Excel.
@Override
public PageNavigation handleItemSelect(ReportBean reportBean,
int seriesIndex, int itemIndex) throws SystemException {
}