From a7db58fb5b97103326395b30282fcc13522d8dfc Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Fri, 29 Nov 2013 18:33:03 +0800 Subject: [PATCH] IDEMPIERE-1583 Zk: Pluggable Chart Renderer Service. --- .../adempiere/apps/graph/ChartBuilder.java | 642 ++++++++++++++++++ .../adempiere/apps/graph/GraphBuilder.java | 7 +- .../src/org/compiere/model/MChart.java | 387 +---------- .../org/compiere/model/MChartDatasource.java | 218 ------ .../src/org/compiere/grid/ed/VChart.java | 7 +- org.adempiere.ui.zk/META-INF/MANIFEST.MF | 3 +- .../OSGI-INF/jfgchartrenderer.xml | 8 + .../apps/graph/IChartRendererService.java | 54 ++ .../adempiere/webui/apps/graph/WGraph.java | 192 ++---- .../adempiere/webui/apps/graph/WPAPanel.java | 2 - .../apps/graph/WPerformanceIndicator.java | 132 +--- .../graph/jfreegraph}/ChartRenderer.java | 13 +- .../jfreegraph/ChartRendererServiceImpl.java | 173 +++++ .../jfreegraph/PerformanceGraphBuilder.java | 91 +++ .../webui/apps/graph/model/ChartModel.java | 25 + .../webui/apps/graph/model/GoalModel.java | 34 + .../apps/graph/model/IndicatorModel.java | 31 + .../webui/dashboard/DPPerformance.java | 1 + .../webui/desktop/DashboardController.java | 9 +- .../adempiere/webui/editor/WChartEditor.java | 10 +- org.adempiere.ui.zk/build.properties | 3 +- .../theme/default/css/theme.css.dsp | 5 +- 22 files changed, 1178 insertions(+), 869 deletions(-) create mode 100644 org.adempiere.base/src/org/adempiere/apps/graph/ChartBuilder.java create mode 100644 org.adempiere.ui.zk/OSGI-INF/jfgchartrenderer.xml create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/IChartRendererService.java rename org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/{util => apps/graph/jfreegraph}/ChartRenderer.java (90%) create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRendererServiceImpl.java create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/PerformanceGraphBuilder.java create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/ChartModel.java create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/GoalModel.java create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/IndicatorModel.java diff --git a/org.adempiere.base/src/org/adempiere/apps/graph/ChartBuilder.java b/org.adempiere.base/src/org/adempiere/apps/graph/ChartBuilder.java new file mode 100644 index 0000000000..0b1af541e1 --- /dev/null +++ b/org.adempiere.base/src/org/adempiere/apps/graph/ChartBuilder.java @@ -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 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(); + 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 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 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); + } +} diff --git a/org.adempiere.base/src/org/adempiere/apps/graph/GraphBuilder.java b/org.adempiere.base/src/org/adempiere/apps/graph/GraphBuilder.java index 7fa04fd44a..94e8c5f6f2 100644 --- a/org.adempiere.base/src/org/adempiere/apps/graph/GraphBuilder.java +++ b/org.adempiere.base/src/org/adempiere/apps/graph/GraphBuilder.java @@ -16,6 +16,7 @@ package org.adempiere.apps.graph; import java.awt.Color; import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import org.compiere.model.MGoal; import org.compiere.model.MMeasure; @@ -245,6 +246,11 @@ public class GraphBuilder { ArrayListlist = measure.getGraphColumnList(getMGoal()); + loadDataSet(list); + return list; + } + + public void loadDataSet(List list) { pieDataset = new DefaultPieDataset(); dataset = new DefaultCategoryDataset(); for (int i = 0; i < list.size(); i++){ @@ -260,6 +266,5 @@ public class GraphBuilder { list.get(i).getLabel()); pieDataset.setValue(list.get(i).getLabel(), list.get(i).getValue()); } - return list; } } \ No newline at end of file diff --git a/org.adempiere.base/src/org/compiere/model/MChart.java b/org.adempiere.base/src/org/compiere/model/MChart.java index af328053eb..9b36813787 100644 --- a/org.adempiere.base/src/org/compiere/model/MChart.java +++ b/org.adempiere.base/src/org/compiere/model/MChart.java @@ -1,27 +1,10 @@ package org.compiere.model; -import java.awt.Color; import java.sql.ResultSet; -import java.util.HashMap; import java.util.List; 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 { @@ -31,8 +14,6 @@ public class MChart extends X_AD_Chart { private static final long serialVersionUID = -8851465915516536910L; private int windowNo=0; - private Dataset dataset; - private HashMap queries; public MChart(Properties ctx, int AD_Chart_ID, String trxName) { super(ctx, AD_Chart_ID, trxName); @@ -42,46 +23,12 @@ public class MChart extends X_AD_Chart { super(ctx, rs, trxName); } - public void loadData() { - queries = new HashMap(); - 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 getDatasources() { + public List getDatasources() { return new Query(getCtx(), MChartDatasource.Table_Name, MChart.COLUMNNAME_AD_Chart_ID + "=?", null) .setParameters(getAD_Chart_ID()).setOnlyActiveRecords(true).list(); } - public HashMap getQueries() { - return queries; - } - public void setWindowNo(int windowNo) { this.windowNo = windowNo; } @@ -89,334 +36,4 @@ public class MChart extends X_AD_Chart { public int getWindowNo() { 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); - } - } diff --git a/org.adempiere.base/src/org/compiere/model/MChartDatasource.java b/org.adempiere.base/src/org/compiere/model/MChartDatasource.java index df5eff7bba..ec361cef4e 100644 --- a/org.adempiere.base/src/org/compiere/model/MChartDatasource.java +++ b/org.adempiere.base/src/org/compiere/model/MChartDatasource.java @@ -3,29 +3,14 @@ package org.compiere.model; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Timestamp; import java.text.SimpleDateFormat; -import java.util.Calendar; import java.util.Date; -import java.util.HashMap; import java.util.Properties; -import java.util.logging.Level; import org.adempiere.exceptions.DBException; import org.compiere.util.DB; import org.compiere.util.Env; 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 { @@ -43,209 +28,6 @@ public class MChartDatasource extends X_AD_ChartDatasource { 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 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 diff --git a/org.adempiere.ui.swing/src/org/compiere/grid/ed/VChart.java b/org.adempiere.ui.swing/src/org/compiere/grid/ed/VChart.java index f875e4078d..996ed90fb8 100644 --- a/org.adempiere.ui.swing/src/org/compiere/grid/ed/VChart.java +++ b/org.adempiere.ui.swing/src/org/compiere/grid/ed/VChart.java @@ -8,6 +8,7 @@ import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.VetoableChangeListener; +import org.adempiere.apps.graph.ChartBuilder; import org.compiere.apps.AEnv; import org.compiere.model.GridField; import org.compiere.model.MChart; @@ -34,6 +35,7 @@ public class VChart extends CPanel implements ChartMouseListener, VEditor { private static final long serialVersionUID = 1L; ChartPanel chartPanel; MChart chartModel; + private ChartBuilder chartBuilder; /** * Constructor */ @@ -52,7 +54,8 @@ public class VChart extends CPanel implements ChartMouseListener, VEditor { public void createChart() { - JFreeChart chart = chartModel.createChart(); + chartBuilder = new ChartBuilder(chartModel); + JFreeChart chart = chartBuilder.createChart(); if (chartPanel != null) remove(chartPanel); @@ -131,7 +134,7 @@ public class VChart extends CPanel implements ChartMouseListener, VEditor { if ( key == null ) return; - MQuery query = chartModel.getQuery(seriesName == null ? key : seriesName+"__"+key); + MQuery query = chartBuilder.getQuery(seriesName == null ? key : seriesName+"__"+key); if (query != null) AEnv.zoom(query); diff --git a/org.adempiere.ui.zk/META-INF/MANIFEST.MF b/org.adempiere.ui.zk/META-INF/MANIFEST.MF index ce53c62b71..68a249b77c 100644 --- a/org.adempiere.ui.zk/META-INF/MANIFEST.MF +++ b/org.adempiere.ui.zk/META-INF/MANIFEST.MF @@ -34,6 +34,7 @@ Export-Package: fi.jawsy.jawwa.zk.atmosphere, org.adempiere.webui.apps, org.adempiere.webui.apps.form, org.adempiere.webui.apps.graph, + org.adempiere.webui.apps.graph.model, org.adempiere.webui.apps.wf, org.adempiere.webui.component, org.adempiere.webui.component.test, @@ -85,4 +86,4 @@ Bundle-Activator: org.adempiere.webui.WebUIActivator Eclipse-ExtensibleAPI: true Eclipse-RegisterBuddy: org.zkoss.zk.library 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 diff --git a/org.adempiere.ui.zk/OSGI-INF/jfgchartrenderer.xml b/org.adempiere.ui.zk/OSGI-INF/jfgchartrenderer.xml new file mode 100644 index 0000000000..16a6d819ce --- /dev/null +++ b/org.adempiere.ui.zk/OSGI-INF/jfgchartrenderer.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/IChartRendererService.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/IChartRendererService.java new file mode 100644 index 0000000000..6c99cfff71 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/IChartRendererService.java @@ -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); +} \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WGraph.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WGraph.java index d245567ac4..c378265045 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WGraph.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WGraph.java @@ -14,15 +14,14 @@ package org.adempiere.webui.apps.graph; import java.awt.Point; -import java.awt.image.BufferedImage; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Iterator; -import java.util.logging.Level; +import java.util.Collections; -import org.adempiere.apps.graph.GraphBuilder; import org.adempiere.apps.graph.GraphColumn; +import org.adempiere.base.Service; import org.adempiere.webui.apps.AEnv; +import org.adempiere.webui.apps.graph.model.GoalModel; import org.adempiere.webui.editor.WTableDirEditor; import org.adempiere.webui.event.ValueChangeEvent; import org.adempiere.webui.event.ValueChangeListener; @@ -30,19 +29,10 @@ import org.compiere.model.MGoal; import org.compiere.model.MLookup; import org.compiere.model.MLookupFactory; import org.compiere.model.MLookupInfo; -import org.compiere.model.MQuery; +import org.compiere.model.MMeasure; import org.compiere.util.CLogger; import org.compiere.util.DB; 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.Br; 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.EventListener; import org.zkoss.zk.ui.event.Events; -import org.zkoss.zk.ui.event.MouseEvent; import org.zkoss.zul.Borderlayout; import org.zkoss.zul.Center; import org.zkoss.zul.East; -import org.zkoss.zul.Area; import org.zkoss.zul.Div; -import org.zkoss.zul.Imagemap; import org.zkoss.zul.Panel; import org.zkoss.zul.Panelchildren; import org.zkoss.zul.Toolbar; @@ -100,18 +87,21 @@ public class WGraph extends Div implements IdSpace { */ ArrayList list = new ArrayList(); - private GraphBuilder builder; - private boolean m_chartSelection; private int zoomFactor = 0; + private MGoal m_goal; + + private String m_xAxisLabel; + + private String m_yAxisLabel; + /** * Constructor */ public WGraph() { super(); - builder = new GraphBuilder(); panel = new Panel(); } // BarGraph @@ -154,9 +144,9 @@ public class WGraph extends Div implements IdSpace { */ public void setGoal(MGoal goal) { - builder.setMGoal(goal); - builder.setYAxisLabel(goal.getName()); - builder.setXAxisLabel(goal.getXAxisText()); + m_goal = goal; + m_yAxisLabel = goal.getName(); + m_xAxisLabel = goal.getXAxisText(); } /** @@ -194,10 +184,7 @@ public class WGraph extends Div implements IdSpace { } if (m_renderChart) { - JFreeChart chart = builder.createChart(builder.getMGoal() - .getChartType()); - - render(chart); + renderChart((String)null); } if (m_renderTable) { if (m_renderChart) { @@ -218,8 +205,16 @@ public class WGraph extends Div implements IdSpace { } 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) { Toolbar toolbar = new Toolbar(); panel.appendChild(toolbar); @@ -239,95 +234,32 @@ public class WGraph extends Div implements IdSpace { Object value = evt.getNewValue(); if (value == null || value.toString().trim().length() == 0) return; - JFreeChart chart = null; - chart = builder.createChart(value.toString()); - if (chart != null) - render(chart); + renderChart(value.toString()); } }); } } // loadData - private void render(JFreeChart chart) { - ChartRenderingInfo info = new ChartRenderingInfo(); + private void renderChart(String type) { int width = 560; int height = 400; - if (zoomFactor > 0) { - width = width * zoomFactor / 100; - height = height * zoomFactor / 100; - } - if (m_hideTitle) { - 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() { - 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); + if (panel.getPanelchildren() != null) { + panel.getPanelchildren().getChildren().clear(); + } else { + Panelchildren pc = new Panelchildren(); + panel.appendChild(pc); } + 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. */ public String getX_AxisLabel() { - return builder.getXAxisLabel(); + return m_xAxisLabel; } // getX_AxisLabel /** @@ -351,14 +283,14 @@ public class WGraph extends Div implements IdSpace { * The x_AxisLabel to set. */ public void setX_AxisLabel(String axisLabel) { - builder.setXAxisLabel(axisLabel); + m_xAxisLabel = axisLabel; } // setX_AxisLabel /** * @return Returns the y_AxisLabel. */ public String getY_AxisLabel() { - return builder.getYAxisLabel(); + return m_yAxisLabel; } // getY_AxisLabel /** @@ -366,7 +298,7 @@ public class WGraph extends Div implements IdSpace { * The y_AxisLabel to set. */ public void setY_AxisLabel(String axisLabel) { - builder.setYAxisLabel(axisLabel); + m_yAxisLabel = axisLabel; } // setY_AxisLabel /** @@ -431,27 +363,6 @@ public class WGraph extends Div implements IdSpace { 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[] @@ -484,7 +395,7 @@ public class WGraph extends Div implements IdSpace { td.setDynamicProperty("colspan", "2"); td.setSclass("pa-tdcontent"); tr.appendChild(td); - text = new Text(builder.getMGoal().getMeasureTarget().setScale(2, + text = new Text(m_goal.getMeasureTarget().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()); td.appendChild(text); @@ -499,7 +410,7 @@ public class WGraph extends Div implements IdSpace { td.setDynamicProperty("colspan", "2"); td.setSclass("pa-tdcontent"); tr.appendChild(td); - text = new Text(builder.getMGoal().getMeasureActual().setScale(2, + text = new Text(m_goal.getMeasureActual().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()); td.appendChild(text); @@ -512,7 +423,7 @@ public class WGraph extends Div implements IdSpace { td.setDynamicProperty("rowspan", bList.length); td.setSclass("pa-label"); td.setDynamicProperty("valign", "top"); - text = new Text(builder.getMGoal().getXAxisText()); + text = new Text(m_goal.getXAxisText()); td.appendChild(text); for (int k = 0; k < bList.length; k++) { @@ -531,7 +442,7 @@ public class WGraph extends Div implements IdSpace { td.setSclass("pa-tdvalue"); tr.appendChild(td); BigDecimal value = BigDecimal.valueOf(bgc.getValue()); - if (bgc.getMQuery(builder.getMGoal()) != null) { + if (bgc.getMQuery(m_goal) != null) { A a = new A(); a.setSclass("pa-hrefNode"); td.appendChild(a); @@ -545,8 +456,7 @@ public class WGraph extends Div implements IdSpace { int index = Integer.parseInt(String.valueOf(ss)); GraphColumn[] colList = getGraphColumnList(); if ((index >= 0) && (index < colList.length)) - AEnv.zoom(colList[index].getMQuery(builder - .getMGoal())); + AEnv.zoom(colList[index].getMQuery(m_goal)); } } @@ -564,11 +474,11 @@ public class WGraph extends Div implements IdSpace { td = new Td(); td.setDynamicProperty("colspan", "3"); tr.appendChild(td); - text = new Text(builder.getMGoal().getDescription()); + text = new Text(m_goal.getDescription()); td.appendChild(text); Br br = new Br(); td.appendChild(br); - text = new Text(stripHtml(builder.getMGoal().getColorSchema() + text = new Text(stripHtml(m_goal.getColorSchema() .getDescription(), true)); td.appendChild(text); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java index 80cd9a458d..c31a00ece7 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java @@ -66,8 +66,6 @@ public class WPAPanel extends Panel implements EventListener setSclass("performance-panel"); Grid grid = new 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(); Rows rows = new Rows(); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java index 5bc9289570..876e65e46d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java @@ -13,36 +13,22 @@ *****************************************************************************/ package org.adempiere.webui.apps.graph; -import java.awt.BasicStroke; 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.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.theme.ThemeManager; -import org.compiere.model.MColorSchema; import org.compiere.model.MGoal; import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.Msg; 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.EventListener; import org.zkoss.zk.ui.event.Events; -import org.zkoss.zul.Image; import org.zkoss.zul.Menuitem; import org.zkoss.zul.Menupopup; @@ -135,11 +121,24 @@ public class WPerformanceIndicator extends Panel implements EventListener return m_goal; } // getGoal - private JFreeChart createChart() + /** + * Init Graph Display + * Kinamo (pelgrim) + */ + private void init() { - JFreeChart chart = null; - - // Set Text + IChartRendererService renderer = Service.locator().locate(IChartRendererService.class).getService(); + IndicatorModel model = new IndicatorModel(); + 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()); if (m_goal.isTarget()) text.append(": ").append(m_goal.getPercent()).append("%"); @@ -157,96 +156,17 @@ public class WPerformanceIndicator extends Panel implements EventListener text.append(" ").append(Msg.getMsg(Env.getCtx(), "of")).append(" ") .append(s_format.format(m_goal.getMeasureTarget())); setTooltiptext(text.toString()); - // - DefaultValueDataset data = new DefaultValueDataset((float)m_goal.getPercent()); - 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; + + invalidate(); } - /** - * 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 { + if (event.getTarget() == this.getFirstChild()) + { + event.stopPropagation(); + Events.sendEvent(Events.ON_CLICK, this, event.getData()); + } } public String getTitle() diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/util/ChartRenderer.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRenderer.java similarity index 90% rename from org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/util/ChartRenderer.java rename to org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRenderer.java index 2667830cd8..70b57c675d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/util/ChartRenderer.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRenderer.java @@ -1,9 +1,10 @@ -package org.adempiere.webui.util; +package org.adempiere.webui.apps.graph.jfreegraph; import java.awt.image.BufferedImage; import java.util.Iterator; import java.util.logging.Level; +import org.adempiere.apps.graph.ChartBuilder; import org.adempiere.webui.apps.AEnv; import org.compiere.model.MChart; import org.compiere.model.MQuery; @@ -33,12 +34,14 @@ import org.zkoss.zul.Imagemap; * @author hengsin * */ -public class ChartRenderer { +/* package */ class ChartRenderer { private static final CLogger log = CLogger.getCLogger(ChartRenderer.class); private MChart chartModel; + private ChartBuilder chartBuilder; + /** * @param chartModel */ @@ -52,7 +55,9 @@ public class ChartRenderer { * @param width */ 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(); BufferedImage bi = chart.createBufferedImage(width, height, @@ -136,7 +141,7 @@ public class ChartRenderer { } 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) AEnv.zoom(query); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRendererServiceImpl.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRendererServiceImpl.java new file mode 100644 index 0000000000..5f9c819524 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/ChartRendererServiceImpl.java @@ -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() { + public void onEvent(Event event) throws Exception { + MouseEvent me = (MouseEvent) event; + String areaId = me.getArea(); + if (areaId != null) { + List 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); + } +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/PerformanceGraphBuilder.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/PerformanceGraphBuilder.java new file mode 100644 index 0000000000..6652c27b08 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/jfreegraph/PerformanceGraphBuilder.java @@ -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; + } +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/ChartModel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/ChartModel.java new file mode 100644 index 0000000000..25e0db13f4 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/ChartModel.java @@ -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; +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/GoalModel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/GoalModel.java new file mode 100644 index 0000000000..42d31a4206 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/GoalModel.java @@ -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 columnList; + public String xAxisLabel; + public String yAxisLabel; + public int zoomFactor; +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/IndicatorModel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/IndicatorModel.java new file mode 100644 index 0000000000..5da0fa1812 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/model/IndicatorModel.java @@ -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; +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java index 9e80740a48..55e5783883 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java @@ -86,6 +86,7 @@ public class DPPerformance extends DashboardPanel { script = script + "grid.parent().height(grid.css('height'));}, 500);"; if (Executions.getCurrent() != null) Clients.response(new AuScript(script)); + this.getFirstChild().invalidate(); } } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java index 865d40b108..16c6d31803 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/desktop/DashboardController.java @@ -29,8 +29,10 @@ import java.util.logging.Level; import org.adempiere.base.Service; import org.adempiere.exceptions.AdempiereException; 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.WPerformanceDetail; +import org.adempiere.webui.apps.graph.model.ChartModel; import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.dashboard.DashboardPanel; 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.session.SessionManager; import org.adempiere.webui.theme.ThemeManager; -import org.adempiere.webui.util.ChartRenderer; import org.adempiere.webui.window.ZkReportViewerProvider; import org.compiere.model.I_AD_Menu; import org.compiere.model.MChart; @@ -382,7 +383,6 @@ public class DashboardController implements EventListener { chartPanel.addEventListener(Events.ON_AFTER_SIZE, new EventListener() { @Override public void onEvent(AfterSizeEvent event) throws Exception { - ChartRenderer renderer = new ChartRenderer(chartModel); int width = event.getWidth()*90/100; int height = event.getHeight(); //set normal height @@ -391,7 +391,10 @@ public class DashboardController implements EventListener { chartPanel.setHeight(height+"px"); } 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); } }); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WChartEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WChartEditor.java index f0b2d394e8..b9c0e51afd 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WChartEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WChartEditor.java @@ -14,7 +14,9 @@ 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.MChart; import org.compiere.util.CLogger; @@ -50,7 +52,6 @@ public class WChartEditor extends WEditor } private void createChart() { - ChartRenderer renderer = new ChartRenderer(chartModel); Panel panel = getComponent(); if (panel.getPanelchildren() != null) { panel.getPanelchildren().getChildren().clear(); @@ -59,7 +60,10 @@ public class WChartEditor extends WEditor panel.appendChild(pc); 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 diff --git a/org.adempiere.ui.zk/build.properties b/org.adempiere.ui.zk/build.properties index c4dc52dec3..d5f688490c 100644 --- a/org.adempiere.ui.zk/build.properties +++ b/org.adempiere.ui.zk/build.properties @@ -33,7 +33,8 @@ bin.includes = META-INF/,\ OSGI-INF/feedbackservice.xml,\ sessiontimeout.zul,\ *.jsp,\ - labelapplet.jar + labelapplet.jar,\ + OSGI-INF/jfgchartrenderer.xml src.includes = WEB-INF/classes/,\ WEB-INF/tld/,\ WEB-INF/web.xml,\ diff --git a/org.adempiere.ui.zk/theme/default/css/theme.css.dsp b/org.adempiere.ui.zk/theme/default/css/theme.css.dsp index 462c65e740..02e7d86b2c 100644 --- a/org.adempiere.ui.zk/theme/default/css/theme.css.dsp +++ b/org.adempiere.ui.zk/theme/default/css/theme.css.dsp @@ -1660,15 +1660,16 @@ table.z-vbox > tbody > tr > td > table { .performance-indicator { margin: auto; position: relative; - width: 120px !important; } .performance-indicator img { height: 120px; width: 120px; + display: block; + margin: auto; } -.window-view-pi .performance-indicator { +.window-view-pi .performance-indicator img { width: 180px !important; }