package com.github.andlyticsproject.chart;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.achartengine.ChartFactory;
import org.achartengine.chart.BarChart.Type;
import org.achartengine.chart.PointStyle;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;
import org.achartengine.renderer.XYSeriesRenderer;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.View;
import com.github.andlyticsproject.Preferences;
import com.github.andlyticsproject.R;
public class Chart extends AbstractChart {
private static final String TAG = Chart.class.getSimpleName();
private static final boolean DEBUG = false;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public enum ChartSet {
RATINGS, DOWNLOADS, REVENUE, ADMOB
}
/*
* public enum AdmobChartType { REVENUE, EPC,REQUESTS, CLICKS, FILL_RATE,
* ECPM, IMPRESSIONS, CTR, HOUSEAD_CLICKS }
*
* public enum DownloadChartType { TOTAL_DOWNLAODS, ACTIVE_INSTALLS_TOTAL,
* TOTAL_DOWNLAODS_BY_DAY, ACTIVE_INSTALLS_PERCENT }
*
* public enum RatingChartType { AVG_RATING, RATINGS_5, RATINGS_4,
* RATINGS_3, RATINGS_2, RATINGS_1 }
*/
public interface ValueCallbackHander {
double getValue(Object appInfo);
Date getDate(Object appInfo);
boolean isHeilightValue(Object appInfo, Object object);
}
private static final int MAX_BAR_VALUES = Integer.MAX_VALUE;
@SuppressLint("SimpleDateFormat")
public View buildBarChart(Context context, Object[] appstats, ValueCallbackHander handler,
double heighestValue, double lowestValue) {
String[] titles = new String[] { "" };
List<Object> statsForApp = Arrays.asList(appstats);
if (statsForApp.size() > MAX_BAR_VALUES) {
statsForApp = statsForApp.subList(statsForApp.size() - MAX_BAR_VALUES,
statsForApp.size());
}
// styling
int[] colors = new int[] { context.getResources().getColor(R.color.lightBlue) };
XYMultipleSeriesRenderer renderer = buildBarRenderer(colors);
renderer.setOrientation(Orientation.HORIZONTAL);
// get x values (dates) at least 10
List<String> dates = new ArrayList<String>();
int xLabelDistance = 0;
if (statsForApp.size() > 0) {
xLabelDistance = statsForApp.size() / 6;
}
SimpleDateFormat dateFormat = new SimpleDateFormat(
Preferences.getDateFormatStringShort(context));
int nextXLabelPrint = 1;
for (int i = 1; i < statsForApp.size(); i++) {
Object appInfo = statsForApp.get(i);
dates.add(getDateString(handler.getDate(appInfo)));
if (i == nextXLabelPrint) {
renderer.addXTextLabel(i, dateFormat.format(handler.getDate(appInfo)));
nextXLabelPrint += xLabelDistance;
}
}
double[] valuesArray = new double[dates.size()];
for (int i = 1; i < statsForApp.size(); i++) {
Object appInfoPrev = statsForApp.get(i);
double value = handler.getValue(appInfoPrev);
valuesArray[i - 1] = value;
if (value > heighestValue) {
heighestValue = value;
}
if (value < lowestValue) {
lowestValue = value;
}
}
List<double[]> values = new ArrayList<double[]>();
values.add(valuesArray);
// values.add(activeArray);
// long dateDistance = datesArray[datesArray.length - 1].getTime() -
// datesArray[0].getTime();
// dateDistance = (long) (dateDistance * .1f);
double valueDistance = heighestValue - lowestValue;
double valueDistanceTop = heighestValue + (valueDistance * .2f);
double valueDistanceBottom = lowestValue - (valueDistance * .1f);
if (heighestValue == lowestValue) {
valueDistanceTop = lowestValue + (lowestValue / 2);
valueDistanceBottom = lowestValue / 2;
}
// settings
setChartSettings(context.getResources(), renderer, "", "", "", 0, statsForApp.size(),
valueDistanceBottom, valueDistanceTop, Color.LTGRAY, Color.BLACK);
renderer.setYLabels(7);
renderer.setXLabels(-1);
renderer.setShowLegend(false);
renderer.setShowAxes(false);
renderer.setShowGrid(true);
renderer.setAntialiasing(true);
return ChartFactory.getBarChartView(context, buildBarDataset(titles, values), renderer,
Type.DEFAULT);
}
public View buildLineChart(Context context, Object[] stats, ValueCallbackHander handler) {
String[] titles = new String[] { "" };
List<Object> statsForApp = Arrays.asList(stats);
// get x values (dates) at least 10
List<Date> dates = new ArrayList<Date>();
List<Date> highlightDates = new ArrayList<Date>();
for (int i = 0; i < statsForApp.size(); i++) {
Object appInfo = statsForApp.get(i);
Calendar calendar = Calendar.getInstance();
calendar.setTime(handler.getDate(appInfo));
calendar.set(Calendar.HOUR_OF_DAY, 0);
dates.add(calendar.getTime());
if (i > 0) {
boolean highlight = handler.isHeilightValue(appInfo, statsForApp.get(i - 1));
if (highlight) {
highlightDates.add(calendar.getTime());
}
}
}
Date[] datesArray = dates.toArray(new Date[dates.size()]);
double[] valuesArray = new double[dates.size()];
double[] highlightValuesArray = new double[highlightDates.size()];
// This could break something, but we don't (?) use negative
// stats, so should be OK. Passing Double.MIN_VALUE to achartengine
// crashes Android, so not a good idea to use it. Cf. #464
double highestValue = 0;//Double.MIN_VALUE;
double lowestValue = Double.MAX_VALUE;
for (int i = 0; i < statsForApp.size(); i++) {
Object appInfo = statsForApp.get(i);
double value = handler.getValue(appInfo);
valuesArray[i] = value;
if (value > highestValue) {
highestValue = value;
}
if (value < lowestValue) {
lowestValue = value;
}
int indexOf = highlightDates.indexOf(handler.getDate(appInfo));
if (indexOf > -1) {
highlightValuesArray[indexOf] = value;
}
}
if (DEBUG) {
for (int i = 0; i < datesArray.length; i++) {
Log.d(TAG, String.format("%s->%f", datesArray[i].toString(), valuesArray[i]));
}
Log.d(TAG, "*********************************************************");
Log.d(TAG, String.format("high=%f, low=%f", highestValue, lowestValue));
Log.d(TAG, "*********************************************************");
}
List<Date[]> dateArrayList = new ArrayList<Date[]>();
dateArrayList.add(datesArray);
// dateArrayList.add(datesArray);
List<double[]> values = new ArrayList<double[]>();
values.add(valuesArray);
// values.add(activeArray);
// styling
int[] colors = new int[] { context.getResources().getColor(R.color.lightBlue) };
PointStyle pointStye = valuesArray.length > 30 ? PointStyle.POINT : PointStyle.CIRCLE;
PointStyle[] styles = new PointStyle[] { pointStye };
XYMultipleSeriesRenderer renderer = buildRenderer(colors, styles);
int length = renderer.getSeriesRendererCount();
for (int i = 0; i < length; i++) {
((XYSeriesRenderer) renderer.getSeriesRendererAt(i)).setFillPoints(true);
}
long dateDistance = datesArray[datesArray.length - 1].getTime() - datesArray[0].getTime();
dateDistance = (long) (dateDistance * .1f);
double valueDistance = highestValue - lowestValue;
double valueDistanceTop = highestValue + (valueDistance * .2f);
double valueDistanceBottom = lowestValue - (valueDistance * .1f);
if (highestValue == lowestValue) {
valueDistanceTop = lowestValue + (lowestValue / 2);
valueDistanceBottom = lowestValue / 2;
}
// settings
setChartSettings(context.getResources(), renderer, "", "", "", datesArray[0].getTime()
- dateDistance, datesArray[datesArray.length - 1].getTime() + dateDistance,
valueDistanceBottom, valueDistanceTop, Color.LTGRAY, Color.BLACK);
renderer.setYLabels(5);
renderer.setXLabels(10);
renderer.setShowLegend(false);
renderer.setShowAxes(false);
renderer.setShowGrid(true);
renderer.setAntialiasing(true);
return ChartFactory.getTimeChartView(context,
buildDateDataset(titles, dateArrayList, values), renderer,
Preferences.getDateFormatStringShort(context));
}
public String getDateString(Date date) {
return dateFormat.format(date);
}
}