IDEMPIERE-1583 Zk: Pluggable Chart Renderer Service.

This commit is contained in:
Heng Sin Low 2013-11-29 18:33:03 +08:00
parent 69ca16cbd9
commit a7db58fb5b
22 changed files with 1178 additions and 869 deletions

View File

@ -0,0 +1,642 @@
/******************************************************************************
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.apps.graph;
import java.awt.Color;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import org.adempiere.exceptions.DBException;
import org.compiere.model.MChart;
import org.compiere.model.MChartDatasource;
import org.compiere.model.MQuery;
import org.compiere.model.MRole;
import org.compiere.model.MTable;
import org.compiere.model.X_AD_Chart;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Util;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.Month;
import org.jfree.data.time.Quarter;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.Week;
import org.jfree.data.time.Year;
import org.jfree.data.xy.IntervalXYDataset;
/**
* @author Paul Bowden, Adaxa Pty Ltd
* @author hengsin
*
*/
public class ChartBuilder {
private final static CLogger log = CLogger.getCLogger(ChartBuilder.class);
private MChart chartModel;
private HashMap<String,MQuery> queries;
private Dataset dataset;
public ChartBuilder(MChart chart) {
this.chartModel = chart;
}
/**
*
* @param type
* @return JFreeChart
*/
public JFreeChart createChart() {
String type = chartModel.getChartType();
if(MChart.CHARTTYPE_BarChart.equals(type))
{
if ( chartModel.isTimeSeries())
{
return createXYBarChart();
}
return createBarChart();
}
else if (MChart.CHARTTYPE_3DBarChart.equals(type))
{
return create3DBarChart();
}
else if (MChart.CHARTTYPE_StackedBarChart.equals(type))
{
if ( chartModel.isTimeSeries())
return createXYBarChart();
return createStackedBarChart();
}
else if (MChart.CHARTTYPE_3DStackedBarChart.equals(type))
{
return create3DStackedBarChart();
}
else if (MChart.CHARTTYPE_3DPieChart.equals(type))
{
return create3DPieChart();
}
else if (MChart.CHARTTYPE_PieChart.equals(type))
{
return createPieChart();
}
else if (MChart.CHARTTYPE_3DLineChart.equals(type))
{
return create3DLineChart();
}
else if (MChart.CHARTTYPE_AreaChart.equals(type))
{
return createAreaChart();
}
else if (MChart.CHARTTYPE_StackedAreaChart.equals(type))
{
return createStackedAreaChart();
}
else if (MChart.CHARTTYPE_LineChart.equals(type))
{
if ( chartModel.isTimeSeries() )
return createTimeSeriesChart();
return createLineChart();
}
else if (MChart.CHARTTYPE_RingChart.equals(type))
{
return createRingChart();
}
else if (MChart.CHARTTYPE_WaterfallChart.equals(type))
{
return createWaterfallChart();
}
else
{
throw new IllegalArgumentException("unknown chart type=" + type);
}
}
public void loadData() {
queries = new HashMap<String,MQuery>();
for ( MChartDatasource ds : chartModel.getDatasources() )
{
addData(ds);
}
}
private void addData(MChartDatasource ds) {
String value = ds.getValueColumn();
String category;
String unit = "D";
if ( !chartModel.isTimeSeries() )
category = ds.getCategoryColumn();
else
{
if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Week))
{
unit = "W";
}
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Month))
{
unit = "MM";
}
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Quarter))
{
unit = "Q";
}
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Year))
{
unit = "Y";
}
category = " TRUNC(" + ds.getDateColumn() + ", '" + unit + "') ";
}
String series = DB.TO_STRING(ds.getName());
boolean hasSeries = false;
if (ds.getSeriesColumn() != null)
{
series = ds.getSeriesColumn();
hasSeries = true;
}
String where = ds.getWhereClause();
if ( !Util.isEmpty(where))
{
where = Env.parseContext(Env.getCtx(), chartModel.getWindowNo(), where, true);
}
boolean hasWhere = false;
String sql = "SELECT " + value + ", " + category + ", " + series
+ " FROM " + ds.getFromClause();
if ( !Util.isEmpty(where))
{
sql += " WHERE " + where;
hasWhere = true;
}
Date currentDate = Env.getContextAsDate(Env.getCtx(), "#Date");
Date startDate = null;
Date endDate = null;
int scope = chartModel.getTimeScope();
int offset = ds.getTimeOffset();
if ( chartModel.isTimeSeries() && scope != 0 )
{
offset += -scope;
startDate = increment(currentDate, chartModel.getTimeUnit(), offset);
endDate = increment(startDate, chartModel.getTimeUnit(), scope);
}
if ( startDate != null && endDate != null )
{
sql += hasWhere ? " AND " : " WHERE ";
sql += category + ">=TRUNC(" + DB.TO_DATE(new Timestamp(startDate.getTime())) + ", '" + unit + "') AND ";
sql += category + "<=TRUNC(" + DB.TO_DATE(new Timestamp(endDate.getTime())) + ", '" + unit + "') ";
}
if (sql.indexOf('@') >= 0) {
sql = Env.parseContext(Env.getCtx(), 0, sql, false, true);
}
MRole role = MRole.getDefault(Env.getCtx(), false);
sql = role.addAccessSQL(sql, null, true, false);
if (hasSeries)
sql += " GROUP BY " + series + ", " + category + " ORDER BY " + series + ", " + category;
else
sql += " GROUP BY " + category + " ORDER BY " + category;
log.log(Level.FINE, sql);
PreparedStatement pstmt = null;
ResultSet rs = null;
TimeSeries tseries = null;
Dataset dataset = getDataset();
try
{
pstmt = DB.prepareStatement(sql, null);
rs = pstmt.executeQuery();
while(rs.next())
{
String key = rs.getString(2);
String seriesName = rs.getString(3);
if (seriesName == null)
seriesName = ds.getName();
String queryWhere = "";
if ( hasWhere )
queryWhere += where + " AND ";
queryWhere += series + " = " + DB.TO_STRING(seriesName) + " AND " + category + " = " ;
if ( chartModel.isTimeSeries() && dataset instanceof TimeSeriesCollection )
{
if ( tseries == null || !tseries.getKey().equals(seriesName))
{
if (tseries != null)
((TimeSeriesCollection) dataset).addSeries(tseries);
tseries = new TimeSeries(seriesName);
}
Date date = rs.getDate(2);
RegularTimePeriod period = null;
if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Day))
period = new Day(date);
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Week))
period = new Week(date);
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Month))
period = new Month(date);
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Quarter))
period = new Quarter(date);
else if ( chartModel.getTimeUnit().equals(MChart.TIMEUNIT_Year))
period = new Year(date);
tseries.add(period, rs.getBigDecimal(1));
key = period.toString();
queryWhere += DB.TO_DATE(new Timestamp(date.getTime()));
}
else {
queryWhere += DB.TO_STRING(key);
}
MQuery query = new MQuery(ds.getAD_Table_ID());
String keyCol = MTable.get(Env.getCtx(), ds.getAD_Table_ID()).getKeyColumns()[0];
String whereClause = keyCol + " IN (SELECT " + ds.getKeyColumn() + " FROM "
+ ds.getFromClause() + " WHERE " + queryWhere + " )";
query.addRestriction(whereClause.toString());
query.setRecordCount(1);
HashMap<String, MQuery> map = getQueries();
if ( dataset instanceof DefaultPieDataset) {
((DefaultPieDataset) dataset).setValue(key, rs.getBigDecimal(1));
map.put(key, query);
}
else if ( dataset instanceof DefaultCategoryDataset ) {
((DefaultCategoryDataset) dataset).addValue(rs.getBigDecimal(1), seriesName, key);
map.put(seriesName + "__" + key, query);
}
else if (dataset instanceof TimeSeriesCollection )
{
map.put(seriesName + "__" + key, query);
}
}
}
catch (SQLException e)
{
throw new DBException(e, sql);
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
if (tseries != null)
((TimeSeriesCollection) dataset).addSeries(tseries);
}
private Date increment(Date lastDate, String timeUnit, int qty) {
if ( lastDate == null )
return null;
Calendar cal = Calendar.getInstance();
cal.setTime(lastDate);
if ( timeUnit.equals(MChart.TIMEUNIT_Day))
cal.add(Calendar.DAY_OF_YEAR, qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Week))
cal.add(Calendar.WEEK_OF_YEAR, qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Month))
cal.add(Calendar.MONTH, qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Quarter))
cal.add(Calendar.MONTH, 3*qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Year))
cal.add(Calendar.YEAR, qty);
return cal.getTime();
}
public CategoryDataset getCategoryDataset() {
dataset = new DefaultCategoryDataset();
loadData();
return (CategoryDataset) dataset;
}
public IntervalXYDataset getXYDataset() {
dataset = new TimeSeriesCollection();
loadData();
return (IntervalXYDataset) dataset;
}
public PieDataset getPieDataset() {
dataset = new DefaultPieDataset();
loadData();
return (PieDataset) dataset;
}
public Dataset getDataset() {
return dataset;
}
public HashMap<String, MQuery> getQueries() {
return queries;
}
public MQuery getQuery(String key) {
if ( queries.containsKey(key) )
{
return queries.get(key);
}
return null;
}
private JFreeChart createXYBarChart() {
JFreeChart chart = ChartFactory.createXYBarChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
true,
chartModel.getRangeLabel(), // range axis label
getXYDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
return chart;
}
private JFreeChart createTimeSeriesChart() {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getXYDataset(), // data
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
return chart;
}
private JFreeChart createWaterfallChart() {
JFreeChart chart = ChartFactory.createWaterfallChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createRingChart() {
final JFreeChart chart = ChartFactory.createRingChart(chartModel.getName(),
getPieDataset(), chartModel.isDisplayLegend(), true, true);
return chart;
}
private JFreeChart createPieChart() {
final JFreeChart chart = ChartFactory.createPieChart(chartModel.getName(),
getPieDataset(), false, true, true);
return chart;
}
private JFreeChart create3DPieChart() {
final JFreeChart chart = ChartFactory.createPieChart3D(chartModel.getName(),
getPieDataset(), false, true, true);
return chart;
}
private JFreeChart createBarChart() {
JFreeChart chart = ChartFactory.createBarChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
BarRenderer renderer = new BarRenderer();
renderer.setBarPainter(new StandardBarPainter());
CategoryPlot plot = chart.getCategoryPlot();
plot.setRenderer(renderer);
setupCategoryChart(chart);
return chart;
}
private JFreeChart create3DBarChart() {
JFreeChart chart = ChartFactory.createBarChart3D(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createStackedBarChart() {
JFreeChart chart = ChartFactory.createStackedBarChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
BarRenderer renderer = new BarRenderer();
renderer.setBarPainter(new StandardBarPainter());
CategoryPlot plot = chart.getCategoryPlot();
plot.setRenderer(renderer);
setupCategoryChart(chart);
return chart;
}
private JFreeChart create3DStackedBarChart() {
JFreeChart chart = ChartFactory.createStackedBarChart3D(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createAreaChart() {
// create the chart...
JFreeChart chart = ChartFactory.createAreaChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createStackedAreaChart() {
// create the chart...
JFreeChart chart = ChartFactory.createStackedAreaChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createLineChart() {
// create the chart...
JFreeChart chart = ChartFactory.createLineChart(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart create3DLineChart() {
// create the chart...
JFreeChart chart = ChartFactory.createLineChart3D(
chartModel.getName(), // chart title
chartModel.getDomainLabel(), // domain axis label
chartModel.getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(chartModel.getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
chartModel.isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private void setupCategoryChart(JFreeChart chart) {
CategoryPlot plot = chart.getCategoryPlot();
CategoryAxis xAxis = (CategoryAxis)plot.getDomainAxis();
xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
CategoryItemRenderer renderer = plot.getRenderer();
renderer.setSeriesPaint(0, Color.RED);
renderer.setSeriesPaint(1, Color.BLUE);
renderer.setSeriesPaint(2, Color.YELLOW);
renderer.setSeriesPaint(3, Color.GREEN);
renderer.setSeriesPaint(4, Color.ORANGE);
renderer.setSeriesPaint(5, Color.CYAN);
renderer.setSeriesPaint(6, Color.MAGENTA);
renderer.setSeriesPaint(7, Color.GRAY);
renderer.setSeriesPaint(8, Color.PINK);
plot.setRenderer(renderer);
}
}

View File

@ -16,6 +16,7 @@ package org.adempiere.apps.graph;
import java.awt.Color; import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.List;
import org.compiere.model.MGoal; import org.compiere.model.MGoal;
import org.compiere.model.MMeasure; import org.compiere.model.MMeasure;
@ -245,6 +246,11 @@ public class GraphBuilder {
ArrayList<GraphColumn>list = measure.getGraphColumnList(getMGoal()); ArrayList<GraphColumn>list = measure.getGraphColumnList(getMGoal());
loadDataSet(list);
return list;
}
public void loadDataSet(List<GraphColumn> list) {
pieDataset = new DefaultPieDataset(); pieDataset = new DefaultPieDataset();
dataset = new DefaultCategoryDataset(); dataset = new DefaultCategoryDataset();
for (int i = 0; i < list.size(); i++){ for (int i = 0; i < list.size(); i++){
@ -260,6 +266,5 @@ public class GraphBuilder {
list.get(i).getLabel()); list.get(i).getLabel());
pieDataset.setValue(list.get(i).getLabel(), list.get(i).getValue()); pieDataset.setValue(list.get(i).getLabel(), list.get(i).getValue());
} }
return list;
} }
} }

View File

@ -1,27 +1,10 @@
package org.compiere.model; package org.compiere.model;
import java.awt.Color;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.IntervalXYDataset;
public class MChart extends X_AD_Chart { public class MChart extends X_AD_Chart {
@ -31,8 +14,6 @@ public class MChart extends X_AD_Chart {
private static final long serialVersionUID = -8851465915516536910L; private static final long serialVersionUID = -8851465915516536910L;
private int windowNo=0; private int windowNo=0;
private Dataset dataset;
private HashMap<String,MQuery> queries;
public MChart(Properties ctx, int AD_Chart_ID, String trxName) { public MChart(Properties ctx, int AD_Chart_ID, String trxName) {
super(ctx, AD_Chart_ID, trxName); super(ctx, AD_Chart_ID, trxName);
@ -42,46 +23,12 @@ public class MChart extends X_AD_Chart {
super(ctx, rs, trxName); super(ctx, rs, trxName);
} }
public void loadData() { public List<MChartDatasource> getDatasources() {
queries = new HashMap<String,MQuery>();
for ( MChartDatasource ds : getDatasources() )
{
ds.addData(this);
}
}
public CategoryDataset getCategoryDataset() {
dataset = new DefaultCategoryDataset();
loadData();
return (CategoryDataset) dataset;
}
public IntervalXYDataset getXYDataset() {
dataset = new TimeSeriesCollection();
loadData();
return (IntervalXYDataset) dataset;
}
public PieDataset getPieDataset() {
dataset = new DefaultPieDataset();
loadData();
return (PieDataset) dataset;
}
public Dataset getDataset() {
return dataset;
}
private List<MChartDatasource> getDatasources() {
return new Query(getCtx(), MChartDatasource.Table_Name, MChart.COLUMNNAME_AD_Chart_ID + "=?", null) return new Query(getCtx(), MChartDatasource.Table_Name, MChart.COLUMNNAME_AD_Chart_ID + "=?", null)
.setParameters(getAD_Chart_ID()).setOnlyActiveRecords(true).list(); .setParameters(getAD_Chart_ID()).setOnlyActiveRecords(true).list();
} }
public HashMap<String, MQuery> getQueries() {
return queries;
}
public void setWindowNo(int windowNo) { public void setWindowNo(int windowNo) {
this.windowNo = windowNo; this.windowNo = windowNo;
} }
@ -89,334 +36,4 @@ public class MChart extends X_AD_Chart {
public int getWindowNo() { public int getWindowNo() {
return windowNo; return windowNo;
} }
public MQuery getQuery(String key) {
if ( queries.containsKey(key) )
{
return queries.get(key);
}
return null;
}
/**
*
* @param type
* @return JFreeChart
*/
public JFreeChart createChart() {
String type = getChartType();
if(MChart.CHARTTYPE_BarChart.equals(type))
{
if ( isTimeSeries())
{
return createXYBarChart();
}
return createBarChart();
}
else if (MChart.CHARTTYPE_3DBarChart.equals(type))
{
return create3DBarChart();
}
else if (MChart.CHARTTYPE_StackedBarChart.equals(type))
{
if ( isTimeSeries())
return createXYBarChart();
return createStackedBarChart();
}
else if (MChart.CHARTTYPE_3DStackedBarChart.equals(type))
{
return create3DStackedBarChart();
}
else if (MChart.CHARTTYPE_3DPieChart.equals(type))
{
return create3DPieChart();
}
else if (MChart.CHARTTYPE_PieChart.equals(type))
{
return createPieChart();
}
else if (MChart.CHARTTYPE_3DLineChart.equals(type))
{
return create3DLineChart();
}
else if (MChart.CHARTTYPE_AreaChart.equals(type))
{
return createAreaChart();
}
else if (MChart.CHARTTYPE_StackedAreaChart.equals(type))
{
return createStackedAreaChart();
}
else if (MChart.CHARTTYPE_LineChart.equals(type))
{
if ( isTimeSeries() )
return createTimeSeriesChart();
return createLineChart();
}
else if (MChart.CHARTTYPE_RingChart.equals(type))
{
return createRingChart();
}
else if (MChart.CHARTTYPE_WaterfallChart.equals(type))
{
return createWaterfallChart();
}
else
{
throw new IllegalArgumentException("unknown chart type=" + type);
}
}
private JFreeChart createXYBarChart() {
JFreeChart chart = ChartFactory.createXYBarChart(
getName(), // chart title
getDomainLabel(), // domain axis label
true,
getRangeLabel(), // range axis label
getXYDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
return chart;
}
private JFreeChart createTimeSeriesChart() {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getXYDataset(), // data
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
return chart;
}
private JFreeChart createWaterfallChart() {
JFreeChart chart = ChartFactory.createWaterfallChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createRingChart() {
final JFreeChart chart = ChartFactory.createRingChart(getName(),
getPieDataset(), isDisplayLegend(), true, true);
return chart;
}
private JFreeChart createPieChart() {
final JFreeChart chart = ChartFactory.createPieChart(getName(),
getPieDataset(), false, true, true);
return chart;
}
private JFreeChart create3DPieChart() {
final JFreeChart chart = ChartFactory.createPieChart3D(getName(),
getPieDataset(), false, true, true);
return chart;
}
private JFreeChart createBarChart() {
JFreeChart chart = ChartFactory.createBarChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
BarRenderer renderer = new BarRenderer();
renderer.setBarPainter(new StandardBarPainter());
CategoryPlot plot = chart.getCategoryPlot();
plot.setRenderer(renderer);
setupCategoryChart(chart);
return chart;
}
private JFreeChart create3DBarChart() {
JFreeChart chart = ChartFactory.createBarChart3D(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createStackedBarChart() {
JFreeChart chart = ChartFactory.createStackedBarChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
BarRenderer renderer = new BarRenderer();
renderer.setBarPainter(new StandardBarPainter());
CategoryPlot plot = chart.getCategoryPlot();
plot.setRenderer(renderer);
setupCategoryChart(chart);
return chart;
}
private JFreeChart create3DStackedBarChart() {
JFreeChart chart = ChartFactory.createStackedBarChart3D(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createAreaChart() {
// create the chart...
JFreeChart chart = ChartFactory.createAreaChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createStackedAreaChart() {
// create the chart...
JFreeChart chart = ChartFactory.createStackedAreaChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart createLineChart() {
// create the chart...
JFreeChart chart = ChartFactory.createLineChart(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private JFreeChart create3DLineChart() {
// create the chart...
JFreeChart chart = ChartFactory.createLineChart3D(
getName(), // chart title
getDomainLabel(), // domain axis label
getRangeLabel(), // range axis label
getCategoryDataset(), // data
X_AD_Chart.CHARTORIENTATION_Horizontal.equals(getChartOrientation())
? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL, // orientation
isDisplayLegend(), // include legend
true, // tooltips?
true // URLs?
);
setupCategoryChart(chart);
return chart;
}
private void setupCategoryChart(JFreeChart chart) {
CategoryPlot plot = chart.getCategoryPlot();
CategoryAxis xAxis = (CategoryAxis)plot.getDomainAxis();
xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
CategoryItemRenderer renderer = plot.getRenderer();
renderer.setSeriesPaint(0, Color.RED);
renderer.setSeriesPaint(1, Color.BLUE);
renderer.setSeriesPaint(2, Color.YELLOW);
renderer.setSeriesPaint(3, Color.GREEN);
renderer.setSeriesPaint(4, Color.ORANGE);
renderer.setSeriesPaint(5, Color.CYAN);
renderer.setSeriesPaint(6, Color.MAGENTA);
renderer.setSeriesPaint(7, Color.GRAY);
renderer.setSeriesPaint(8, Color.PINK);
plot.setRenderer(renderer);
}
} }

View File

@ -3,29 +3,14 @@ package org.compiere.model;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.DBException; import org.adempiere.exceptions.DBException;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Util; import org.compiere.util.Util;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.Month;
import org.jfree.data.time.Quarter;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.Week;
import org.jfree.data.time.Year;
public class MChartDatasource extends X_AD_ChartDatasource { public class MChartDatasource extends X_AD_ChartDatasource {
@ -43,209 +28,6 @@ public class MChartDatasource extends X_AD_ChartDatasource {
super(ctx, rs, trxName); super(ctx, rs, trxName);
} }
public void addData(MChart parent) {
String value = getValueColumn();
String category;
String unit = "D";
if ( !parent.isTimeSeries() )
category = getCategoryColumn();
else
{
if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Week))
{
unit = "W";
}
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Month))
{
unit = "MM";
}
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Quarter))
{
unit = "Q";
}
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Year))
{
unit = "Y";
}
category = " TRUNC(" + getDateColumn() + ", '" + unit + "') ";
}
String series = DB.TO_STRING(getName());
boolean hasSeries = false;
if (getSeriesColumn() != null)
{
series = getSeriesColumn();
hasSeries = true;
}
String where = getWhereClause();
if ( !Util.isEmpty(where))
{
where = Env.parseContext(getCtx(), parent.getWindowNo(), where, true);
}
boolean hasWhere = false;
String sql = "SELECT " + value + ", " + category + ", " + series
+ " FROM " + getFromClause();
if ( !Util.isEmpty(where))
{
sql += " WHERE " + where;
hasWhere = true;
}
Date currentDate = Env.getContextAsDate(getCtx(), "#Date");
Date startDate = null;
Date endDate = null;
int scope = parent.getTimeScope();
int offset = getTimeOffset();
if ( parent.isTimeSeries() && scope != 0 )
{
offset += -scope;
startDate = increment(currentDate, parent.getTimeUnit(), offset);
endDate = increment(startDate, parent.getTimeUnit(), scope);
}
if ( startDate != null && endDate != null )
{
sql += hasWhere ? " AND " : " WHERE ";
sql += category + ">=TRUNC(" + DB.TO_DATE(new Timestamp(startDate.getTime())) + ", '" + unit + "') AND ";
sql += category + "<=TRUNC(" + DB.TO_DATE(new Timestamp(endDate.getTime())) + ", '" + unit + "') ";
}
if (sql.indexOf('@') >= 0) {
sql = Env.parseContext(getCtx(), 0, sql, false, true);
}
MRole role = MRole.getDefault(getCtx(), false);
sql = role.addAccessSQL(sql, null, true, false);
if (hasSeries)
sql += " GROUP BY " + series + ", " + category + " ORDER BY " + series + ", " + category;
else
sql += " GROUP BY " + category + " ORDER BY " + category;
log.log(Level.FINE, sql);
PreparedStatement pstmt = null;
ResultSet rs = null;
TimeSeries tseries = null;
Dataset dataset = parent.getDataset();
try
{
pstmt = DB.prepareStatement(sql, null);
rs = pstmt.executeQuery();
while(rs.next())
{
String key = rs.getString(2);
String seriesName = rs.getString(3);
if (seriesName == null)
seriesName = getName();
String queryWhere = "";
if ( hasWhere )
queryWhere += where + " AND ";
queryWhere += series + " = " + DB.TO_STRING(seriesName) + " AND " + category + " = " ;
if ( parent.isTimeSeries() && dataset instanceof TimeSeriesCollection )
{
if ( tseries == null || !tseries.getKey().equals(seriesName))
{
if (tseries != null)
((TimeSeriesCollection) dataset).addSeries(tseries);
tseries = new TimeSeries(seriesName);
}
Date date = rs.getDate(2);
RegularTimePeriod period = null;
if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Day))
period = new Day(date);
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Week))
period = new Week(date);
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Month))
period = new Month(date);
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Quarter))
period = new Quarter(date);
else if ( parent.getTimeUnit().equals(MChart.TIMEUNIT_Year))
period = new Year(date);
tseries.add(period, rs.getBigDecimal(1));
key = period.toString();
queryWhere += DB.TO_DATE(new Timestamp(date.getTime()));
}
else {
queryWhere += DB.TO_STRING(key);
}
MQuery query = new MQuery(getAD_Table_ID());
String keyCol = MTable.get(getCtx(), getAD_Table_ID()).getKeyColumns()[0];
String whereClause = keyCol + " IN (SELECT " + getKeyColumn() + " FROM "
+ getFromClause() + " WHERE " + queryWhere + " )";
query.addRestriction(whereClause.toString());
query.setRecordCount(1);
HashMap<String, MQuery> map = parent.getQueries();
if ( dataset instanceof DefaultPieDataset) {
((DefaultPieDataset) dataset).setValue(key, rs.getBigDecimal(1));
map.put(key, query);
}
else if ( dataset instanceof DefaultCategoryDataset ) {
((DefaultCategoryDataset) dataset).addValue(rs.getBigDecimal(1), seriesName, key);
map.put(seriesName + "__" + key, query);
}
else if (dataset instanceof TimeSeriesCollection )
{
map.put(seriesName + "__" + key, query);
}
}
}
catch (SQLException e)
{
throw new DBException(e, sql);
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
if (tseries != null)
((TimeSeriesCollection) dataset).addSeries(tseries);
}
private Date increment(Date lastDate, String timeUnit, int qty) {
if ( lastDate == null )
return null;
Calendar cal = Calendar.getInstance();
cal.setTime(lastDate);
if ( timeUnit.equals(MChart.TIMEUNIT_Day))
cal.add(Calendar.DAY_OF_YEAR, qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Week))
cal.add(Calendar.WEEK_OF_YEAR, qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Month))
cal.add(Calendar.MONTH, qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Quarter))
cal.add(Calendar.MONTH, 3*qty);
else if ( timeUnit.equals(MChart.TIMEUNIT_Year))
cal.add(Calendar.YEAR, qty);
return cal.getTime();
}
/** /**
* Convert date formatted as yyyy-MM to yyyy-QQ * Convert date formatted as yyyy-MM to yyyy-QQ

View File

@ -8,6 +8,7 @@ import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.VetoableChangeListener; import java.beans.VetoableChangeListener;
import org.adempiere.apps.graph.ChartBuilder;
import org.compiere.apps.AEnv; import org.compiere.apps.AEnv;
import org.compiere.model.GridField; import org.compiere.model.GridField;
import org.compiere.model.MChart; import org.compiere.model.MChart;
@ -34,6 +35,7 @@ public class VChart extends CPanel implements ChartMouseListener, VEditor {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
ChartPanel chartPanel; ChartPanel chartPanel;
MChart chartModel; MChart chartModel;
private ChartBuilder chartBuilder;
/** /**
* Constructor * Constructor
*/ */
@ -52,7 +54,8 @@ public class VChart extends CPanel implements ChartMouseListener, VEditor {
public void createChart() public void createChart()
{ {
JFreeChart chart = chartModel.createChart(); chartBuilder = new ChartBuilder(chartModel);
JFreeChart chart = chartBuilder.createChart();
if (chartPanel != null) if (chartPanel != null)
remove(chartPanel); remove(chartPanel);
@ -131,7 +134,7 @@ public class VChart extends CPanel implements ChartMouseListener, VEditor {
if ( key == null ) if ( key == null )
return; return;
MQuery query = chartModel.getQuery(seriesName == null ? key : seriesName+"__"+key); MQuery query = chartBuilder.getQuery(seriesName == null ? key : seriesName+"__"+key);
if (query != null) if (query != null)
AEnv.zoom(query); AEnv.zoom(query);

View File

@ -34,6 +34,7 @@ Export-Package: fi.jawsy.jawwa.zk.atmosphere,
org.adempiere.webui.apps, org.adempiere.webui.apps,
org.adempiere.webui.apps.form, org.adempiere.webui.apps.form,
org.adempiere.webui.apps.graph, org.adempiere.webui.apps.graph,
org.adempiere.webui.apps.graph.model,
org.adempiere.webui.apps.wf, org.adempiere.webui.apps.wf,
org.adempiere.webui.component, org.adempiere.webui.component,
org.adempiere.webui.component.test, org.adempiere.webui.component.test,
@ -85,4 +86,4 @@ Bundle-Activator: org.adempiere.webui.WebUIActivator
Eclipse-ExtensibleAPI: true Eclipse-ExtensibleAPI: true
Eclipse-RegisterBuddy: org.zkoss.zk.library Eclipse-RegisterBuddy: org.zkoss.zk.library
Web-ContextPath: webui Web-ContextPath: webui
Service-Component: OSGI-INF/reportviewerprovider.xml, OSGI-INF/defaultinfofactory.xml, OSGI-INF/defaulteditorfactory.xml, OSGI-INF/jrviewerprovider.xml, OSGI-INF/resourcefinder.xml, OSGI-INF/defaultpaymentformfactory.xml, OSGI-INF/processfactory.xml, OSGI-INF/defaultprintshippinglabel.xml, OSGI-INF/defaultcreatefromfactory.xml, OSGI-INF/defaultformfactory.xml, OSGI-INF/feedbackservice.xml, OSGI-INF/zulgadgetfactory.xml Service-Component: OSGI-INF/reportviewerprovider.xml, OSGI-INF/defaultinfofactory.xml, OSGI-INF/defaulteditorfactory.xml, OSGI-INF/jrviewerprovider.xml, OSGI-INF/resourcefinder.xml, OSGI-INF/defaultpaymentformfactory.xml, OSGI-INF/processfactory.xml, OSGI-INF/defaultprintshippinglabel.xml, OSGI-INF/defaultcreatefromfactory.xml, OSGI-INF/defaultformfactory.xml, OSGI-INF/feedbackservice.xml, OSGI-INF/zulgadgetfactory.xml, OSGI-INF/jfgchartrenderer.xml

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.adempiere.webui.apps.graph.jfreegraph.ChartRendererServiceImpl">
<implementation class="org.adempiere.webui.apps.graph.jfreegraph.ChartRendererServiceImpl"/>
<property name="service.ranking" type="Integer" value="0"/>
<service>
<provide interface="org.adempiere.webui.apps.graph.IChartRendererService"/>
</service>
</scr:component>

View File

@ -0,0 +1,54 @@
/******************************************************************************
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.apps.graph;
import org.adempiere.webui.apps.graph.model.ChartModel;
import org.adempiere.webui.apps.graph.model.GoalModel;
import org.adempiere.webui.apps.graph.model.IndicatorModel;
import org.zkoss.zk.ui.Component;
/**
* Chart renderer service. Note that implementation must be thread safe.
* @author hengsin
*
*/
public interface IChartRendererService {
/**
* render indicator chart for PA_Goal
* @param parent
* @param chartWidth
* @param chartHeight
* @param model
*/
public void renderPerformanceIndicator(Component parent, int chartWidth, int chartHeight, IndicatorModel model);
/**
* render chart for PA_Goal
* @param parent
* @param chartWidth
* @param chartHeight
* @param goalModel
*/
public void renderPerformanceGraph(Component parent, int chartWidth, int chartHeight, GoalModel goalModel);
/**
* render chart for AD_Chart
* @param parent
* @param width
* @param height
* @param chartModel
*/
public void renderChart(Component parent, int width, int height, ChartModel chartModel);
}

View File

@ -14,15 +14,14 @@
package org.adempiere.webui.apps.graph; package org.adempiere.webui.apps.graph;
import java.awt.Point; import java.awt.Point;
import java.awt.image.BufferedImage;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Collections;
import java.util.logging.Level;
import org.adempiere.apps.graph.GraphBuilder;
import org.adempiere.apps.graph.GraphColumn; import org.adempiere.apps.graph.GraphColumn;
import org.adempiere.base.Service;
import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.apps.graph.model.GoalModel;
import org.adempiere.webui.editor.WTableDirEditor; import org.adempiere.webui.editor.WTableDirEditor;
import org.adempiere.webui.event.ValueChangeEvent; import org.adempiere.webui.event.ValueChangeEvent;
import org.adempiere.webui.event.ValueChangeListener; import org.adempiere.webui.event.ValueChangeListener;
@ -30,19 +29,10 @@ import org.compiere.model.MGoal;
import org.compiere.model.MLookup; import org.compiere.model.MLookup;
import org.compiere.model.MLookupFactory; import org.compiere.model.MLookupFactory;
import org.compiere.model.MLookupInfo; import org.compiere.model.MLookupInfo;
import org.compiere.model.MQuery; import org.compiere.model.MMeasure;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.encoders.EncoderUtil;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.chart.entity.CategoryItemEntity;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.PieSectionEntity;
import org.zkoss.image.AImage;
import org.zkoss.zhtml.A; import org.zkoss.zhtml.A;
import org.zkoss.zhtml.Br; import org.zkoss.zhtml.Br;
import org.zkoss.zhtml.Table; import org.zkoss.zhtml.Table;
@ -54,13 +44,10 @@ import org.zkoss.zk.ui.IdSpace;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.MouseEvent;
import org.zkoss.zul.Borderlayout; import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Center; import org.zkoss.zul.Center;
import org.zkoss.zul.East; import org.zkoss.zul.East;
import org.zkoss.zul.Area;
import org.zkoss.zul.Div; import org.zkoss.zul.Div;
import org.zkoss.zul.Imagemap;
import org.zkoss.zul.Panel; import org.zkoss.zul.Panel;
import org.zkoss.zul.Panelchildren; import org.zkoss.zul.Panelchildren;
import org.zkoss.zul.Toolbar; import org.zkoss.zul.Toolbar;
@ -100,18 +87,21 @@ public class WGraph extends Div implements IdSpace {
*/ */
ArrayList<GraphColumn> list = new ArrayList<GraphColumn>(); ArrayList<GraphColumn> list = new ArrayList<GraphColumn>();
private GraphBuilder builder;
private boolean m_chartSelection; private boolean m_chartSelection;
private int zoomFactor = 0; private int zoomFactor = 0;
private MGoal m_goal;
private String m_xAxisLabel;
private String m_yAxisLabel;
/** /**
* Constructor * Constructor
*/ */
public WGraph() { public WGraph() {
super(); super();
builder = new GraphBuilder();
panel = new Panel(); panel = new Panel();
} // BarGraph } // BarGraph
@ -154,9 +144,9 @@ public class WGraph extends Div implements IdSpace {
*/ */
public void setGoal(MGoal goal) public void setGoal(MGoal goal)
{ {
builder.setMGoal(goal); m_goal = goal;
builder.setYAxisLabel(goal.getName()); m_yAxisLabel = goal.getName();
builder.setXAxisLabel(goal.getXAxisText()); m_xAxisLabel = goal.getXAxisText();
} }
/** /**
@ -194,10 +184,7 @@ public class WGraph extends Div implements IdSpace {
} }
if (m_renderChart) { if (m_renderChart) {
JFreeChart chart = builder.createChart(builder.getMGoal() renderChart((String)null);
.getChartType());
render(chart);
} }
if (m_renderTable) { if (m_renderTable) {
if (m_renderChart) { if (m_renderChart) {
@ -218,8 +205,16 @@ public class WGraph extends Div implements IdSpace {
} }
private void loadData() { private void loadData() {
list = builder.loadData(); // Calculated
MMeasure measure = m_goal.getMeasure();
if (measure == null)
{
log.warning("No Measure for " + m_goal);
return;
}
list = measure.getGraphColumnList(m_goal);
if (m_renderChart && m_chartSelection) { if (m_renderChart && m_chartSelection) {
Toolbar toolbar = new Toolbar(); Toolbar toolbar = new Toolbar();
panel.appendChild(toolbar); panel.appendChild(toolbar);
@ -239,95 +234,32 @@ public class WGraph extends Div implements IdSpace {
Object value = evt.getNewValue(); Object value = evt.getNewValue();
if (value == null || value.toString().trim().length() == 0) if (value == null || value.toString().trim().length() == 0)
return; return;
JFreeChart chart = null; renderChart(value.toString());
chart = builder.createChart(value.toString());
if (chart != null)
render(chart);
} }
}); });
} }
} // loadData } // loadData
private void render(JFreeChart chart) { private void renderChart(String type) {
ChartRenderingInfo info = new ChartRenderingInfo();
int width = 560; int width = 560;
int height = 400; int height = 400;
if (zoomFactor > 0) { if (panel.getPanelchildren() != null) {
width = width * zoomFactor / 100; panel.getPanelchildren().getChildren().clear();
height = height * zoomFactor / 100; } else {
} Panelchildren pc = new Panelchildren();
if (m_hideTitle) { panel.appendChild(pc);
chart.setTitle("");
}
BufferedImage bi = chart.createBufferedImage(width, height,
BufferedImage.TRANSLUCENT, info);
try {
byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
AImage image = new AImage("", bytes);
Imagemap myImage = new Imagemap();
myImage.setContent(image);
if (panel.getPanelchildren() != null) {
panel.getPanelchildren().getChildren().clear();
panel.getPanelchildren().appendChild(myImage);
} else {
Panelchildren pc = new Panelchildren();
panel.appendChild(pc);
pc.appendChild(myImage);
}
int count = 0;
for (Iterator<?> it = info.getEntityCollection().getEntities()
.iterator(); it.hasNext();) {
ChartEntity entity = (ChartEntity) it.next();
String key = null;
if (entity instanceof CategoryItemEntity) {
Comparable<?> colKey = ((CategoryItemEntity) entity)
.getColumnKey();
if (colKey != null) {
key = colKey.toString();
}
} else if (entity instanceof PieSectionEntity) {
Comparable<?> sectionKey = ((PieSectionEntity) entity)
.getSectionKey();
if (sectionKey != null) {
key = sectionKey.toString();
}
}
if (key == null) {
continue;
}
Area area = new Area();
myImage.appendChild(area);
area.setCoords(entity.getShapeCoords());
area.setShape(entity.getShapeType());
area.setTooltiptext(entity.getToolTipText());
area.setId(count+"_WG_" + key);
count++;
}
myImage.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
public void onEvent(Event event) throws Exception {
MouseEvent me = (MouseEvent) event;
String areaId = me.getArea();
if (areaId != null) {
for (int i = 0; i < list.size(); i++) {
String s = "_WG_" + list.get(i).getLabel();
if (areaId.endsWith(s)) {
chartMouseClicked(i);
return;
}
}
}
}
});
} catch (Exception e) {
log.log(Level.SEVERE, "", e);
} }
IChartRendererService renderer = Service.locator().locate(IChartRendererService.class).getService();
GoalModel goalModel = new GoalModel();
goalModel.goal = m_goal;
goalModel.chartType = type != null ? type : m_goal.getChartType();
goalModel.columnList = Collections.unmodifiableList(list);
goalModel.showTitle = !m_hideTitle;
goalModel.xAxisLabel = m_xAxisLabel;
goalModel.yAxisLabel = m_yAxisLabel;
goalModel.zoomFactor = zoomFactor;
renderer.renderPerformanceGraph(panel.getPanelchildren(), width, height, goalModel);
} }
/** /**
@ -343,7 +275,7 @@ public class WGraph extends Div implements IdSpace {
* @return Returns the x_AxisLabel. * @return Returns the x_AxisLabel.
*/ */
public String getX_AxisLabel() { public String getX_AxisLabel() {
return builder.getXAxisLabel(); return m_xAxisLabel;
} // getX_AxisLabel } // getX_AxisLabel
/** /**
@ -351,14 +283,14 @@ public class WGraph extends Div implements IdSpace {
* The x_AxisLabel to set. * The x_AxisLabel to set.
*/ */
public void setX_AxisLabel(String axisLabel) { public void setX_AxisLabel(String axisLabel) {
builder.setXAxisLabel(axisLabel); m_xAxisLabel = axisLabel;
} // setX_AxisLabel } // setX_AxisLabel
/** /**
* @return Returns the y_AxisLabel. * @return Returns the y_AxisLabel.
*/ */
public String getY_AxisLabel() { public String getY_AxisLabel() {
return builder.getYAxisLabel(); return m_yAxisLabel;
} // getY_AxisLabel } // getY_AxisLabel
/** /**
@ -366,7 +298,7 @@ public class WGraph extends Div implements IdSpace {
* The y_AxisLabel to set. * The y_AxisLabel to set.
*/ */
public void setY_AxisLabel(String axisLabel) { public void setY_AxisLabel(String axisLabel) {
builder.setYAxisLabel(axisLabel); m_yAxisLabel = axisLabel;
} // setY_AxisLabel } // setY_AxisLabel
/** /**
@ -431,27 +363,6 @@ public class WGraph extends Div implements IdSpace {
m_renderChart = mRenderChart; m_renderChart = mRenderChart;
} }
/**************************************************************************
* Paint Component
*
* @param g
* graphics
*/
public void chartMouseClicked(int index) {
GraphColumn bgc = list.get(index);
if (null == bgc)
return;
MQuery query = bgc.getMQuery(builder.getMGoal());
if (query != null)
AEnv.zoom(query);
else
log.warning("Nothing to zoom to - " + bgc);
}
public void chartMouseMoved(ChartMouseEvent event) {
}
/** /**
* *
* @return GraphColumn[] * @return GraphColumn[]
@ -484,7 +395,7 @@ public class WGraph extends Div implements IdSpace {
td.setDynamicProperty("colspan", "2"); td.setDynamicProperty("colspan", "2");
td.setSclass("pa-tdcontent"); td.setSclass("pa-tdcontent");
tr.appendChild(td); tr.appendChild(td);
text = new Text(builder.getMGoal().getMeasureTarget().setScale(2, text = new Text(m_goal.getMeasureTarget().setScale(2,
BigDecimal.ROUND_HALF_UP).toPlainString()); BigDecimal.ROUND_HALF_UP).toPlainString());
td.appendChild(text); td.appendChild(text);
@ -499,7 +410,7 @@ public class WGraph extends Div implements IdSpace {
td.setDynamicProperty("colspan", "2"); td.setDynamicProperty("colspan", "2");
td.setSclass("pa-tdcontent"); td.setSclass("pa-tdcontent");
tr.appendChild(td); tr.appendChild(td);
text = new Text(builder.getMGoal().getMeasureActual().setScale(2, text = new Text(m_goal.getMeasureActual().setScale(2,
BigDecimal.ROUND_HALF_UP).toPlainString()); BigDecimal.ROUND_HALF_UP).toPlainString());
td.appendChild(text); td.appendChild(text);
@ -512,7 +423,7 @@ public class WGraph extends Div implements IdSpace {
td.setDynamicProperty("rowspan", bList.length); td.setDynamicProperty("rowspan", bList.length);
td.setSclass("pa-label"); td.setSclass("pa-label");
td.setDynamicProperty("valign", "top"); td.setDynamicProperty("valign", "top");
text = new Text(builder.getMGoal().getXAxisText()); text = new Text(m_goal.getXAxisText());
td.appendChild(text); td.appendChild(text);
for (int k = 0; k < bList.length; k++) { for (int k = 0; k < bList.length; k++) {
@ -531,7 +442,7 @@ public class WGraph extends Div implements IdSpace {
td.setSclass("pa-tdvalue"); td.setSclass("pa-tdvalue");
tr.appendChild(td); tr.appendChild(td);
BigDecimal value = BigDecimal.valueOf(bgc.getValue()); BigDecimal value = BigDecimal.valueOf(bgc.getValue());
if (bgc.getMQuery(builder.getMGoal()) != null) { if (bgc.getMQuery(m_goal) != null) {
A a = new A(); A a = new A();
a.setSclass("pa-hrefNode"); a.setSclass("pa-hrefNode");
td.appendChild(a); td.appendChild(a);
@ -545,8 +456,7 @@ public class WGraph extends Div implements IdSpace {
int index = Integer.parseInt(String.valueOf(ss)); int index = Integer.parseInt(String.valueOf(ss));
GraphColumn[] colList = getGraphColumnList(); GraphColumn[] colList = getGraphColumnList();
if ((index >= 0) && (index < colList.length)) if ((index >= 0) && (index < colList.length))
AEnv.zoom(colList[index].getMQuery(builder AEnv.zoom(colList[index].getMQuery(m_goal));
.getMGoal()));
} }
} }
@ -564,11 +474,11 @@ public class WGraph extends Div implements IdSpace {
td = new Td(); td = new Td();
td.setDynamicProperty("colspan", "3"); td.setDynamicProperty("colspan", "3");
tr.appendChild(td); tr.appendChild(td);
text = new Text(builder.getMGoal().getDescription()); text = new Text(m_goal.getDescription());
td.appendChild(text); td.appendChild(text);
Br br = new Br(); Br br = new Br();
td.appendChild(br); td.appendChild(br);
text = new Text(stripHtml(builder.getMGoal().getColorSchema() text = new Text(stripHtml(m_goal.getColorSchema()
.getDescription(), true)); .getDescription(), true));
td.appendChild(text); td.appendChild(text);
} }

View File

@ -66,8 +66,6 @@ public class WPAPanel extends Panel implements EventListener<Event>
setSclass("performance-panel"); setSclass("performance-panel");
Grid grid = new Grid(); Grid grid = new Grid();
appendChild(grid); appendChild(grid);
int gh = options != null && options.chartHeight > 0 ? options.chartHeight+60 : 180;
grid.setHeight((m_goals.length + (m_goals.length % 2)) * gh / 2 + "px");
grid.makeNoStrip(); grid.makeNoStrip();
Rows rows = new Rows(); Rows rows = new Rows();

View File

@ -13,36 +13,22 @@
*****************************************************************************/ *****************************************************************************/
package org.adempiere.webui.apps.graph; package org.adempiere.webui.apps.graph;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Font;
import java.awt.LinearGradientPaint;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Map; import java.util.Map;
import org.adempiere.base.Service;
import org.adempiere.webui.apps.graph.model.IndicatorModel;
import org.adempiere.webui.component.Panel; import org.adempiere.webui.component.Panel;
import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.theme.ThemeManager;
import org.compiere.model.MColorSchema;
import org.compiere.model.MGoal; import org.compiere.model.MGoal;
import org.compiere.util.DisplayType; import org.compiere.util.DisplayType;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg; import org.compiere.util.Msg;
import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.encoders.EncoderUtil;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.data.Range;
import org.jfree.data.general.DefaultValueDataset;
import org.zkoss.image.AImage;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Image;
import org.zkoss.zul.Menuitem; import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Menupopup; import org.zkoss.zul.Menupopup;
@ -135,11 +121,24 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
return m_goal; return m_goal;
} // getGoal } // getGoal
private JFreeChart createChart() /**
* Init Graph Display
* Kinamo (pelgrim)
*/
private void init()
{ {
JFreeChart chart = null; IChartRendererService renderer = Service.locator().locate(IChartRendererService.class).getService();
IndicatorModel model = new IndicatorModel();
// Set Text model.goalModel = m_goal;
model.chartBackground = chartBackground;
model.dialBackground = dialBackground;
model.needleColor = needleColor;
model.tickColor = tickColor;
renderer.renderPerformanceIndicator(this, chartWidth, chartHeight, model);
this.getFirstChild().addEventListener(Events.ON_CLICK, this);
// Set Text
StringBuilder text = new StringBuilder(m_goal.getName()); StringBuilder text = new StringBuilder(m_goal.getName());
if (m_goal.isTarget()) if (m_goal.isTarget())
text.append(": ").append(m_goal.getPercent()).append("%"); text.append(": ").append(m_goal.getPercent()).append("%");
@ -157,96 +156,17 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
text.append(" ").append(Msg.getMsg(Env.getCtx(), "of")).append(" ") text.append(" ").append(Msg.getMsg(Env.getCtx(), "of")).append(" ")
.append(s_format.format(m_goal.getMeasureTarget())); .append(s_format.format(m_goal.getMeasureTarget()));
setTooltiptext(text.toString()); setTooltiptext(text.toString());
//
DefaultValueDataset data = new DefaultValueDataset((float)m_goal.getPercent()); invalidate();
MeterPlot plot = new MeterPlot(data);
MColorSchema colorSchema = m_goal.getColorSchema();
int rangeLo = 0; int rangeHi=0;
Point2D start = new Point2D.Float(0, 0);
Point2D end = new Point2D.Float(50, 50);
float[] dist = {0.0f, 0.2f, 0.45f, 0.75f, 1.0f};
for (int i=1; i<=4; i++){
switch (i) {
case 1: rangeHi = colorSchema.getMark1Percent(); break;
case 2: rangeHi = colorSchema.getMark2Percent(); break;
case 3: rangeHi = colorSchema.getMark3Percent(); break;
case 4: rangeHi = colorSchema.getMark4Percent(); break;
}
if (rangeHi==9999)
rangeHi = (int) Math.floor(rangeLo*1.5);
if (rangeLo < rangeHi) {
Color[] colors = {colorSchema.getColor(rangeHi).brighter().brighter(),
colorSchema.getColor(rangeHi).brighter(), colorSchema.getColor(rangeHi),
colorSchema.getColor(rangeHi).darker(), colorSchema.getColor(rangeHi).darker().darker()};
LinearGradientPaint p =
new LinearGradientPaint(start, end, dist, colors);
plot.addInterval(new MeterInterval("Normal", //label
new Range(rangeLo, rangeHi), //range
p,
new BasicStroke(7.0f),
dialBackground
));
rangeLo = rangeHi;
}
}
plot.setRange(new Range(0,rangeLo));
plot.setDialBackgroundPaint(dialBackground);
plot.setUnits("");
plot.setDialShape(DialShape.CHORD);
plot.setNeedlePaint(needleColor);
plot.setTickSize(2000);
plot.setTickLabelFont(new Font("SansSerif", Font.BOLD, 8));
plot.setValueFont(new Font("SansSerif", Font.BOLD, 8));
plot.setNoDataMessageFont(new Font("SansSerif", Font.BOLD, 8));
plot.setTickLabelPaint(tickColor);
plot.setValuePaint(new Color(0.0f, 0.0f, 0.0f, 0.0f));
plot.setTickPaint(tickColor);
//
chart = new JFreeChart( "", new Font("SansSerif", Font.BOLD, 9), plot,false);
return chart;
} }
/**
* Init Graph Display
* Kinamo (pelgrim)
*/
private void init()
{
JFreeChart chart = createChart();
chart.setBackgroundPaint(chartBackground);
chart.setAntiAlias(true);
BufferedImage bi = chart.createBufferedImage(chartWidth, chartHeight, BufferedImage.TRANSLUCENT , null);
try {
byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
AImage image = new AImage("", bytes);
Image myImage = new Image();
myImage.setContent(image);
appendChild(myImage);
}
catch (Exception e)
{
e.printStackTrace();
}
invalidate();
}
/**
* Update Display Data
*/
protected void updateDisplay()
{
chartPanel.setChart(createChart());
invalidate();
} // updateData
public void onEvent(Event event) throws Exception public void onEvent(Event event) throws Exception
{ {
if (event.getTarget() == this.getFirstChild())
{
event.stopPropagation();
Events.sendEvent(Events.ON_CLICK, this, event.getData());
}
} }
public String getTitle() public String getTitle()

View File

@ -1,9 +1,10 @@
package org.adempiere.webui.util; package org.adempiere.webui.apps.graph.jfreegraph;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.Iterator; import java.util.Iterator;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.apps.graph.ChartBuilder;
import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.apps.AEnv;
import org.compiere.model.MChart; import org.compiere.model.MChart;
import org.compiere.model.MQuery; import org.compiere.model.MQuery;
@ -33,12 +34,14 @@ import org.zkoss.zul.Imagemap;
* @author hengsin * @author hengsin
* *
*/ */
public class ChartRenderer { /* package */ class ChartRenderer {
private static final CLogger log = CLogger.getCLogger(ChartRenderer.class); private static final CLogger log = CLogger.getCLogger(ChartRenderer.class);
private MChart chartModel; private MChart chartModel;
private ChartBuilder chartBuilder;
/** /**
* @param chartModel * @param chartModel
*/ */
@ -52,7 +55,9 @@ public class ChartRenderer {
* @param width * @param width
*/ */
public void render(Component parent, int width, int height) { public void render(Component parent, int width, int height) {
JFreeChart chart = chartModel.createChart(); chartBuilder = new ChartBuilder(chartModel);
JFreeChart chart = chartBuilder.createChart();
chart.getPlot().setForegroundAlpha(0.6f);
ChartRenderingInfo info = new ChartRenderingInfo(); ChartRenderingInfo info = new ChartRenderingInfo();
BufferedImage bi = chart.createBufferedImage(width, height, BufferedImage bi = chart.createBufferedImage(width, height,
@ -136,7 +141,7 @@ public class ChartRenderer {
} }
public void chartMouseClicked(String key, String category) { public void chartMouseClicked(String key, String category) {
MQuery query = chartModel.getQuery("null".equals(category) ? key : category + "__" + key); MQuery query = chartBuilder.getQuery("null".equals(category) ? key : category + "__" + key);
if (query != null) if (query != null)
AEnv.zoom(query); AEnv.zoom(query);
} }

View File

@ -0,0 +1,173 @@
/******************************************************************************
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.apps.graph.jfreegraph;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import org.adempiere.apps.graph.GraphBuilder;
import org.adempiere.apps.graph.GraphColumn;
import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.apps.graph.IChartRendererService;
import org.adempiere.webui.apps.graph.model.ChartModel;
import org.adempiere.webui.apps.graph.model.GoalModel;
import org.adempiere.webui.apps.graph.model.IndicatorModel;
import org.compiere.model.MGoal;
import org.compiere.model.MQuery;
import org.compiere.util.CLogger;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.encoders.EncoderUtil;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.chart.entity.CategoryItemEntity;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.PieSectionEntity;
import org.zkoss.image.AImage;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.MouseEvent;
import org.zkoss.zul.Area;
import org.zkoss.zul.Image;
import org.zkoss.zul.Imagemap;
/**
*
* @author hengsin
*
*/
public class ChartRendererServiceImpl implements IChartRendererService {
private final static CLogger log = CLogger.getCLogger(ChartRendererServiceImpl.class);
@Override
public void renderPerformanceIndicator(Component parent, int chartWidth, int chartHeight, IndicatorModel model) {
PerformanceGraphBuilder builder = new PerformanceGraphBuilder();
JFreeChart chart = builder.createIndicatorChart(model);
chart.setBackgroundPaint(model.chartBackground);
chart.setAntiAlias(true);
BufferedImage bi = chart.createBufferedImage(chartWidth, chartHeight, BufferedImage.TRANSLUCENT , null);
try {
byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
AImage image = new AImage("", bytes);
Image myImage = new Image();
myImage.setContent(image);
parent.appendChild(myImage);
}
catch (Exception e)
{
e.printStackTrace();
}
}
@Override
public void renderPerformanceGraph(Component parent, int chartWidth, int chartHeight, final GoalModel goalModel) {
GraphBuilder builder = new GraphBuilder();
builder.setMGoal(goalModel.goal);
builder.setXAxisLabel(goalModel.xAxisLabel);
builder.setYAxisLabel(goalModel.yAxisLabel);
builder.loadDataSet(goalModel.columnList);
JFreeChart chart = builder.createChart(goalModel.chartType);
ChartRenderingInfo info = new ChartRenderingInfo();
chart.getPlot().setForegroundAlpha(0.6f);
if (goalModel.zoomFactor > 0) {
chartWidth = chartWidth * goalModel.zoomFactor / 100;
chartHeight = chartHeight * goalModel.zoomFactor / 100;
}
if (!goalModel.showTitle) {
chart.setTitle("");
}
BufferedImage bi = chart.createBufferedImage(chartWidth, chartHeight,
BufferedImage.TRANSLUCENT, info);
try {
byte[] bytes = EncoderUtil.encode(bi, ImageFormat.PNG, true);
AImage image = new AImage("", bytes);
Imagemap myImage = new Imagemap();
myImage.setContent(image);
parent.appendChild(myImage);
int count = 0;
for (Iterator<?> it = info.getEntityCollection().getEntities()
.iterator(); it.hasNext();) {
ChartEntity entity = (ChartEntity) it.next();
String key = null;
if (entity instanceof CategoryItemEntity) {
Comparable<?> colKey = ((CategoryItemEntity) entity)
.getColumnKey();
if (colKey != null) {
key = colKey.toString();
}
} else if (entity instanceof PieSectionEntity) {
Comparable<?> sectionKey = ((PieSectionEntity) entity)
.getSectionKey();
if (sectionKey != null) {
key = sectionKey.toString();
}
}
if (key == null) {
continue;
}
Area area = new Area();
myImage.appendChild(area);
area.setCoords(entity.getShapeCoords());
area.setShape(entity.getShapeType());
area.setTooltiptext(entity.getToolTipText());
area.setId(count+"_WG_" + key);
count++;
}
myImage.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
public void onEvent(Event event) throws Exception {
MouseEvent me = (MouseEvent) event;
String areaId = me.getArea();
if (areaId != null) {
List<GraphColumn> list = goalModel.columnList;
for (int i = 0; i < list.size(); i++) {
String s = "_WG_" + list.get(i).getLabel();
if (areaId.endsWith(s)) {
chartMouseClicked(goalModel.goal, list.get(i));
return;
}
}
}
}
});
} catch (Exception e) {
log.log(Level.SEVERE, "", e);
}
}
private void chartMouseClicked(MGoal goal, GraphColumn bgc) {
if (null == bgc)
return;
MQuery query = bgc.getMQuery(goal);
if (query != null)
AEnv.zoom(query);
else
log.warning("Nothing to zoom to - " + bgc);
}
@Override
public void renderChart(Component parent, int width, int height,
ChartModel chartModel) {
ChartRenderer renderer = new ChartRenderer(chartModel.chart);
renderer.render(parent, width, height);
}
}

View File

@ -0,0 +1,91 @@
/******************************************************************************
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.apps.graph.jfreegraph;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.LinearGradientPaint;
import java.awt.geom.Point2D;
import org.adempiere.webui.apps.graph.model.IndicatorModel;
import org.compiere.model.MColorSchema;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.data.Range;
import org.jfree.data.general.DefaultValueDataset;
/**
*
* @author hengsin
*
*/
public class PerformanceGraphBuilder {
public JFreeChart createIndicatorChart(IndicatorModel model)
{
JFreeChart chart = null;
DefaultValueDataset data = new DefaultValueDataset((float)model.goalModel.getPercent());
MeterPlot plot = new MeterPlot(data);
MColorSchema colorSchema = model.goalModel.getColorSchema();
int rangeLo = 0; int rangeHi=0;
Point2D start = new Point2D.Float(0, 0);
Point2D end = new Point2D.Float(50, 50);
float[] dist = {0.0f, 0.2f, 0.45f, 0.75f, 1.0f};
for (int i=1; i<=4; i++){
switch (i) {
case 1: rangeHi = colorSchema.getMark1Percent(); break;
case 2: rangeHi = colorSchema.getMark2Percent(); break;
case 3: rangeHi = colorSchema.getMark3Percent(); break;
case 4: rangeHi = colorSchema.getMark4Percent(); break;
}
if (rangeHi==9999)
rangeHi = (int) Math.floor(rangeLo*1.5);
if (rangeLo < rangeHi) {
Color[] colors = {colorSchema.getColor(rangeHi).brighter().brighter(),
colorSchema.getColor(rangeHi).brighter(), colorSchema.getColor(rangeHi),
colorSchema.getColor(rangeHi).darker(), colorSchema.getColor(rangeHi).darker().darker()};
LinearGradientPaint p =
new LinearGradientPaint(start, end, dist, colors);
plot.addInterval(new MeterInterval("Normal", //label
new Range(rangeLo, rangeHi), //range
p,
new BasicStroke(7.0f),
model.dialBackground
));
rangeLo = rangeHi;
}
}
plot.setRange(new Range(0,rangeLo));
plot.setDialBackgroundPaint(model.dialBackground);
plot.setUnits("");
plot.setDialShape(DialShape.CHORD);
plot.setNeedlePaint(model.needleColor);
plot.setTickSize(2000);
plot.setTickLabelFont(new Font("SansSerif", Font.BOLD, 8));
plot.setValueFont(new Font("SansSerif", Font.BOLD, 8));
plot.setNoDataMessageFont(new Font("SansSerif", Font.BOLD, 8));
plot.setTickLabelPaint(model.tickColor);
plot.setValuePaint(new Color(0.0f, 0.0f, 0.0f, 0.0f));
plot.setTickPaint(model.tickColor);
//
chart = new JFreeChart( "", new Font("SansSerif", Font.BOLD, 9), plot,false);
return chart;
}
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.apps.graph.model;
import org.compiere.model.MChart;
/**
*
* @author hengsin
*
*/
public class ChartModel {
public MChart chart;
}

View File

@ -0,0 +1,34 @@
/******************************************************************************
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.apps.graph.model;
import java.util.List;
import org.adempiere.apps.graph.GraphColumn;
import org.compiere.model.MGoal;
/**
*
* @author hengsin
*
*/
public class GoalModel {
public MGoal goal;
public String chartType;
public boolean showTitle;
public List<GraphColumn> columnList;
public String xAxisLabel;
public String yAxisLabel;
public int zoomFactor;
}

View File

@ -0,0 +1,31 @@
/******************************************************************************
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.apps.graph.model;
import java.awt.Color;
import org.compiere.model.MGoal;
/**
*
* @author hengsin
*
*/
public class IndicatorModel {
public MGoal goalModel;
public Color chartBackground;
public Color dialBackground;
public Color needleColor;
public Color tickColor;
}

View File

@ -86,6 +86,7 @@ public class DPPerformance extends DashboardPanel {
script = script + "grid.parent().height(grid.css('height'));}, 500);"; script = script + "grid.parent().height(grid.css('height'));}, 500);";
if (Executions.getCurrent() != null) if (Executions.getCurrent() != null)
Clients.response(new AuScript(script)); Clients.response(new AuScript(script));
this.getFirstChild().invalidate();
} }
} }
} }

View File

@ -29,8 +29,10 @@ import java.util.logging.Level;
import org.adempiere.base.Service; import org.adempiere.base.Service;
import org.adempiere.exceptions.AdempiereException; import org.adempiere.exceptions.AdempiereException;
import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.apps.graph.IChartRendererService;
import org.adempiere.webui.apps.graph.WGraph; import org.adempiere.webui.apps.graph.WGraph;
import org.adempiere.webui.apps.graph.WPerformanceDetail; import org.adempiere.webui.apps.graph.WPerformanceDetail;
import org.adempiere.webui.apps.graph.model.ChartModel;
import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.component.ToolBarButton;
import org.adempiere.webui.dashboard.DashboardPanel; import org.adempiere.webui.dashboard.DashboardPanel;
import org.adempiere.webui.dashboard.DashboardRunnable; import org.adempiere.webui.dashboard.DashboardRunnable;
@ -38,7 +40,6 @@ import org.adempiere.webui.factory.IDashboardGadgetFactory;
import org.adempiere.webui.report.HTMLExtension; import org.adempiere.webui.report.HTMLExtension;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.ChartRenderer;
import org.adempiere.webui.window.ZkReportViewerProvider; import org.adempiere.webui.window.ZkReportViewerProvider;
import org.compiere.model.I_AD_Menu; import org.compiere.model.I_AD_Menu;
import org.compiere.model.MChart; import org.compiere.model.MChart;
@ -382,7 +383,6 @@ public class DashboardController implements EventListener<Event> {
chartPanel.addEventListener(Events.ON_AFTER_SIZE, new EventListener<AfterSizeEvent>() { chartPanel.addEventListener(Events.ON_AFTER_SIZE, new EventListener<AfterSizeEvent>() {
@Override @Override
public void onEvent(AfterSizeEvent event) throws Exception { public void onEvent(AfterSizeEvent event) throws Exception {
ChartRenderer renderer = new ChartRenderer(chartModel);
int width = event.getWidth()*90/100; int width = event.getWidth()*90/100;
int height = event.getHeight(); int height = event.getHeight();
//set normal height //set normal height
@ -391,7 +391,10 @@ public class DashboardController implements EventListener<Event> {
chartPanel.setHeight(height+"px"); chartPanel.setHeight(height+"px");
} }
chartPanel.getChildren().clear(); chartPanel.getChildren().clear();
renderer.render(chartPanel, width, height); ChartModel model = new ChartModel();
model.chart = chartModel;
IChartRendererService renderer = Service.locator().locate(IChartRendererService.class).getService();
renderer.renderChart(chartPanel, width, height, model);
} }
}); });
} }

View File

@ -14,7 +14,9 @@
package org.adempiere.webui.editor; package org.adempiere.webui.editor;
import org.adempiere.webui.util.ChartRenderer; import org.adempiere.base.Service;
import org.adempiere.webui.apps.graph.IChartRendererService;
import org.adempiere.webui.apps.graph.model.ChartModel;
import org.compiere.model.GridField; import org.compiere.model.GridField;
import org.compiere.model.MChart; import org.compiere.model.MChart;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
@ -50,7 +52,6 @@ public class WChartEditor extends WEditor
} }
private void createChart() { private void createChart() {
ChartRenderer renderer = new ChartRenderer(chartModel);
Panel panel = getComponent(); Panel panel = getComponent();
if (panel.getPanelchildren() != null) { if (panel.getPanelchildren() != null) {
panel.getPanelchildren().getChildren().clear(); panel.getPanelchildren().getChildren().clear();
@ -59,7 +60,10 @@ public class WChartEditor extends WEditor
panel.appendChild(pc); panel.appendChild(pc);
pc.setSclass("chart-field"); pc.setSclass("chart-field");
} }
renderer.render(panel.getPanelchildren(), 400, chartModel.getWinHeight()); ChartModel model = new ChartModel();
model.chart = chartModel;
IChartRendererService renderer = Service.locator().locate(IChartRendererService.class).getService();
renderer.renderChart(panel.getPanelchildren(), 400, chartModel.getWinHeight(), model);
} }
@Override @Override

View File

@ -33,7 +33,8 @@ bin.includes = META-INF/,\
OSGI-INF/feedbackservice.xml,\ OSGI-INF/feedbackservice.xml,\
sessiontimeout.zul,\ sessiontimeout.zul,\
*.jsp,\ *.jsp,\
labelapplet.jar labelapplet.jar,\
OSGI-INF/jfgchartrenderer.xml
src.includes = WEB-INF/classes/,\ src.includes = WEB-INF/classes/,\
WEB-INF/tld/,\ WEB-INF/tld/,\
WEB-INF/web.xml,\ WEB-INF/web.xml,\

View File

@ -1660,15 +1660,16 @@ table.z-vbox > tbody > tr > td > table {
.performance-indicator { .performance-indicator {
margin: auto; margin: auto;
position: relative; position: relative;
width: 120px !important;
} }
.performance-indicator img { .performance-indicator img {
height: 120px; height: 120px;
width: 120px; width: 120px;
display: block;
margin: auto;
} }
.window-view-pi .performance-indicator { .window-view-pi .performance-indicator img {
width: 180px !important; width: 180px !important;
} }