/**
* $URL: https://source.sakaiproject.org/svn/sitestats/trunk/sitestats-impl/src/java/org/sakaiproject/sitestats/impl/chart/ChartServiceImpl.java $
* $Id: ChartServiceImpl.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $
*
* Copyright (c) 2006-2009 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sakaiproject.sitestats.impl.chart;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.imageio.ImageIO;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.PeriodAxis;
import org.jfree.chart.axis.PeriodAxisLabelInfo;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
import org.jfree.chart.renderer.xy.ClusteredXYBarRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.UnknownKeyException;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.AbstractDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.TimePeriodAnchor;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleInsets;
import org.jfree.util.SortOrder;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.sitestats.api.EventStat;
import org.sakaiproject.sitestats.api.ResourceStat;
import org.sakaiproject.sitestats.api.SiteActivityByTool;
import org.sakaiproject.sitestats.api.SitePresence;
import org.sakaiproject.sitestats.api.SiteVisits;
import org.sakaiproject.sitestats.api.Stat;
import org.sakaiproject.sitestats.api.StatsManager;
import org.sakaiproject.sitestats.api.SummaryActivityChartData;
import org.sakaiproject.sitestats.api.SummaryVisitsChartData;
import org.sakaiproject.sitestats.api.Util;
import org.sakaiproject.sitestats.api.chart.ChartService;
import org.sakaiproject.sitestats.api.event.EventRegistryService;
import org.sakaiproject.sitestats.api.report.Report;
import org.sakaiproject.sitestats.api.report.ReportManager;
import org.sakaiproject.sitestats.impl.event.EventRegistryServiceImpl;
import org.sakaiproject.user.api.PreferencesService;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.util.ResourceLoader;
public class ChartServiceImpl implements ChartService {
/** Static fields */
private static Log LOG = LogFactory.getLog(EventRegistryServiceImpl.class);
private static ResourceLoader msgs = new ResourceLoader("Messages");
private static final int MIN_CHART_WIDTH_TO_DRAW_ALL_DAYS = 640;
/** Utility */
private Map<Integer, String> weekDaysMap = null;
private Map<Integer, String> monthNamesMap = null;
/** Sakai services */
private StatsManager M_sm;
private SiteService M_ss;
private UserDirectoryService M_uds;
private PreferencesService M_ps;
private EventRegistryService M_ers;
// ################################################################
// Spring methods
// ################################################################
public void setStatsManager(StatsManager statsManager) {
this.M_sm = statsManager;
}
public void setSiteService(SiteService siteService) {
this.M_ss = siteService;
}
public void setUserService(UserDirectoryService userDirectoryService) {
this.M_uds = userDirectoryService;
}
public void setPreferencesService(PreferencesService preferencesService) {
this.M_ps = preferencesService;
}
public void setEventRegistryService(EventRegistryService eventRegistryService) {
this.M_ers = eventRegistryService;
}
// ################################################################
// Chart Service methods
// ################################################################
/* (non-Javadoc)
* @see org.sakaiproject.sitestats.api.chart.ChartService#generateVisitsChart(java.lang.String, java.lang.String, int, int, boolean, float, boolean)
*/
public byte[] generateVisitsChart(
String siteId, String viewType,
int width, int height,
boolean render3d, float transparency, boolean itemLabelsVisible) {
CategoryDataset dataset = null;
boolean smallFontInDomainAxis = false;
render3d = false;
if(StatsManager.VIEW_WEEK.equals(viewType)) {
dataset = getVisitsWeekDataSet(siteId);
}else if(StatsManager.VIEW_MONTH.equals(viewType)) {
dataset = getVisitsMonthDataSet(siteId, width);
smallFontInDomainAxis = true;
}else{
dataset = getVisitsYearDataSet(siteId);
}
if(dataset != null)
return generateBarChart(siteId, dataset, width, height, render3d, transparency, itemLabelsVisible, smallFontInDomainAxis);
else
return generateNoDataChart(width, height);
}
/* (non-Javadoc)
* @see org.sakaiproject.sitestats.api.chart.ChartService#generateActivityChart(java.lang.String, java.lang.String, java.lang.String, int, int, boolean, float, boolean)
*/
public byte[] generateActivityChart(
String siteId, String viewType, String chartType,
int width, int height,
boolean render3d, float transparency, boolean itemLabelsVisible) {
boolean smallFontInDomainAxis = false;
render3d = false;
if(StatsManager.CHARTTYPE_PIE.equals(chartType)) {
DefaultPieDataset dataset = null;
if(StatsManager.VIEW_WEEK.equals(viewType))
dataset = getActivityWeekPieDataSet(siteId);
else if(StatsManager.VIEW_MONTH.equals(viewType))
dataset = getActivityMonthPieDataSet(siteId);
else
dataset = getActivityYearPieDataSet(siteId);
if(dataset != null)
return generatePieChart(siteId, dataset, width, height, render3d, transparency, smallFontInDomainAxis);
else
return generateNoDataChart(width, height);
}else{
CategoryDataset dataset = null;
if(StatsManager.VIEW_WEEK.equals(viewType))
dataset = getActivityWeekBarDataSet(siteId);
else if(StatsManager.VIEW_MONTH.equals(viewType)){
dataset = getActivityMonthBarDataSet(siteId, width);
smallFontInDomainAxis = true;
}else
dataset = getActivityYearBarDataSet(siteId);
if(dataset != null)
return generateBarChart(siteId, dataset, width, height, render3d, transparency, itemLabelsVisible, smallFontInDomainAxis);
else
return generateNoDataChart(width, height);
}
}
/* (non-Javadoc)
* @see org.sakaiproject.sitestats.api.chart.ChartService#generateChart(java.lang.String, java.lang.Object, java.lang.String, int, int, boolean, float, boolean, java.lang.String)
*/
public byte[] generateChart(
String siteId, Object dataset, String chartType,
int width, int height,
boolean render3d, float transparency,
boolean itemLabelsVisible, String timePeriod) {
render3d = false;
if(StatsManager.CHARTTYPE_BAR.equals(chartType)) {
if(dataset instanceof CategoryDataset) {
CategoryDataset ds = (CategoryDataset) dataset;
return generateBarChart(siteId, ds, width, height, render3d, transparency, itemLabelsVisible, false);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing CategoryDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_LINE.equals(chartType)) {
if(dataset instanceof CategoryDataset) {
CategoryDataset ds = (CategoryDataset) dataset;
return generateLineChart(siteId, ds, width, height, render3d, transparency, itemLabelsVisible, false);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing CategoryDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_PIE.equals(chartType)) {
if(dataset instanceof PieDataset) {
PieDataset ds = (PieDataset) dataset;
return generatePieChart(siteId, ds, width, height, render3d, transparency, false);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing PieDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_TIMESERIES.equals(chartType)) {
if(dataset instanceof IntervalXYDataset) {
IntervalXYDataset ds = (IntervalXYDataset) dataset;
return generateTimeSeriesChart(siteId, ds, width, height, false, transparency, itemLabelsVisible, false, timePeriod);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing XYDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_TIMESERIESBAR.equals(chartType)) {
if(dataset instanceof IntervalXYDataset) {
IntervalXYDataset ds = (IntervalXYDataset) dataset;
return generateTimeSeriesChart(siteId, ds, width, height, true, transparency, itemLabelsVisible, false, timePeriod);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing XYDataset are supported.");
}
}
LOG.warn("Chart type "+chartType+" not supported: only line, bar, pie, timeseries are supported.");
return null;
}
/* (non-Javadoc)
* @see org.sakaiproject.sitestats.api.chart.ChartService#generateChart(org.sakaiproject.sitestats.api.report.ReportDef, int, int, boolean, float, boolean)
*/
public byte[] generateChart(
Report report,
int width, int height,
boolean render3d, float transparency,
boolean itemLabelsVisible) {
// Data set
AbstractDataset dataset = null;
String chartType = report.getReportDefinition().getReportParams().getHowChartType();
render3d = false;
if(StatsManager.CHARTTYPE_BAR.equals(chartType)
|| StatsManager.CHARTTYPE_LINE.equals(chartType)) {
dataset = getCategoryDataset(report);
}else if(StatsManager.CHARTTYPE_TIMESERIES.equals(chartType)
|| StatsManager.CHARTTYPE_TIMESERIESBAR.equals(chartType)) {
dataset = getTimeSeriesCollectionDataset(report);
}else if(StatsManager.CHARTTYPE_PIE.equals(chartType)) {
dataset = getPieDataset(report);
}
// Report
if(dataset != null) {
/*return generateChart(
report.getReportDefinition().getReportParams().getSiteId(), dataset, chartType,
width, height,
render3d, transparency,
true,
report.getReportDefinition().getReportParams().getHowChartSeriesPeriod()
);*/
String siteId = report.getReportDefinition().getReportParams().getSiteId();
String timePeriod = report.getReportDefinition().getReportParams().getHowChartSeriesPeriod();
Date firstDate = report.getReportDefinition().getReportParams().getWhenFrom();
Date lastDate = report.getReportDefinition().getReportParams().getWhenTo();
if(StatsManager.CHARTTYPE_BAR.equals(chartType)) {
if(dataset instanceof CategoryDataset) {
CategoryDataset ds = (CategoryDataset) dataset;
return generateBarChart(siteId, ds, width, height, render3d, transparency, itemLabelsVisible, false);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing CategoryDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_LINE.equals(chartType)) {
if(dataset instanceof CategoryDataset) {
CategoryDataset ds = (CategoryDataset) dataset;
return generateLineChart(siteId, ds, width, height, render3d, transparency, itemLabelsVisible, false);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing CategoryDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_PIE.equals(chartType)) {
if(dataset instanceof PieDataset) {
PieDataset ds = (PieDataset) dataset;
return generatePieChart(siteId, ds, width, height, render3d, transparency, false);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing PieDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_TIMESERIES.equals(chartType)) {
if(dataset instanceof IntervalXYDataset) {
IntervalXYDataset ds = (IntervalXYDataset) dataset;
return generateTimeSeriesChart(siteId, ds, width, height, false, transparency, itemLabelsVisible, false, timePeriod, firstDate, lastDate);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing XYDataset are supported.");
}
}else if(StatsManager.CHARTTYPE_TIMESERIESBAR.equals(chartType)) {
if(dataset instanceof IntervalXYDataset) {
IntervalXYDataset ds = (IntervalXYDataset) dataset;
return generateTimeSeriesChart(siteId, ds, width, height, true, transparency, itemLabelsVisible, false, timePeriod, firstDate, lastDate);
}else{
LOG.warn("Dataset not supported for "+chartType+" chart type: only classes implementing XYDataset are supported.");
}
}
LOG.warn("Chart type "+chartType+" not supported: only line, bar, pie, timeseries are supported.");
return null;
}else{
LOG.warn("Chart type "+chartType+" not supported: only line, bar, pie, timeseries are supported.");
return null;
}
}
// ######################################################################################
// Chart Generation methods
// ######################################################################################
private byte[] generateBarChart(
String siteId, CategoryDataset dataset, int width, int height,
boolean render3d, float transparency,
boolean itemLabelsVisible,
boolean smallFontInDomainAxis) {
JFreeChart chart = null;
if(render3d)
chart = ChartFactory.createBarChart3D(null, null, null, dataset, PlotOrientation.VERTICAL, true, false, false);
else
chart = ChartFactory.createBarChart(null, null, null, dataset, PlotOrientation.VERTICAL, true, false, false);
CategoryPlot plot = (CategoryPlot) chart.getPlot();
// set transparency
plot.setForegroundAlpha(transparency);
// set background
chart.setBackgroundPaint(parseColor(M_sm.getChartBackgroundColor()));
// set chart border
chart.setPadding(new RectangleInsets(10,5,5,5));
chart.setBorderVisible(true);
chart.setBorderPaint(parseColor("#cccccc"));
// allow longer legends (prevent truncation)
plot.getDomainAxis().setMaximumCategoryLabelLines(50);
plot.getDomainAxis().setMaximumCategoryLabelWidthRatio(1.0f);
// set antialias
chart.setAntiAlias(true);
// set domain axis font size
if(smallFontInDomainAxis && !canUseNormalFontSize(width)) {
plot.getDomainAxis().setTickLabelFont(new Font("SansSerif", Font.PLAIN, 8));
plot.getDomainAxis().setCategoryMargin(0.05);
}
// set bar outline
BarRenderer barrenderer = (BarRenderer) plot.getRenderer();
barrenderer.setDrawBarOutline(true);
if(smallFontInDomainAxis && !canUseNormalFontSize(width))
barrenderer.setItemMargin(0.05);
else
barrenderer.setItemMargin(0.10);
// item labels
if(itemLabelsVisible) {
plot.getRangeAxis().setUpperMargin(0.2);
barrenderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator() {
private static final long serialVersionUID = 1L;
@Override
public String generateLabel(CategoryDataset dataset, int row, int column) {
Number n = dataset.getValue(row, column);
if(n.doubleValue() != 0) {
if((double)n.intValue() == n.doubleValue()) return Integer.toString(n.intValue());
else return Double.toString( Util.round(n.doubleValue(), 1) );
}
return "";
}
});
barrenderer.setItemLabelFont(new Font("SansSerif", Font.PLAIN, 8));
barrenderer.setItemLabelsVisible(true);
}
BufferedImage img = chart.createBufferedImage(width, height);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
ImageIO.write(img, "png", out);
}catch(IOException e){
LOG.warn("Error occurred while generating SiteStats chart image data", e);
}
return out.toByteArray();
}
private byte[] generateLineChart(
String siteId, CategoryDataset dataset, int width, int height,
boolean render3d, float transparency,
boolean itemLabelsVisible,
boolean smallFontInDomainAxis) {
JFreeChart chart = null;
if(render3d)
chart = ChartFactory.createLineChart3D(null, null, null, dataset, PlotOrientation.VERTICAL, true, false, false);
else
chart = ChartFactory.createLineChart(null, null, null, dataset, PlotOrientation.VERTICAL, true, false, false);
CategoryPlot plot = (CategoryPlot) chart.getPlot();
// set transparency
plot.setForegroundAlpha(transparency);
// set background
chart.setBackgroundPaint(parseColor(M_sm.getChartBackgroundColor()));
// set chart border
chart.setPadding(new RectangleInsets(10,5,5,5));
chart.setBorderVisible(true);
chart.setBorderPaint(parseColor("#cccccc"));
// set antialias
chart.setAntiAlias(true);
// set domain axis font size
if(smallFontInDomainAxis && !canUseNormalFontSize(width)) {
plot.getDomainAxis().setTickLabelFont(new Font("SansSerif", Font.PLAIN, 8));
plot.getDomainAxis().setCategoryMargin(0.05);
}
// set outline
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
renderer.setDrawOutlines(true);
// item labels
if(itemLabelsVisible) {
plot.getRangeAxis().setUpperMargin(0.2);
renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator() {
private static final long serialVersionUID = 1L;
@Override
public String generateLabel(CategoryDataset dataset, int row, int column) {
Number n = dataset.getValue(row, column);
if(n.intValue() != 0)
//return n.intValue()+"";
return n.toString();
return "";
}
});
renderer.setItemLabelFont(new Font("SansSerif", Font.PLAIN, 8));
renderer.setItemLabelsVisible(true);
}
BufferedImage img = chart.createBufferedImage(width, height);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
ImageIO.write(img, "png", out);
}catch(IOException e){
LOG.warn("Error occurred while generating SiteStats chart image data", e);
}
return out.toByteArray();
}
private byte[] generatePieChart(
String siteId, PieDataset dataset, int width, int height,
boolean render3d, float transparency,
boolean smallFontInDomainAxis) {
JFreeChart chart = null;
if(render3d)
chart = ChartFactory.createPieChart3D(null, dataset, false, false, false);
else
chart = ChartFactory.createPieChart(null, dataset, false, false, false);
PiePlot plot = (PiePlot) chart.getPlot();
// set start angle (135 or 150 deg so minor data has more space on the left)
plot.setStartAngle(150D);
// set transparency
plot.setForegroundAlpha(transparency);
// set background
chart.setBackgroundPaint(parseColor(M_sm.getChartBackgroundColor()));
plot.setBackgroundPaint(parseColor(M_sm.getChartBackgroundColor()));
// fix border offset
chart.setPadding(new RectangleInsets(5,5,5,5));
plot.setInsets(new RectangleInsets(1,1,1,1));
// set chart border
plot.setOutlinePaint(null);
chart.setBorderVisible(true);
chart.setBorderPaint(parseColor("#cccccc"));
// set antialias
chart.setAntiAlias(true);
BufferedImage img = chart.createBufferedImage(width, height);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
ImageIO.write(img, "png", out);
}catch(IOException e){
LOG.warn("Error occurred while generating SiteStats chart image data", e);
}
return out.toByteArray();
}
private byte[] generateTimeSeriesChart(
String siteId, IntervalXYDataset dataset, int width, int height,
boolean renderBar, float transparency,
boolean itemLabelsVisible,
boolean smallFontInDomainAxis,
String timePeriod) {
return generateTimeSeriesChart(siteId, dataset, width, height,
renderBar, transparency,
itemLabelsVisible,
smallFontInDomainAxis,
timePeriod, null, null);
}
private byte[] generateTimeSeriesChart(
String siteId, IntervalXYDataset dataset, int width, int height,
boolean renderBar, float transparency,
boolean itemLabelsVisible,
boolean smallFontInDomainAxis,
String timePeriod, Date firstDate, Date lastDate) {
JFreeChart chart = null;
if(!renderBar) {
chart = ChartFactory.createTimeSeriesChart(null, null, null, dataset, true, false, false);
}else {
chart = ChartFactory.createXYBarChart(null,
null, true, null, dataset, PlotOrientation.VERTICAL,
true, false, false);
}
XYPlot plot = (XYPlot) chart.getPlot();
// set transparency
plot.setForegroundAlpha(transparency);
// set background
chart.setBackgroundPaint(parseColor(M_sm.getChartBackgroundColor()));
// set chart border
chart.setPadding(new RectangleInsets(10,5,5,5));
chart.setBorderVisible(true);
chart.setBorderPaint(parseColor("#cccccc"));
// set antialias
chart.setAntiAlias(true);
// set domain axis font size
if(smallFontInDomainAxis && !canUseNormalFontSize(width)) {
plot.getDomainAxis().setTickLabelFont(new Font("SansSerif", Font.PLAIN, 8));
}
// configure date display (localized) in domain axis
Locale locale = msgs.getLocale();
PeriodAxis periodaxis = new PeriodAxis(null);
Class timePeriodClass = null;
if(dataset instanceof TimeSeriesCollection) {
TimeSeriesCollection tsc = (TimeSeriesCollection) dataset;
if(tsc.getSeriesCount() > 0) {
timePeriodClass = tsc.getSeries(0).getTimePeriodClass();
}else{
timePeriodClass = org.jfree.data.time.Day.class;
}
periodaxis.setAutoRangeTimePeriodClass(timePeriodClass);
}
PeriodAxisLabelInfo aperiodaxislabelinfo[] = null;
if(StatsManager.CHARTTIMESERIES_WEEKDAY.equals(timePeriod)) {
aperiodaxislabelinfo = new PeriodAxisLabelInfo[2];
aperiodaxislabelinfo[0] = new PeriodAxisLabelInfo(org.jfree.data.time.Day.class, new SimpleDateFormat("E", locale));
aperiodaxislabelinfo[1] = new PeriodAxisLabelInfo(org.jfree.data.time.Day.class, new SimpleDateFormat("d", locale));
}else if(StatsManager.CHARTTIMESERIES_DAY.equals(timePeriod)) {
aperiodaxislabelinfo = new PeriodAxisLabelInfo[3];
aperiodaxislabelinfo[0] = new PeriodAxisLabelInfo(org.jfree.data.time.Day.class, new SimpleDateFormat("d", locale));
aperiodaxislabelinfo[1] = new PeriodAxisLabelInfo(org.jfree.data.time.Month.class, new SimpleDateFormat("MMM", locale));
aperiodaxislabelinfo[2] = new PeriodAxisLabelInfo(org.jfree.data.time.Year.class, new SimpleDateFormat("yyyy", locale));
}else if(StatsManager.CHARTTIMESERIES_MONTH.equals(timePeriod)) {
aperiodaxislabelinfo = new PeriodAxisLabelInfo[2];
aperiodaxislabelinfo[0] = new PeriodAxisLabelInfo(org.jfree.data.time.Month.class, new SimpleDateFormat("MMM", locale));
aperiodaxislabelinfo[1] = new PeriodAxisLabelInfo(org.jfree.data.time.Year.class, new SimpleDateFormat("yyyy", locale));
}else if(StatsManager.CHARTTIMESERIES_YEAR.equals(timePeriod)) {
aperiodaxislabelinfo = new PeriodAxisLabelInfo[1];
aperiodaxislabelinfo[0] = new PeriodAxisLabelInfo(org.jfree.data.time.Year.class, new SimpleDateFormat("yyyy", locale));
}
periodaxis.setLabelInfo(aperiodaxislabelinfo);
// date range
if(firstDate != null || lastDate != null) {
periodaxis.setAutoRange(false);
if(firstDate != null) {
if(StatsManager.CHARTTIMESERIES_MONTH.equals(timePeriod) || StatsManager.CHARTTIMESERIES_YEAR.equals(timePeriod)) {
periodaxis.setFirst(new org.jfree.data.time.Month(firstDate));
}else{
periodaxis.setFirst(new org.jfree.data.time.Day(firstDate));
}
}
if(lastDate != null) {
if(StatsManager.CHARTTIMESERIES_MONTH.equals(timePeriod) || StatsManager.CHARTTIMESERIES_YEAR.equals(timePeriod)) {
periodaxis.setLast(new org.jfree.data.time.Month(lastDate));
}else{
periodaxis.setLast(new org.jfree.data.time.Day(lastDate));
}
}
}
periodaxis.setTickMarkOutsideLength(0.0F);
plot.setDomainAxis(periodaxis);
// set outline
AbstractXYItemRenderer renderer = (AbstractXYItemRenderer) plot.getRenderer();
if(renderer instanceof XYLineAndShapeRenderer) {
XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) renderer;
r.setDrawSeriesLineAsPath(true);
r.setShapesVisible(true);
r.setShapesFilled(true);
}else if(renderer instanceof XYBarRenderer) {
//XYBarRenderer r = (XYBarRenderer) renderer;
ClusteredXYBarRenderer r = new ClusteredXYBarRenderer();
r.setDrawBarOutline(true);
if(smallFontInDomainAxis && !canUseNormalFontSize(width))
r.setMargin(0.05);
else
r.setMargin(0.10);
plot.setRenderer(r);
renderer = r;
}
// item labels
if(itemLabelsVisible) {
plot.getRangeAxis().setUpperMargin(0.2);
renderer.setItemLabelGenerator(new XYItemLabelGenerator() {
private static final long serialVersionUID = 1L;
public String generateLabel(XYDataset dataset, int series, int item) {
Number n = dataset.getY(series, item);
if(n.doubleValue() != 0)
return n.toString();
return "";
}
});
renderer.setItemLabelFont(new Font("SansSerif", Font.PLAIN, 8));
renderer.setItemLabelsVisible(true);
}
BufferedImage img = chart.createBufferedImage(width, height);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
ImageIO.write(img, "png", out);
}catch(IOException e){
LOG.warn("Error occurred while generating SiteStats chart image data", e);
}
return out.toByteArray();
}
private byte[] generateNoDataChart(int width, int height) {
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setBackground(parseColor(M_sm.getChartBackgroundColor()));
g2d.clearRect(0, 0, width-1, height-1);
g2d.setColor(parseColor("#cccccc"));
g2d.drawRect(0, 0, width-1, height-1);
Font f = new Font("SansSerif", Font.PLAIN, 12);
g2d.setFont(f);
FontMetrics fm = g2d.getFontMetrics(f);
String noData = msgs.getString("no_data");
int noDataWidth = fm.stringWidth(noData);
int noDataHeight = fm.getHeight();
g2d.setColor(parseColor("#555555"));
g2d.drawString(noData, width/2 - noDataWidth/2, height/2 - noDataHeight/2 + 2);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
ImageIO.write(img, "png", out);
}catch(IOException e){
LOG.warn("Error occurred while generating SiteStats chart image data", e);
}
return out.toByteArray();
}
// ######################################################################################
// Chart DataSet methods
// ######################################################################################
private DefaultCategoryDataset getVisitsWeekDataSet(String siteId) {
// LOG.info("Generating visitsWeekDataSet");
SummaryVisitsChartData svc = M_sm.getSummaryVisitsChartData(siteId, StatsManager.VIEW_WEEK);
if(svc == null) return null;
DefaultCategoryDataset visitsWeekDataSet = new DefaultCategoryDataset();
String visits = msgs.getString("legend_visits");
String uniqueVisits = msgs.getString("legend_unique_visitors");
Calendar cal = Calendar.getInstance();
cal.setTime(svc.getFirstDay());
Calendar currDay = (Calendar) cal.clone();
long visitsData[] = svc.getVisits();
long uniqueVisitsData[] = svc.getUniqueVisits();
for(int i = 0; i < visitsData.length; i++){
visitsWeekDataSet.addValue(visitsData[i], visits, getWeekDaysMap().get(currDay.get(Calendar.DAY_OF_WEEK)));
visitsWeekDataSet.addValue(uniqueVisitsData[i], uniqueVisits, getWeekDaysMap().get(currDay.get(Calendar.DAY_OF_WEEK)));
currDay.add(Calendar.DAY_OF_YEAR, 1);
}
return visitsWeekDataSet;
}
private DefaultCategoryDataset getVisitsMonthDataSet(String siteId, int width) {
// LOG.info("Generating visitsMonthDataSet");
SummaryVisitsChartData svc = M_sm.getSummaryVisitsChartData(siteId, StatsManager.VIEW_MONTH);
if(svc == null) return null;
DefaultCategoryDataset visitsMonthDataSet = new DefaultCategoryDataset();
String visits = msgs.getString("legend_visits");
String uniqueVisits = msgs.getString("legend_unique_visitors");
Day day;
Calendar cal = Calendar.getInstance();
cal.setTime(svc.getFirstDay());
Calendar currDay = (Calendar) cal.clone();
long visitsData[] = svc.getVisits();
long uniqueVisitsData[] = svc.getUniqueVisits();
for(int i = 0; i < visitsData.length; i++){
int dayOfMonth = currDay.get(Calendar.DAY_OF_MONTH);
if(canUseNormalFontSize(width) || (i == 0 || i == 30 - 1 || i % 2 == 0)){
day = new Day(dayOfMonth, Integer.toString(dayOfMonth));
}else{
day = new Day(dayOfMonth, "");
}
visitsMonthDataSet.addValue(visitsData[i], visits, day);
visitsMonthDataSet.addValue(uniqueVisitsData[i], uniqueVisits, day);
currDay.add(Calendar.DAY_OF_MONTH, 1);
}
return visitsMonthDataSet;
}
private DefaultCategoryDataset getVisitsYearDataSet(String siteId) {
// LOG.info("Generating visitsYearDataSet");
SummaryVisitsChartData svc = M_sm.getSummaryVisitsChartData(siteId, StatsManager.VIEW_YEAR);
if(svc == null) return null;
DefaultCategoryDataset visitsYearDataSet = new DefaultCategoryDataset();
String visits = msgs.getString("legend_visits");
String uniqueVisits = msgs.getString("legend_unique_visitors");
Calendar cal = Calendar.getInstance();
cal.setTime(svc.getFirstDay());
Calendar currMonth = (Calendar) cal.clone();
long visitsData[] = svc.getVisits();
long uniqueVisitsData[] = svc.getUniqueVisits();
for(int i = 0; i < visitsData.length; i++){
visitsYearDataSet.addValue(visitsData[i], visits, getMonthNamesMap().get(currMonth.get(Calendar.MONTH)));
visitsYearDataSet.addValue(uniqueVisitsData[i], uniqueVisits, getMonthNamesMap().get(currMonth.get(Calendar.MONTH)));
currMonth.add(Calendar.MONTH, 1);
}
return visitsYearDataSet;
}
private DefaultPieDataset getActivityWeekPieDataSet(String siteId) {
// LOG.info("Generating activityWeekPieDataSet");
SummaryActivityChartData sac = M_sm.getSummaryActivityChartData(siteId, StatsManager.VIEW_WEEK, StatsManager.CHARTTYPE_PIE);
if(sac == null) return null;
DefaultPieDataset activityWeekPieDataSet = fillActivityPieDataSet(sac);
return activityWeekPieDataSet;
}
private DefaultPieDataset getActivityMonthPieDataSet(String siteId) {
// LOG.info("Generating activityMonthPieDataSet");
SummaryActivityChartData sac = M_sm.getSummaryActivityChartData(siteId, StatsManager.VIEW_MONTH, StatsManager.CHARTTYPE_PIE);
if(sac == null) return null;
DefaultPieDataset activityMonthPieDataSet = fillActivityPieDataSet(sac);
return activityMonthPieDataSet;
}
private DefaultPieDataset getActivityYearPieDataSet(String siteId) {
// LOG.info("Generating activityYearPieDataSet");
SummaryActivityChartData sac = M_sm.getSummaryActivityChartData(siteId, StatsManager.VIEW_YEAR, StatsManager.CHARTTYPE_PIE);
if(sac == null) return null;
DefaultPieDataset activityYearPieDataSet = fillActivityPieDataSet(sac);
return activityYearPieDataSet;
}
private DefaultPieDataset fillActivityPieDataSet(SummaryActivityChartData sac){
DefaultPieDataset pieDataSet = new DefaultPieDataset();
List<SiteActivityByTool> lsac = sac.getActivityByTool();
int total = sac.getActivityByToolTotal();
int showMax = 5;
for(int i=0; i<lsac.size() && i<showMax; i++){
SiteActivityByTool s = lsac.get(i);
double percentage = (double) s.getCount() * 100 / total;
int decimalPlaces = 1;
if(percentage < 0.1)
decimalPlaces = 2;
String label = M_ers.getToolName(s.getTool().getToolId()) + " " + Util.round(percentage, decimalPlaces) + "%";
pieDataSet.setValue(label, percentage );
}
if(lsac.size() > showMax){
int acumulated = 0;
String otherTools = msgs.getString("label_activity_other_tools");
for(int i=showMax; i<lsac.size(); i++){
SiteActivityByTool s = lsac.get(i);
acumulated += s.getCount();
}
double percentage = (double) acumulated * 100 / total;
int decimalPlaces = 1;
if(percentage < 0.1)
decimalPlaces = 2;
String label = otherTools + " " + Util.round(percentage, decimalPlaces) + "%";
pieDataSet.setValue(label, percentage );
}
return pieDataSet;
}
private DefaultCategoryDataset getActivityWeekBarDataSet(String siteId) {
// LOG.info("Generating activityWeekBarDataSet");
SummaryActivityChartData sac = M_sm.getSummaryActivityChartData(siteId, StatsManager.VIEW_WEEK, StatsManager.CHARTTYPE_BAR);
if(sac == null) return null;
DefaultCategoryDataset activityWeekBarDataSet = new DefaultCategoryDataset();
String activity = msgs.getString("legend_activity");
Calendar cal = Calendar.getInstance();
cal.setTime(sac.getFirstDay());
Calendar currDay = (Calendar) cal.clone();
long activityData[] = sac.getActivity();
for(int i = 0; i < activityData.length; i++){
activityWeekBarDataSet.addValue(activityData[i], activity, getWeekDaysMap().get(currDay.get(Calendar.DAY_OF_WEEK)));
currDay.add(Calendar.DAY_OF_YEAR, 1);
}
return activityWeekBarDataSet;
}
private DefaultCategoryDataset getActivityMonthBarDataSet(String siteId, int width) {
// LOG.info("Generating activityMonthBarDataSet");
SummaryActivityChartData sac = M_sm.getSummaryActivityChartData(siteId, StatsManager.VIEW_MONTH, StatsManager.CHARTTYPE_BAR);
if(sac == null) return null;
DefaultCategoryDataset activityMonthBarDataSet = new DefaultCategoryDataset();
String activity = msgs.getString("legend_activity");
Day day;
Calendar cal = Calendar.getInstance();
cal.setTime(sac.getFirstDay());
Calendar currDay = (Calendar) cal.clone();
long activityData[] = sac.getActivity();
for(int i = 0; i < activityData.length; i++){
int dayOfMonth = currDay.get(Calendar.DAY_OF_MONTH);
//if(params.areAllDaysDrawable() || (i == 0 || i == 30 - 1 || i % 2 == 0)){
if(canUseNormalFontSize(width) || (i == 0 || i == 30 - 1 || i % 2 == 0)){
day = new Day(dayOfMonth, Integer.toString(dayOfMonth));
}else{
day = new Day(dayOfMonth, "");
}
activityMonthBarDataSet.addValue(activityData[i], activity, day);
currDay.add(Calendar.DAY_OF_MONTH, 1);
}
return activityMonthBarDataSet;
}
private DefaultCategoryDataset getActivityYearBarDataSet(String siteId) {
// LOG.info("Generating activityYearBarDataSet");
SummaryActivityChartData sac = M_sm.getSummaryActivityChartData(siteId, StatsManager.VIEW_YEAR, StatsManager.CHARTTYPE_BAR);
if(sac == null) return null;
DefaultCategoryDataset activityYearBarDataSet = new DefaultCategoryDataset();
String activity = msgs.getString("legend_activity");
Calendar cal = Calendar.getInstance();
cal.setTime(sac.getFirstDay());
Calendar currMonth = (Calendar) cal.clone();
long activityData[] = sac.getActivity();
for(int i = 0; i < activityData.length; i++){
activityYearBarDataSet.addValue(activityData[i], activity, getMonthNamesMap().get(currMonth.get(Calendar.MONTH)));
currMonth.add(Calendar.MONTH, 1);
}
return activityYearBarDataSet;
}
private AbstractDataset getCategoryDataset(Report report) {
List<Stat> reportData = report.getReportData();
// fill dataset
DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
String dataSource = report.getReportDefinition().getReportParams().getHowChartSource();
String categorySource = report.getReportDefinition().getReportParams().getHowChartCategorySource();
if(StatsManager.T_NONE.equals(categorySource)){
categorySource = null;
}
if(categorySource == null){
// without categories
Set<Comparable> usedKeys = new HashSet<Comparable>();
for(Stat s : reportData){
Comparable key = getStatValue(s, dataSource);
if(key != null) {
if(usedKeys.contains(key)){
dataSet.incrementValue(getTotalValue(s, report).doubleValue(), key, key);
}else{
dataSet.addValue(getTotalValue(s, report), key, key);
usedKeys.add(key);
}
}
}
}else{
// with categories
Map<Comparable, Comparable> usedKeys = new HashMap<Comparable, Comparable>();
for(Stat s : reportData){
Comparable key = getStatValue(s, dataSource);
Comparable cat = getStatValue(s, categorySource);
if(key != null && cat != null) {
if(usedKeys.containsKey(cat) && key.equals(usedKeys.get(cat))){
dataSet.incrementValue(getTotalValue(s, report).doubleValue(), key, cat);
}else{
dataSet.addValue(getTotalValue(s, report), key, cat);
usedKeys.put(cat, key);
}
}
}
// fill missing values with zeros
for(Comparable c : usedKeys.keySet()) {
for(Comparable k : usedKeys.values()) {
if(dataSet.getValue(k, c) == null) {
dataSet.addValue(0, k, c);
}
}
}
}
return dataSet;
}
private AbstractDataset getPieDataset(Report report) {
List<Stat> reportData = report.getReportData();
// fill dataset
DefaultPieDataset dataSet = new DefaultPieDataset();
String dataSource = report.getReportDefinition().getReportParams().getHowChartSource();
//int total = 0;
double total = 0;
for(Stat s : reportData){
Comparable key = getStatValue(s, dataSource);
if(key != null) {
try{
Number existingValue = dataSet.getValue(key);
dataSet.setValue(key, getTotalValue(existingValue, s, report));
total += getTotalValue(s, report).doubleValue();
}catch(UnknownKeyException e){
dataSet.setValue(key, getTotalValue(s, report));
total += getTotalValue(s, report).doubleValue();
}
}
}
// sort
dataSet.sortByValues(SortOrder.DESCENDING);
// fill in final key values in dataset
// show only top values (aggregate remaining in 'others')
int maxDisplayedItems = 10;
int currItem = 1;
Number othersValues = Integer.valueOf(0);
List<Comparable> keys = dataSet.getKeys();
for(Comparable key : keys) {
Number existingValue = dataSet.getValue(key);
if(currItem < maxDisplayedItems) {
// re-compute values
double percentage = (double) existingValue.doubleValue() * 100 / total;
double valuePercentage = Util.round(percentage, (percentage > 0.1) ? 1 : 2 );
// replace key with updated label
StringBuilder keyStr = new StringBuilder(key.toString());
keyStr.append(' ');
keyStr.append(valuePercentage);
keyStr.append("% (");
if((double)existingValue.intValue() == existingValue.doubleValue()) keyStr.append(existingValue.intValue());
else keyStr.append(existingValue.doubleValue());
keyStr.append(")");
dataSet.remove(key);
dataSet.setValue(keyStr.toString(), existingValue);
}else{
othersValues = Integer.valueOf( othersValues.intValue() + existingValue.intValue() );
dataSet.remove(key);
}
currItem++;
}
// compute "Others" value
if(othersValues.intValue() > 0){
double percentage = (double) othersValues.doubleValue() * 100 / total;
double valuePercentage = Util.round(percentage, (percentage > 0.1) ? 1 : 2 );
// replace key with updated label
StringBuilder keyStr = new StringBuilder(msgs.getString("pie_chart_others"));
keyStr.append(' ');
keyStr.append(valuePercentage);
keyStr.append("% (");
if((double)othersValues.intValue() == othersValues.doubleValue()) keyStr.append(othersValues.intValue());
else keyStr.append(othersValues.doubleValue());
keyStr.append(")");
dataSet.setValue(keyStr.toString(), othersValues);
}
return dataSet;
}
private AbstractDataset getTimeSeriesCollectionDataset(Report report) {
List<Stat> reportData = report.getReportData();
// fill dataset
TimeSeriesCollection dataSet = new TimeSeriesCollection();
String dataSource = report.getReportDefinition().getReportParams().getHowChartSource();
String seriesFrom = report.getReportDefinition().getReportParams().getHowChartSeriesSource();
if(StatsManager.T_TOTAL.equals(seriesFrom) || StatsManager.T_NONE.equals(seriesFrom)){
seriesFrom = null;
}
Class periodGrouping = null;
if(StatsManager.CHARTTIMESERIES_DAY.equals(report.getReportDefinition().getReportParams().getHowChartSeriesPeriod())
|| StatsManager.CHARTTIMESERIES_WEEKDAY.equals(report.getReportDefinition().getReportParams().getHowChartSeriesPeriod())) {
periodGrouping = org.jfree.data.time.Day.class;
}else if(StatsManager.CHARTTIMESERIES_MONTH.equals(report.getReportDefinition().getReportParams().getHowChartSeriesPeriod())) {
periodGrouping = org.jfree.data.time.Month.class;
}else if(StatsManager.CHARTTIMESERIES_YEAR.equals(report.getReportDefinition().getReportParams().getHowChartSeriesPeriod())) {
periodGrouping = org.jfree.data.time.Year.class;
}
boolean visitsTotalsChart =
ReportManager.WHAT_VISITS_TOTALS.equals(report.getReportDefinition().getReportParams().getWhat())
|| report.getReportDefinition().getReportParams().getHowTotalsBy().contains(StatsManager.T_VISITS)
|| report.getReportDefinition().getReportParams().getHowTotalsBy().contains(StatsManager.T_UNIQUEVISITS);
Set<RegularTimePeriod> keys = new HashSet<RegularTimePeriod>();
if(!visitsTotalsChart && seriesFrom == null){
// without additional series
String name = msgs.getString("th_total");
TimeSeries ts = new TimeSeries(name, periodGrouping);
for(Stat s : reportData){
RegularTimePeriod key = (RegularTimePeriod) getStatValue(s, dataSource, periodGrouping);
if(key != null) {
Number existing = null;
if((existing = ts.getValue(key)) == null) {
ts.add(key, getTotalValue(s, report));
}else{
ts.addOrUpdate(key, getTotalValue(existing, s, report));
}
keys.add(key);
}
}
dataSet.addSeries(ts);
}else if(!visitsTotalsChart && seriesFrom != null){
// with additional series
Map<Comparable,TimeSeries> series = new HashMap<Comparable,TimeSeries>();
//TimeSeries ts = new TimeSeries(dataSource, org.jfree.data.time.Day.class);
for(Stat s : reportData){
RegularTimePeriod key = (RegularTimePeriod) getStatValue(s, dataSource, periodGrouping);
Comparable serie = (Comparable) getStatValue(s, seriesFrom);
if(key != null && serie != null) {
// determine appropriate serie
TimeSeries ts = null;
if(!series.containsKey(serie)) {
ts = new TimeSeries(serie.toString(), periodGrouping);
series.put(serie, ts);
}else{
ts = series.get(serie);
}
Number existing = null;
if((existing = ts.getValue(key)) == null) {
ts.add(key, getTotalValue(s, report));
}else{
ts.addOrUpdate(key, getTotalValue(existing, s, report));
}
keys.add(key);
}
}
// add series
for(TimeSeries ts : series.values()) {
dataSet.addSeries(ts);
}
}else if(visitsTotalsChart){
// 2 series: visits & unique visitors
TimeSeries tsV = new TimeSeries(msgs.getString("th_visits"), periodGrouping);
TimeSeries tsUV = new TimeSeries(msgs.getString("th_uniquevisitors"), periodGrouping);
for(Stat _s : reportData){
SiteVisits s = (SiteVisits) _s;
RegularTimePeriod key = (RegularTimePeriod) getStatValue(s, dataSource, periodGrouping);
if(key != null) {
Number existing = null;
if((existing = tsV.getValue(key)) == null) {
tsV.add(key, s.getTotalVisits());
tsUV.add(key, s.getTotalUnique());
}else{
tsV.addOrUpdate(key, s.getTotalVisits() + existing.longValue());
tsUV.addOrUpdate(key, s.getTotalVisits() + existing.longValue());
}
keys.add(key);
}
}
dataSet.addSeries(tsV);
dataSet.addSeries(tsUV);
}
// fill missing values with zeros
/*for(TimeSeries ts : (List<TimeSeries>) dataSet.getSeries()) {
for(RegularTimePeriod tp : keys) {
if(ts.getValue(tp) == null) {
ts.add(tp, 0.0);
}
}
}*/
dataSet.setXPosition(TimePeriodAnchor.MIDDLE);
return dataSet;
}
// ################################################################
// Utility Methods
// ################################################################
private static class Day implements Comparable<Object> {
private String dayLabel;
private int day;
public Day(int day, String dayLabel) {
this.day = day;
this.dayLabel = dayLabel;
}
public int getDay() {
return this.day;
}
public String toString() {
return this.dayLabel;
}
public int compareTo(Object o) {
if(!(o instanceof Day))
return -1;
int otherDay = ((Day) o).getDay();
if(day < otherDay)
return -1;
else if(day > otherDay)
return 1;
else return 0;
}
public boolean equals(Object o) {
if(!(o instanceof Day))
return false;
int otherDay = ((Day) o).getDay();
if(day == otherDay)
return true;
else
return false;
}
public int hashCode() {
return getDay();
}
}
private Map<Integer, String> getWeekDaysMap(){
weekDaysMap = new HashMap<Integer, String>();
weekDaysMap.put(Calendar.SUNDAY, msgs.getString("day_sun"));
weekDaysMap.put(Calendar.MONDAY, msgs.getString("day_mon"));
weekDaysMap.put(Calendar.TUESDAY, msgs.getString("day_tue"));
weekDaysMap.put(Calendar.WEDNESDAY, msgs.getString("day_wed"));
weekDaysMap.put(Calendar.THURSDAY, msgs.getString("day_thu"));
weekDaysMap.put(Calendar.FRIDAY, msgs.getString("day_fri"));
weekDaysMap.put(Calendar.SATURDAY, msgs.getString("day_sat"));
return weekDaysMap;
}
private Map<Integer, String> getMonthNamesMap(){
monthNamesMap = new HashMap<Integer, String>();
monthNamesMap.put(Calendar.JANUARY, msgs.getString("mo_jan"));
monthNamesMap.put(Calendar.FEBRUARY, msgs.getString("mo_feb"));
monthNamesMap.put(Calendar.MARCH, msgs.getString("mo_mar"));
monthNamesMap.put(Calendar.APRIL, msgs.getString("mo_apr"));
monthNamesMap.put(Calendar.MAY, msgs.getString("mo_may"));
monthNamesMap.put(Calendar.JUNE, msgs.getString("mo_jun"));
monthNamesMap.put(Calendar.JULY, msgs.getString("mo_jul"));
monthNamesMap.put(Calendar.AUGUST, msgs.getString("mo_ago"));
monthNamesMap.put(Calendar.SEPTEMBER, msgs.getString("mo_sep"));
monthNamesMap.put(Calendar.OCTOBER, msgs.getString("mo_oct"));
monthNamesMap.put(Calendar.NOVEMBER, msgs.getString("mo_nov"));
monthNamesMap.put(Calendar.DECEMBER, msgs.getString("mo_dec"));
return monthNamesMap;
}
private boolean canUseNormalFontSize(int chartWidth) {
return chartWidth >= MIN_CHART_WIDTH_TO_DRAW_ALL_DAYS;
}
private static Color parseColor(String color) {
if(color != null) {
if(color.trim().startsWith("#")){
// HTML colors (#FFFFFF format)
return new Color(Integer.parseInt(color.substring(1), 16));
}else if(color.trim().startsWith("rgb")){
// HTML colors (rgb(255, 255, 255) format)
String values = color.substring(color.indexOf("(") + 1, color.indexOf(")"));
String rgb[] = values.split(",");
return new Color(Integer.parseInt(rgb[0].trim()), Integer.parseInt(rgb[1].trim()), Integer.parseInt(rgb[2].trim()));
}else{
// Colors by name
if(color.equalsIgnoreCase("black")) return Color.black;
if(color.equalsIgnoreCase("grey")) return Color.gray;
if(color.equalsIgnoreCase("yellow")) return Color.yellow;
if(color.equalsIgnoreCase("green")) return Color.green;
if(color.equalsIgnoreCase("blue")) return Color.blue;
if(color.equalsIgnoreCase("red")) return Color.red;
if(color.equalsIgnoreCase("orange")) return Color.orange;
if(color.equalsIgnoreCase("cyan")) return Color.cyan;
if(color.equalsIgnoreCase("magenta")) return Color.magenta;
if(color.equalsIgnoreCase("darkgray")) return Color.darkGray;
if(color.equalsIgnoreCase("lightgray")) return Color.lightGray;
if(color.equalsIgnoreCase("pink")) return Color.pink;
if(color.equalsIgnoreCase("white")) return Color.white;
}
}
LOG.info("Unable to parse body background-color (color:" + color+"). Assuming white.");
return Color.white;
}
//periodGrouping
private Comparable getStatValue(Stat s, String fieldCode) {
return getStatValue(s, fieldCode, org.jfree.data.time.Day.class);
}
private Comparable getStatValue(Stat s, String fieldCode, Class periodGrouping) {
if(fieldCode == null) {
return null;
}
try{
if(fieldCode.equals(StatsManager.T_SITE)) {
String siteId = s.getSiteId();
String title = null;
try{
title = M_ss.getSite(siteId).getTitle();
}catch(IdUnusedException e){
title = siteId;
}
return title;
}else if(fieldCode.equals(StatsManager.T_USER)) {
String userId = s.getUserId();
String name = null;
if (userId != null) {
if(("-").equals(userId)) {
name = msgs.getString("user_anonymous");
}else if(("?").equals(userId)) {
name = msgs.getString("user_anonymous_access");
}else{
name = M_sm.getUserNameForDisplay(userId);
}
}else{
name = msgs.getString("user_unknown");
}
return name;
}else if(fieldCode.equals(StatsManager.T_EVENT)) {
String eventName = "";
if(s instanceof EventStat) {
String eventId = ((EventStat) s).getEventId();
if(!"".equals(eventId)){
eventName = M_ers.getEventName(eventId);
}
}
return eventName;
}else if(fieldCode.equals(StatsManager.T_TOOL)) {
String toolName = "";
if(s instanceof EventStat) {
String toolId = ((EventStat) s).getToolId();
if(!"".equals(toolId)){
toolName = M_ers.getToolName(toolId);
}
}
return toolName;
}else if(fieldCode.equals(StatsManager.T_RESOURCE)) {
if(s instanceof ResourceStat) {
String ref = ((ResourceStat) s).getResourceRef();
String resName = M_sm.getResourceName(ref);
return resName != null ? resName : msgs.getString("resource_unknown");
}else{
return "";
}
}else if(fieldCode.equals(StatsManager.T_RESOURCE_ACTION)) {
String action = "";
if(s instanceof ResourceStat) {
String refAction = ((ResourceStat) s).getResourceAction();
if(refAction == null){
action = "";
}else{
if(!"".equals(refAction.trim()))
action = msgs.getString("action_"+refAction);
}
}
return action;
}else if(fieldCode.equals(StatsManager.T_DATE) || fieldCode.equals(StatsManager.T_LASTDATE)
|| fieldCode.equals(StatsManager.T_DATEMONTH) || fieldCode.equals(StatsManager.T_DATEYEAR)) {
Date d = s.getDate();
if(d != null) {
Calendar c = Calendar.getInstance();
c.setTime(d);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
if(org.jfree.data.time.Year.class.equals(periodGrouping)) {
return new org.jfree.data.time.Year(c.getTime());
}else if(org.jfree.data.time.Month.class.equals(periodGrouping)) {
return new org.jfree.data.time.Month(c.getTime());
}else if(org.jfree.data.time.Week.class.equals(periodGrouping)) {
return new org.jfree.data.time.Week(c.getTime());
}else{
return new org.jfree.data.time.Day(c.getTime());
}
}else{
return null;
}
}else if(fieldCode.equals(StatsManager.T_TOTAL)) {
return s.getCount();
}else if(fieldCode.equals(StatsManager.T_VISITS)) {
if(s instanceof SiteVisits) {
return ((SiteVisits) s).getTotalVisits();
}
return s.getCount();
}else if(fieldCode.equals(StatsManager.T_UNIQUEVISITS)) {
if(s instanceof SiteVisits) {
return ((SiteVisits) s).getTotalUnique();
}
return s.getCount();
}else if(fieldCode.equals(StatsManager.T_DURATION)) {
if(s instanceof SitePresence) {
double duration = (double) ((SitePresence) s).getDuration();
return Util.round(duration / 1000 / 60, 1); // in minutes
}
}
}catch(Exception e) {
LOG.warn("Error occurred while getting value for chart", e);
}
return null;
}
private Number getTotalValue(Stat s, Report r) {
return getTotalValue(null, s, r);
}
private Number getTotalValue(Number existingValue, Stat s, Report r) {
try{
String what = r.getReportDefinition().getReportParams().getWhat();
if(ReportManager.WHAT_VISITS_TOTALS.equals(what)) {
if(s instanceof SiteVisits) {
long totalVisits = ((SiteVisits) s).getTotalVisits();
if(existingValue != null) {
totalVisits += existingValue.longValue();
}
return totalVisits;
}
}else if(ReportManager.WHAT_PRESENCES.equals(what)) {
if(s instanceof SitePresence) {
double duration = (double) ((SitePresence) s).getDuration();
duration = Util.round(duration / 1000 / 60, 1); // in minutes
if(existingValue != null) {
duration += existingValue.doubleValue();
}
return duration;
}
}
long count = s.getCount();
if(existingValue != null) {
count += existingValue.longValue();
}
return count;
}catch(Exception e) {
LOG.warn("Error occurred while getting total value for chart", e);
}
return null;
}
}