0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-20 12:02:16 +02:00

removed dependencies of old statistics in NavigationDrawerActivity and StudyOptionsFragment, removed achartengine and old CharBuilder class,

added transparency to some statistic graphs, changed "select deck" icon in statistics
This commit is contained in:
Michael Goldbach 2014-07-25 01:12:10 +02:00
parent f13736714e
commit ff0ea64521
58 changed files with 37 additions and 10117 deletions

View File

@ -5,7 +5,7 @@
<item android:id="@+id/action_deck_spinner"
android:title="@string/stats_select_decks"
android:icon="@drawable/ic_action_action_settings"
android:icon="@drawable/ic_action_storage"
app:showAsAction="ifRoom"/>
<item android:id="@+id/action_time_spinner"
android:title="@string/stats_select_time_scale"

View File

@ -41,7 +41,6 @@ import com.ichi2.anim.ActivityTransitionAnimation;
import com.ichi2.anki.stats.AnkiStatsActivity;
import com.ichi2.anki.stats.AnkiStatsTaskHandler;
import com.ichi2.async.DeckTask;
import com.ichi2.charts.ChartBuilder;
import com.ichi2.themes.StyledProgressDialog;
@ -261,51 +260,7 @@ public class NavigationDrawerActivity extends AnkiActivity {
}
/* Members not related directly to navigation drawer */
// Statistics
DeckTask.TaskListener mLoadStatisticsHandler = new DeckTask.TaskListener() {
@Override
public void onPostExecute(DeckTask.TaskData result) {
if (mProgressDialog.isShowing()) {
try {
mProgressDialog.dismiss();
} catch (Exception e) {
Log.e(AnkiDroidApp.TAG, "onPostExecute - Dialog dismiss Exception = " + e.getMessage());
}
}
if (result.getBoolean()) {
// if (mStatisticType == Statistics.TYPE_DECK_SUMMARY) {
// Statistics.showDeckSummary(DeckPicker.this);
// } else {
Intent intent = new Intent(NavigationDrawerActivity.this, com.ichi2.charts.ChartBuilder.class);
startActivityWithAnimation(intent, ActivityTransitionAnimation.DOWN);
// }
} else {
// TODO: db error handling
}
}
@Override
public void onPreExecute() {
mProgressDialog = StyledProgressDialog.show(NavigationDrawerActivity.this, "",
getResources().getString(R.string.calculating_statistics), true);
}
@Override
public void onProgressUpdate(DeckTask.TaskData... values) {
}
@Override
public void onCancelled() {
// TODO Auto-generated method stub
}
};
@Override
protected void onDestroy() {
super.onDestroy();

View File

@ -54,7 +54,7 @@ import com.ichi2.anki.stats.AnkiStatsTaskHandler;
import com.ichi2.anki.stats.ChartView;
import com.ichi2.async.DeckTask;
import com.ichi2.async.DeckTask.TaskData;
import com.ichi2.charts.ChartBuilder;
import com.ichi2.libanki.Collection;
import com.ichi2.libanki.Consts;
import com.ichi2.libanki.Stats;
@ -64,13 +64,6 @@ import com.ichi2.themes.StyledOpenCollectionDialog;
import com.ichi2.themes.StyledProgressDialog;
import com.ichi2.themes.Themes;
import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.BarChart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -857,13 +850,15 @@ public class StudyOptionsFragment extends Fragment {
switch (id) {
case DIALOG_STATISTIC_TYPE:
dialog = ChartBuilder.getStatisticsDialog(getActivity(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
DeckTask.launchDeckTask(DeckTask.TASK_TYPE_LOAD_STATISTICS, mLoadStatisticsHandler,
new DeckTask.TaskData(AnkiDroidApp.getCol(), which, false));
boolean selectAllDecksButton = false;
if(!(getActivity() instanceof AnkiStatsActivity)) {
if ((getActivity() instanceof DeckPicker && !mFragmented)) {
selectAllDecksButton = true;
}
}, mFragmented);
AnkiStatsTaskHandler.setIsWholeCollection(selectAllDecksButton);
Intent intent = new Intent(getActivity(), AnkiStatsActivity.class);
startActivity(intent);
}
break;
case DIALOG_CUSTOM_STUDY:
@ -1358,46 +1353,6 @@ public class StudyOptionsFragment extends Fragment {
}
};
DeckTask.TaskListener mLoadStatisticsHandler = new DeckTask.TaskListener() {
@Override
public void onPostExecute(DeckTask.TaskData result) {
dismissProgressDialog();
if (result.getBoolean()) {
// if (mStatisticType == Statistics.TYPE_DECK_SUMMARY) {
// Statistics.showDeckSummary(getActivity());
// } else {
Intent intent = new Intent(getActivity(), com.ichi2.charts.ChartBuilder.class);
startActivityForResult(intent, STATISTICS);
ActivityTransitionAnimation.slide(getActivity(), ActivityTransitionAnimation.DOWN);
// }
} else {
// TODO: db error handling
}
}
@Override
public void onPreExecute() {
mProgressDialog = StyledProgressDialog.show(getActivity(), "",
getResources().getString(R.string.calculating_statistics), true);
}
@Override
public void onProgressUpdate(DeckTask.TaskData... values) {
}
@Override
public void onCancelled() {
// TODO Auto-generated method stub
}
};
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
@ -1413,12 +1368,6 @@ public class StudyOptionsFragment extends Fragment {
&& Math.abs(e1.getY() - e2.getY()) < AnkiDroidApp.sSwipeMaxOffPath) {
// right
closeStudyOptions();
} else if (e2.getY() - e1.getY() > AnkiDroidApp.sSwipeMinDistance
&& Math.abs(velocityY) > AnkiDroidApp.sSwipeThresholdVelocity
&& Math.abs(e1.getX() - e2.getX()) < AnkiDroidApp.sSwipeMaxOffPath) {
// down
DeckTask.launchDeckTask(DeckTask.TASK_TYPE_LOAD_STATISTICS, mLoadStatisticsHandler,
new DeckTask.TaskData(AnkiDroidApp.getCol(), Stats.TYPE_FORECAST, false));
} else if (e1.getY() - e2.getY() > AnkiDroidApp.sSwipeMinDistance
&& Math.abs(velocityY) > AnkiDroidApp.sSwipeThresholdVelocity
&& Math.abs(e1.getX() - e2.getX()) < AnkiDroidApp.sSwipeMaxOffPath) {

View File

@ -242,8 +242,10 @@ public class AnkiStatsActivity extends NavigationDrawerActivity implements Actio
builder.setView(view);
builder.setTitle(getResources().getString(R.string.stats_select_time_scale));
mTimeSpinner = (Spinner)((RelativeLayout)view).getChildAt(0);
mTimeSpinner.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
getResources().getStringArray(R.array.stats_period)));
ArrayAdapter<String> timeFrameAdapter =new ArrayAdapter<String>(this,R.layout.drawer_list_item,
R.id.drawer_list_item_text, getResources().getStringArray(R.array.stats_period));
mTimeSpinner.setAdapter(timeFrameAdapter);
mTimeSpinner.setSelection(mTaskHandler.getStatType(), false);
final int currentStatType = mSelectedStatType;

View File

@ -35,6 +35,7 @@ public class ChartBuilder {
private ChartView mChartView;
private Collection mCollectionData;
private int mDesiredPixelDistanceBetweenTicks = 200;
private float barOpacity = 0.7f;
private int mFrameThickness = 60;
@ -204,12 +205,23 @@ public class ChartBuilder {
barThickness = 0.2;
}
}
ColorWrap color;
switch (mChartType){
case ANSWER_BUTTONS:
case HOURLY_BREAKDOWN:
case WEEKLY_BREAKDOWN:
case INTERVALS:
color =new ColorWrap(mChartView.getResources().getColor(mColors[i-1]), barOpacity);
break;
default:
color =new ColorWrap(mChartView.getResources().getColor(mColors[i-1]));
}
BarGraph barGraph = new BarGraph(usedPlotSheet, barThickness, bars, new ColorWrap(mChartView.getResources().getColor(mColors[i-1])));
BarGraph barGraph = new BarGraph(usedPlotSheet, barThickness, bars, color);
barGraph.setFilling(true);
barGraph.setName(mChartView.getResources().getString(mValueLabels[i - 1]));
//barGraph.setFillColor(Color.GREEN.darker());
barGraph.setFillColor(new ColorWrap(mChartView.getResources().getColor(mColors[i - 1])));
barGraph.setFillColor(color);
plotSheet.addDrawable(barGraph);
}
}

View File

@ -1,369 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
* Copyright (C) 2011 Norbert Nagold <norbert.nagold@gmail.com>
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.ichi2.charts;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Paint.Align;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import com.ichi2.anim.ActivityTransitionAnimation;
import com.ichi2.anki.AnkiDroidApp;
import com.ichi2.anki.R;
import com.ichi2.libanki.Stats;
import com.ichi2.themes.StyledDialog;
import com.ichi2.themes.Themes;
import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.BarChart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
public class ChartBuilder extends ActionBarActivity {
public static final String TYPE = "type";
private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
private XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
private GraphicalView mChartView;
private double[] mPan;
private double[][] mSeriesList;
private Object[] mMeta;
/**
* Swipe Detection
*/
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
private boolean mSwipeEnabled;
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
int len = mSeriesList.length;
outState.putInt("seriesListLen", len);
for (int i = 0; i < len; i++) {
outState.putSerializable("seriesList" + i, mSeriesList[i]);
}
outState.putSerializable("meta", mMeta);
}
public void closeChartBuilder() {
finish();
ActivityTransitionAnimation.slide(this, ActivityTransitionAnimation.UP);
}
private SharedPreferences restorePreferences() {
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
mSwipeEnabled = preferences.getBoolean("gestures", false);
return preferences;
}
// public void setRenderer(int type, int row) {
// Resources res = getResources();
// XYSeriesRenderer renderer = new XYSeriesRenderer();
// if (type <= 2) {
// switch (row) {
// case 0:
// renderer.setColor(res.getColor(R.color.statistics_due_young_cards));
// break;
// case 1:
// renderer.setColor(res.getColor(R.color.statistics_due_mature_cards));
// break;
// case 2:
// // renderer.setColor(res.getColor(R.color.statistics_due_failed_cards));
// break;
// }
// } else if (type == 3) {
// switch (row) {
// case 0:
// // renderer.setColor(res.getColor(R.color.statistics_reps_new_cards));
// break;
// case 1:
// renderer.setColor(res.getColor(R.color.statistics_reps_young_cards));
// break;
// case 2:
// renderer.setColor(res.getColor(R.color.statistics_reps_mature_cards));
// break;
// }
// } else {
// renderer.setColor(res.getColor(R.color.statistics_default));
// }
// mRenderer.addSeriesRenderer(renderer);
// }
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(AnkiDroidApp.TAG, "ChartBuilder.OnCreate");
Themes.applyTheme(this);
super.onCreate(savedInstanceState);
restorePreferences();
Resources res = getResources();
Stats stats = Stats.currentStats();
if (stats != null) {
mSeriesList = stats.getSeriesList();
mMeta = stats.getMetaInfo();
} else if (savedInstanceState != null) {
int len = savedInstanceState.getInt("seriesListLen");
mSeriesList = new double[len][];
for (int i = 0; i < len; i++) {
mSeriesList[i] = (double[]) savedInstanceState.getSerializable("seriesList" + i);
}
mMeta = (Object[]) savedInstanceState.getSerializable("meta");
} else {
finish();
}
String title = res.getString((Integer) mMeta[1]);
boolean backwards = (Boolean) mMeta[2];
int[] valueLabels = (int[]) mMeta[3];
int[] barColors = (int[]) mMeta[4];
int[] axisTitles = (int[]) mMeta[5];
String subTitle = (String) mMeta[6];
if (mSeriesList == null || mSeriesList[0].length < 2) {
Log.i(AnkiDroidApp.TAG, "ChartBuilder - Data variable empty, closing chartbuilder");
finish();
return;
}
View mainView = getLayoutInflater().inflate(R.layout.statistics, null);
setContentView(mainView);
mainView.setBackgroundColor(Color.WHITE);
if (mChartView == null) {
setTitle(title);
AnkiDroidApp.getCompat().setSubtitle(this, subTitle);
for (int i = 1; i < mSeriesList.length; i++) {
XYSeries series = new XYSeries(res.getString(valueLabels[i - 1]));
for (int j = 0; j < mSeriesList[i].length; j++) {
series.add(mSeriesList[0][j], mSeriesList[i][j]);
}
mDataset.addSeries(series);
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setColor(res.getColor(barColors[i - 1]));
mRenderer.addSeriesRenderer(renderer);
}
if (mSeriesList.length == 1) {
mRenderer.setShowLegend(false);
}
if (backwards) {
mPan = new double[] { mSeriesList[0][0] - 0.5, 0.5 };
} else {
mPan = new double[] { -0.5, mSeriesList[0][mSeriesList[0].length - 1] + 0.5 };
}
mRenderer.setLegendTextSize(17);
mRenderer.setBarSpacing(0.4);
mRenderer.setLegendHeight(60);
mRenderer.setAxisTitleTextSize(17);
mRenderer.setLabelsTextSize(17);
mRenderer.setXAxisMin(mPan[0]);
mRenderer.setXAxisMax(mPan[1]);
mRenderer.setYAxisMin(0);
mRenderer.setGridColor(Color.LTGRAY);
mRenderer.setShowGrid(true);
mRenderer.setXTitle(res.getStringArray(R.array.due_x_axis_title)[axisTitles[0]]);
mRenderer.setYTitle(res.getString(axisTitles[1]));
mRenderer.setBackgroundColor(Color.WHITE);
mRenderer.setMarginsColor(Color.WHITE);
mRenderer.setAxesColor(Color.BLACK);
mRenderer.setLabelsColor(Color.BLACK);
mRenderer.setYLabelsColor(0, Color.BLACK);
mRenderer.setYLabelsAngle(-90);
mRenderer.setXLabelsColor(Color.BLACK);
mRenderer.setXLabelsAlign(Align.CENTER);
mRenderer.setYLabelsAlign(Align.CENTER);
mRenderer.setZoomEnabled(false, false);
mRenderer.setMargins(new int[] { 15, 48, 30, 10 });
mRenderer.setAntialiasing(true);
mRenderer.setPanEnabled(true, false);
mRenderer.setPanLimits(mPan);
mChartView = ChartFactory.getBarChartView(this, mDataset, mRenderer, BarChart.Type.STACKED);
FrameLayout layout = (FrameLayout) findViewById(R.id.chart);
layout.addView(mChartView);
} else {
mChartView.repaint();
}
gestureDetector = new GestureDetector(new MyGestureDetector());
mChartView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
Log.i(AnkiDroidApp.TAG, "ChartBuilder - onBackPressed()");
closeChartBuilder();
}
return super.onKeyDown(keyCode, event);
}
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mSwipeEnabled) {
try {
if (e1.getY() - e2.getY() > AnkiDroidApp.sSwipeMinDistance
&& Math.abs(velocityY) > AnkiDroidApp.sSwipeThresholdVelocity
&& Math.abs(e1.getX() - e2.getX()) < AnkiDroidApp.sSwipeMaxOffPath) {
closeChartBuilder();
}
} catch (Exception e) {
Log.e(AnkiDroidApp.TAG, "onFling Exception = " + e.getMessage());
}
}
return false;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
public static StyledDialog getStatisticsDialog(Context context, DialogInterface.OnClickListener listener,
boolean setWholeDeckSelection) {
StyledDialog.Builder builder = new StyledDialog.Builder(context);
builder.setTitle(context.getString(R.string.statistics_type_title));
builder.setIcon(android.R.drawable.ic_menu_sort_by_size);
// set items
String[] items = new String[3];
items[0] = context.getResources().getString(R.string.stats_forecast);
items[1] = context.getResources().getString(R.string.stats_review_count);
items[2] = context.getResources().getString(R.string.stats_review_time);
builder.setItems(items, listener);
// period selection
final RadioButton[] statisticRadioButtons = new RadioButton[3];
RadioGroup rg = new RadioGroup(context);
rg.setOrientation(RadioGroup.HORIZONTAL);
RadioGroup.LayoutParams lp = new RadioGroup.LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
Resources res = context.getResources();
String[] text = res.getStringArray(R.array.stats_period);
int height = context.getResources().getDrawable(R.drawable.white_btn_radio).getIntrinsicHeight();
// workaround for text overlapping radiobutton.
// It appears that when API Level is <= 16, the text would overlap the radio button, hence the
// addition of spaces.
String spaces = "";
if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.JELLY_BEAN) {
spaces = " ";
}
for (int i = 0; i < statisticRadioButtons.length; i++) {
statisticRadioButtons[i] = new RadioButton(context);
statisticRadioButtons[i].setClickable(true);
statisticRadioButtons[i].setText(spaces + text[i]);
statisticRadioButtons[i].setHeight(height * 2);
statisticRadioButtons[i].setSingleLine();
statisticRadioButtons[i].setBackgroundDrawable(null);
statisticRadioButtons[i].setGravity(Gravity.CENTER_VERTICAL);
rg.addView(statisticRadioButtons[i], lp);
}
rg.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup arg0, int arg1) {
int checked = arg0.getCheckedRadioButtonId();
for (int i = 0; i < 3; i++) {
if (arg0.getChildAt(i).getId() == checked) {
AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit()
.putInt("statsType", i).commit();
break;
}
}
}
});
rg.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, height));
statisticRadioButtons[Math.min(
AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).getInt("statsType",
Stats.TYPE_MONTH), Stats.TYPE_LIFE)].setChecked(true);
// collection/current deck
final RadioButton[] statisticRadioButtons2 = new RadioButton[2];
RadioGroup rg2 = new RadioGroup(context);
rg2.setOrientation(RadioGroup.HORIZONTAL);
String[] text2 = res.getStringArray(R.array.stats_range);
for (int i = 0; i < statisticRadioButtons2.length; i++) {
statisticRadioButtons2[i] = new RadioButton(context);
statisticRadioButtons2[i].setClickable(true);
statisticRadioButtons2[i].setText(" " + text2[i]);
statisticRadioButtons2[i].setHeight(height * 2);
statisticRadioButtons2[i].setSingleLine();
statisticRadioButtons2[i].setBackgroundDrawable(null);
statisticRadioButtons2[i].setGravity(Gravity.CENTER_VERTICAL);
rg2.addView(statisticRadioButtons2[i], lp);
}
rg2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup arg0, int arg1) {
AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit()
.putBoolean("statsRange", arg0.getCheckedRadioButtonId() == arg0.getChildAt(0).getId())
.commit();
}
});
rg2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, height));
statisticRadioButtons2[AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).getBoolean(
"statsRange", true) ? 0 : 1].setChecked(true);
// Make the by deck button selected by default if arg specified
if (setWholeDeckSelection) {
rg2.check(rg2.getChildAt(0).getId());
} else {
rg2.check(rg2.getChildAt(1).getId());
}
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.VERTICAL);
ll.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
ll.addView(rg);
ll.addView(rg2);
builder.setView(ll, false, true);
return builder.create();
}
}

View File

@ -56,6 +56,15 @@ public class ColorWrap {
super();
this.colorValue = colorValue;
}
public ColorWrap(int colorValue, float af) {
super();
int a = Math.round(af * 255);
int r = android.graphics.Color.red(colorValue);
int g = android.graphics.Color.green(colorValue);
int b = android.graphics.Color.blue(colorValue);
this.colorValue = android.graphics.Color.argb(a, r, g, b);
}
public ColorWrap(int r, int g, int b){
this.colorValue = android.graphics.Color.rgb(r, g, b);

View File

@ -1,708 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine;
import org.achartengine.chart.BarChart;
import org.achartengine.chart.BarChart.Type;
import org.achartengine.chart.BubbleChart;
import org.achartengine.chart.CombinedXYChart;
import org.achartengine.chart.CubicLineChart;
import org.achartengine.chart.DialChart;
import org.achartengine.chart.DoughnutChart;
import org.achartengine.chart.LineChart;
import org.achartengine.chart.PieChart;
import org.achartengine.chart.RangeBarChart;
import org.achartengine.chart.ScatterChart;
import org.achartengine.chart.TimeChart;
import org.achartengine.chart.XYChart;
import org.achartengine.model.CategorySeries;
import org.achartengine.model.MultipleCategorySeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.DialRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import android.content.Context;
import android.content.Intent;
/**
* Utility methods for creating chart views or intents.
*/
public class ChartFactory {
/** The key for the chart data. */
public static final String CHART = "chart";
/** The key for the chart graphical activity title. */
public static final String TITLE = "title";
private ChartFactory() {
// empty for now
}
/**
* Creates a line chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a line chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getLineChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
checkParameters(dataset, renderer);
XYChart chart = new LineChart(dataset, renderer);
return new GraphicalView(context, chart);
}
/**
* Creates a cubic line chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a line chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getCubeLineChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {
checkParameters(dataset, renderer);
XYChart chart = new CubicLineChart(dataset, renderer, smoothness);
return new GraphicalView(context, chart);
}
/**
* Creates a scatter chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a scatter chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getScatterChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
checkParameters(dataset, renderer);
XYChart chart = new ScatterChart(dataset, renderer);
return new GraphicalView(context, chart);
}
/**
* Creates a bubble chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a scatter chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getBubbleChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
checkParameters(dataset, renderer);
XYChart chart = new BubbleChart(dataset, renderer);
return new GraphicalView(context, chart);
}
/**
* Creates a time chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param format the date format pattern to be used for displaying the X axis
* date labels. If null, a default appropriate format will be used.
* @return a time chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getTimeChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String format) {
checkParameters(dataset, renderer);
TimeChart chart = new TimeChart(dataset, renderer);
chart.setDateFormat(format);
return new GraphicalView(context, chart);
}
/**
* Creates a bar chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param type the bar chart type
* @return a bar chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getBarChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
checkParameters(dataset, renderer);
XYChart chart = new BarChart(dataset, renderer, type);
return new GraphicalView(context, chart);
}
/**
* Creates a range bar chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param type the range bar chart type
* @return a bar chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final GraphicalView getRangeBarChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
checkParameters(dataset, renderer);
XYChart chart = new RangeBarChart(dataset, renderer, type);
return new GraphicalView(context, chart);
}
/**
* Creates a combined XY chart view.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param types the chart types (cannot be null)
* @return a combined XY chart graphical view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if a dataset number of items is different than the number of
* series renderers or number of chart types
*/
public static final GraphicalView getCombinedXYChartView(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types) {
if (dataset == null || renderer == null || types == null
|| dataset.getSeriesCount() != types.length) {
throw new IllegalArgumentException(
"Dataset, renderer and types should be not null and the datasets series count should be equal to the types length");
}
checkParameters(dataset, renderer);
CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);
return new GraphicalView(context, chart);
}
/**
* Creates a pie chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the category series dataset (cannot be null)
* @param renderer the series renderer (cannot be null)
* @return a pie chart view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
public static final GraphicalView getPieChartView(Context context, CategorySeries dataset,
DefaultRenderer renderer) {
checkParameters(dataset, renderer);
PieChart chart = new PieChart(dataset, renderer);
return new GraphicalView(context, chart);
}
/**
* Creates a dial chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the category series dataset (cannot be null)
* @param renderer the dial renderer (cannot be null)
* @return a pie chart view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
public static final GraphicalView getDialChartView(Context context, CategorySeries dataset,
DialRenderer renderer) {
checkParameters(dataset, renderer);
DialChart chart = new DialChart(dataset, renderer);
return new GraphicalView(context, chart);
}
/**
* Creates a doughnut chart intent that can be used to start the graphical
* view activity.
*
* @param context the context
* @param dataset the multiple category series dataset (cannot be null)
* @param renderer the series renderer (cannot be null)
* @return a pie chart view
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
public static final GraphicalView getDoughnutChartView(Context context,
MultipleCategorySeries dataset, DefaultRenderer renderer) {
checkParameters(dataset, renderer);
DoughnutChart chart = new DoughnutChart(dataset, renderer);
return new GraphicalView(context, chart);
}
/**
*
* Creates a line chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a line chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
return getLineChartIntent(context, dataset, renderer, "");
}
/**
*
* Creates a cubic line chart intent that can be used to start the graphical
* view activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a line chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getCubicLineChartIntent(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {
return getCubicLineChartIntent(context, dataset, renderer, smoothness, "");
}
/**
* Creates a scatter chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a scatter chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getScatterChartIntent(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
return getScatterChartIntent(context, dataset, renderer, "");
}
/**
* Creates a bubble chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @return a scatter chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getBubbleChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
return getBubbleChartIntent(context, dataset, renderer, "");
}
/**
* Creates a time chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param format the date format pattern to be used for displaying the X axis
* date labels. If null, a default appropriate format will be used.
* @return a time chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer, String format) {
return getTimeChartIntent(context, dataset, renderer, format, "");
}
/**
* Creates a bar chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param type the bar chart type
* @return a bar chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getBarChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer, Type type) {
return getBarChartIntent(context, dataset, renderer, type, "");
}
/**
* Creates a line chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param activityTitle the graphical chart activity title. If this is null,
* then the title bar will be hidden. If a blank title is passed in,
* then the title bar will be the default. Pass in any other string
* to set a custom title.
* @return a line chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
XYChart chart = new LineChart(dataset, renderer);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a line chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param activityTitle the graphical chart activity title. If this is null,
* then the title bar will be hidden. If a blank title is passed in,
* then the title bar will be the default. Pass in any other string
* to set a custom title.
* @return a line chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getCubicLineChartIntent(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness,
String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
XYChart chart = new CubicLineChart(dataset, renderer, smoothness);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a scatter chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param activityTitle the graphical chart activity title
* @return a scatter chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getScatterChartIntent(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
XYChart chart = new ScatterChart(dataset, renderer);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a bubble chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param activityTitle the graphical chart activity title
* @return a scatter chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getBubbleChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
XYChart chart = new BubbleChart(dataset, renderer);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a time chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param format the date format pattern to be used for displaying the X axis
* date labels. If null, a default appropriate format will be used
* @param activityTitle the graphical chart activity title
* @return a time chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer, String format, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
TimeChart chart = new TimeChart(dataset, renderer);
chart.setDateFormat(format);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a bar chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param type the bar chart type
* @param activityTitle the graphical chart activity title
* @return a bar chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getBarChartIntent(Context context, XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer, Type type, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
BarChart chart = new BarChart(dataset, renderer, type);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a range bar chart intent that can be used to start the graphical
* view activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param type the range bar chart type
* @param activityTitle the graphical chart activity title
* @return a range bar chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
public static final Intent getRangeBarChartIntent(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type,
String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
RangeBarChart chart = new RangeBarChart(dataset, renderer, type);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a combined XY chart intent that can be used to start the graphical
* view activity.
*
* @param context the context
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @param types the chart types (cannot be null)
* @param activityTitle the graphical chart activity title
* @return a combined XY chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if a dataset number of items is different than the number of
* series renderers or number of chart types
*/
public static final Intent getCombinedXYChartIntent(Context context,
XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types,
String activityTitle) {
if (dataset == null || renderer == null || types == null
|| dataset.getSeriesCount() != types.length) {
throw new IllegalArgumentException(
"Datasets, renderers and types should be not null and the datasets series count should be equal to the types length");
}
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a pie chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the category series dataset (cannot be null)
* @param renderer the series renderer (cannot be null)
* @param activityTitle the graphical chart activity title
* @return a pie chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
public static final Intent getPieChartIntent(Context context, CategorySeries dataset,
DefaultRenderer renderer, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
PieChart chart = new PieChart(dataset, renderer);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a doughnut chart intent that can be used to start the graphical
* view activity.
*
* @param context the context
* @param dataset the multiple category series dataset (cannot be null)
* @param renderer the series renderer (cannot be null)
* @param activityTitle the graphical chart activity title
* @return a pie chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
public static final Intent getDoughnutChartIntent(Context context,
MultipleCategorySeries dataset, DefaultRenderer renderer, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
DoughnutChart chart = new DoughnutChart(dataset, renderer);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Creates a dial chart intent that can be used to start the graphical view
* activity.
*
* @param context the context
* @param dataset the category series dataset (cannot be null)
* @param renderer the dial renderer (cannot be null)
* @param activityTitle the graphical chart activity title
* @return a dial chart intent
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
public static final Intent getDialChartIntent(Context context, CategorySeries dataset,
DialRenderer renderer, String activityTitle) {
checkParameters(dataset, renderer);
Intent intent = new Intent(context, GraphicalActivity.class);
DialChart chart = new DialChart(dataset, renderer);
intent.putExtra(CHART, chart);
intent.putExtra(TITLE, activityTitle);
return intent;
}
/**
* Checks the validity of the dataset and renderer parameters.
*
* @param dataset the multiple series dataset (cannot be null)
* @param renderer the multiple series renderer (cannot be null)
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset and the renderer don't include the same number of
* series
*/
private static void checkParameters(XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
if (dataset == null || renderer == null
|| dataset.getSeriesCount() != renderer.getSeriesRendererCount()) {
throw new IllegalArgumentException(
"Dataset and renderer should be not null and should have the same number of series");
}
}
/**
* Checks the validity of the dataset and renderer parameters.
*
* @param dataset the category series dataset (cannot be null)
* @param renderer the series renderer (cannot be null)
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
private static void checkParameters(CategorySeries dataset, DefaultRenderer renderer) {
if (dataset == null || renderer == null
|| dataset.getItemCount() != renderer.getSeriesRendererCount()) {
throw new IllegalArgumentException(
"Dataset and renderer should be not null and the dataset number of items should be equal to the number of series renderers");
}
}
/**
* Checks the validity of the dataset and renderer parameters.
*
* @param dataset the category series dataset (cannot be null)
* @param renderer the series renderer (cannot be null)
* @throws IllegalArgumentException if dataset is null or renderer is null or
* if the dataset number of items is different than the number of
* series renderers
*/
private static void checkParameters(MultipleCategorySeries dataset, DefaultRenderer renderer) {
if (dataset == null || renderer == null
|| !checkMultipleSeriesItems(dataset, renderer.getSeriesRendererCount())) {
throw new IllegalArgumentException(
"Titles and values should be not null and the dataset number of items should be equal to the number of series renderers");
}
}
private static boolean checkMultipleSeriesItems(MultipleCategorySeries dataset, int value) {
int count = dataset.getCategoriesCount();
boolean equal = true;
for (int k = 0; k < count && equal; k++) {
equal = dataset.getValues(k).length == dataset.getTitles(k).length;
}
return equal;
}
}

View File

@ -1,48 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine;
import org.achartengine.chart.AbstractChart;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
/**
* An activity that encapsulates a graphical view of the chart.
*/
public class GraphicalActivity extends Activity {
/** The encapsulated graphical view. */
private GraphicalView mView;
/** The chart to be drawn. */
private AbstractChart mChart;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
mChart = (AbstractChart) extras.getSerializable(ChartFactory.CHART);
mView = new GraphicalView(this, mChart);
String title = extras.getString(ChartFactory.TITLE);
if (title == null) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
} else if (title.length() > 0) {
setTitle(title);
}
setContentView(mView);
}
}

View File

@ -1,325 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.RoundChart;
import org.achartengine.chart.XYChart;
import org.achartengine.model.Point;
import org.achartengine.model.SeriesSelection;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.tools.FitZoom;
import org.achartengine.tools.PanListener;
import org.achartengine.tools.Zoom;
import org.achartengine.tools.ZoomListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
/**
* The view that encapsulates the graphical chart.
*/
public class GraphicalView extends View {
/** The chart to be drawn. */
private AbstractChart mChart;
/** The chart renderer. */
private DefaultRenderer mRenderer;
/** The view bounds. */
private Rect mRect = new Rect();
/** The user interface thread handler. */
private Handler mHandler;
/** The zoom buttons rectangle. */
private RectF mZoomR = new RectF();
/** The zoom in icon. */
private Bitmap zoomInImage;
/** The zoom out icon. */
private Bitmap zoomOutImage;
/** The fit zoom icon. */
private Bitmap fitZoomImage;
/** The zoom area size. */
private int zoomSize = 50;
/** The zoom buttons background color. */
private static final int ZOOM_BUTTONS_COLOR = Color.argb(175, 150, 150, 150);
/** The zoom in tool. */
private Zoom mZoomIn;
/** The zoom out tool. */
private Zoom mZoomOut;
/** The fit zoom tool. */
private FitZoom mFitZoom;
/** The paint to be used when drawing the chart. */
private Paint mPaint = new Paint();
/** The touch handler. */
private ITouchHandler mTouchHandler;
/** The old x coordinate. */
private float oldX;
/** The old y coordinate. */
private float oldY;
/**
* Creates a new graphical view.
*
* @param context the context
* @param chart the chart to be drawn
*/
public GraphicalView(Context context, AbstractChart chart) {
super(context);
mChart = chart;
mHandler = new Handler();
if (mChart instanceof XYChart) {
mRenderer = ((XYChart) mChart).getRenderer();
} else {
mRenderer = ((RoundChart) mChart).getRenderer();
}
if (mRenderer.isZoomButtonsVisible()) {
zoomInImage = BitmapFactory.decodeStream(GraphicalView.class
.getResourceAsStream("image/zoom_in.png"));
zoomOutImage = BitmapFactory.decodeStream(GraphicalView.class
.getResourceAsStream("image/zoom_out.png"));
fitZoomImage = BitmapFactory.decodeStream(GraphicalView.class
.getResourceAsStream("image/zoom-1.png"));
}
if (mRenderer instanceof XYMultipleSeriesRenderer
&& ((XYMultipleSeriesRenderer) mRenderer).getMarginsColor() == XYMultipleSeriesRenderer.NO_COLOR) {
((XYMultipleSeriesRenderer) mRenderer).setMarginsColor(mPaint.getColor());
}
if (mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()
|| mRenderer.isExternalZoomEnabled()) {
mZoomIn = new Zoom(mChart, true, mRenderer.getZoomRate());
mZoomOut = new Zoom(mChart, false, mRenderer.getZoomRate());
mFitZoom = new FitZoom(mChart);
}
mTouchHandler = new TouchHandler(this, mChart);
}
/**
* Returns the current series selection object.
*
* @return the series selection
*/
public SeriesSelection getCurrentSeriesAndPoint() {
return mChart.getSeriesAndPointForScreenCoordinate(new Point(oldX, oldY));
}
/**
* Transforms the currently selected screen point to a real point.
*
* @param scale the scale
* @return the currently selected real point
*/
public double[] toRealPoint(int scale) {
if (mChart instanceof XYChart) {
XYChart chart = (XYChart) mChart;
return chart.toRealPoint(oldX, oldY, scale);
}
return null;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getClipBounds(mRect);
int top = mRect.top;
int left = mRect.left;
int width = mRect.width();
int height = mRect.height();
if (mRenderer.isInScroll()) {
top = 0;
left = 0;
width = getMeasuredWidth();
height = getMeasuredHeight();
}
mChart.draw(canvas, left, top, width, height, mPaint);
if (mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()) {
mPaint.setColor(ZOOM_BUTTONS_COLOR);
zoomSize = Math.max(zoomSize, Math.min(width, height) / 7);
mZoomR.set(left + width - zoomSize * 3, top + height - zoomSize * 0.775f, left + width, top
+ height);
canvas.drawRoundRect(mZoomR, zoomSize / 3, zoomSize / 3, mPaint);
float buttonY = top + height - zoomSize * 0.625f;
canvas.drawBitmap(zoomInImage, left + width - zoomSize * 2.75f, buttonY, null);
canvas.drawBitmap(zoomOutImage, left + width - zoomSize * 1.75f, buttonY, null);
canvas.drawBitmap(fitZoomImage, left + width - zoomSize * 0.75f, buttonY, null);
}
}
/**
* Sets the zoom rate.
*
* @param rate the zoom rate
*/
public void setZoomRate(float rate) {
if (mZoomIn != null && mZoomOut != null) {
mZoomIn.setZoomRate(rate);
mZoomOut.setZoomRate(rate);
}
}
/**
* Do a chart zoom in.
*/
public void zoomIn() {
if (mZoomIn != null) {
mZoomIn.apply();
repaint();
}
}
/**
* Do a chart zoom out.
*/
public void zoomOut() {
if (mZoomOut != null) {
mZoomOut.apply();
repaint();
}
}
/**
* Do a chart zoom reset / fit zoom.
*/
public void zoomReset() {
if (mFitZoom != null) {
mFitZoom.apply();
mZoomIn.notifyZoomResetListeners();
repaint();
}
}
/**
* Adds a new zoom listener.
*
* @param listener zoom listener
*/
public void addZoomListener(ZoomListener listener, boolean onButtons, boolean onPinch) {
if (onButtons) {
if (mZoomIn != null) {
mZoomIn.addZoomListener(listener);
mZoomOut.addZoomListener(listener);
}
if (onPinch) {
mTouchHandler.addZoomListener(listener);
}
}
}
/**
* Removes a zoom listener.
*
* @param listener zoom listener
*/
public synchronized void removeZoomListener(ZoomListener listener) {
if (mZoomIn != null) {
mZoomIn.removeZoomListener(listener);
mZoomOut.removeZoomListener(listener);
}
mTouchHandler.removeZoomListener(listener);
}
/**
* Adds a new pan listener.
*
* @param listener pan listener
*/
public void addPanListener(PanListener listener) {
mTouchHandler.addPanListener(listener);
}
/**
* Removes a pan listener.
*
* @param listener pan listener
*/
public void removePanListener(PanListener listener) {
mTouchHandler.removePanListener(listener);
}
protected RectF getZoomRectangle() {
return mZoomR;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// save the x and y so they can be used in the click and long press
// listeners
oldX = event.getX();
oldY = event.getY();
}
if (mRenderer != null && (mRenderer.isPanEnabled() || mRenderer.isZoomEnabled())) {
if (mTouchHandler.handleTouch(event)) {
return true;
}
}
return super.onTouchEvent(event);
}
/**
* Schedule a view content repaint.
*/
public void repaint() {
mHandler.post(new Runnable() {
public void run() {
invalidate();
}
});
}
/**
* Schedule a view content repaint, in the specified rectangle area.
*
* @param left the left position of the area to be repainted
* @param top the top position of the area to be repainted
* @param right the right position of the area to be repainted
* @param bottom the bottom position of the area to be repainted
*/
public void repaint(final int left, final int top, final int right, final int bottom) {
mHandler.post(new Runnable() {
public void run() {
invalidate(left, top, right, bottom);
}
});
}
/**
* Saves the content of the graphical view to a bitmap.
*
* @return the bitmap
*/
public Bitmap toBitmap() {
setDrawingCacheEnabled(false);
if (!isDrawingCacheEnabled()) {
setDrawingCacheEnabled(true);
}
if (mRenderer.isApplyBackgroundColor()) {
setDrawingCacheBackgroundColor(mRenderer.getBackgroundColor());
}
setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
return getDrawingCache(true);
}
}

View File

@ -1,63 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine;
import org.achartengine.tools.PanListener;
import org.achartengine.tools.ZoomListener;
import android.view.MotionEvent;
/**
* The interface to be implemented by the touch handlers.
*/
public interface ITouchHandler {
/**
* Handles the touch event.
*
* @param event the touch event
* @return true if the event was handled
*/
boolean handleTouch(MotionEvent event);
/**
* Adds a new zoom listener.
*
* @param listener zoom listener
*/
void addZoomListener(ZoomListener listener);
/**
* Removes a zoom listener.
*
* @param listener zoom listener
*/
void removeZoomListener(ZoomListener listener);
/**
* Adds a new pan listener.
*
* @param listener pan listener
*/
void addPanListener(PanListener listener);
/**
* Removes a pan listener.
*
* @param listener pan listener
*/
void removePanListener(PanListener listener);
}

View File

@ -1,186 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine;
import android.annotation.TargetApi;
import android.graphics.RectF;
import android.view.MotionEvent;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.RoundChart;
import org.achartengine.chart.XYChart;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.tools.Pan;
import org.achartengine.tools.PanListener;
import org.achartengine.tools.Zoom;
import org.achartengine.tools.ZoomListener;
/**
* The main handler of the touch events.
*/
public class TouchHandler implements ITouchHandler {
/** The chart renderer. */
private DefaultRenderer mRenderer;
/** The old x coordinate. */
private float oldX;
/** The old y coordinate. */
private float oldY;
/** The old x2 coordinate. */
private float oldX2;
/** The old y2 coordinate. */
private float oldY2;
/** The zoom buttons rectangle. */
private RectF zoomR = new RectF();
/** The pan tool. */
private Pan mPan;
/** The zoom for the pinch gesture. */
private Zoom mPinchZoom;
/** The graphical view. */
private GraphicalView graphicalView;
/**
* Creates a new graphical view.
*
* @param view the graphical view
* @param chart the chart to be drawn
*/
public TouchHandler(GraphicalView view, AbstractChart chart) {
graphicalView = view;
zoomR = graphicalView.getZoomRectangle();
if (chart instanceof XYChart) {
mRenderer = ((XYChart) chart).getRenderer();
} else {
mRenderer = ((RoundChart) chart).getRenderer();
}
if (mRenderer.isPanEnabled()) {
mPan = new Pan(chart);
}
if (mRenderer.isZoomEnabled()) {
mPinchZoom = new Zoom(chart, true, 1);
}
}
/**
* Handles the touch event.
*
* @param event the touch event
*/
@TargetApi(5)
public boolean handleTouch(MotionEvent event) {
int action = event.getAction();
if (mRenderer != null && action == MotionEvent.ACTION_MOVE) {
if (oldX >= 0 || oldY >= 0) {
float newX = event.getX();
float newY = event.getY();
if (event.getPointerCount() > 1 && (oldX2 >= 0 || oldY2 >= 0) && mRenderer.isZoomEnabled()) {
float newX2 = event.getX(1);
float newY2 = event.getY(1);
float newDeltaX = Math.abs(newX - newX2);
float newDeltaY = Math.abs(newY - newY2);
float oldDeltaX = Math.abs(oldX - oldX2);
float oldDeltaY = Math.abs(oldY - oldY2);
float zoomRate = 1;
if (Math.abs(newX - oldX) >= Math.abs(newY - oldY)) {
zoomRate = newDeltaX / oldDeltaX;
} else {
zoomRate = newDeltaY / oldDeltaY;
}
if (zoomRate > 0.909 && zoomRate < 1.1) {
mPinchZoom.setZoomRate(zoomRate);
mPinchZoom.apply();
}
oldX2 = newX2;
oldY2 = newY2;
} else if (mRenderer.isPanEnabled()) {
mPan.apply(oldX, oldY, newX, newY);
oldX2 = 0;
oldY2 = 0;
}
oldX = newX;
oldY = newY;
graphicalView.repaint();
return true;
}
} else if (action == MotionEvent.ACTION_DOWN) {
oldX = event.getX();
oldY = event.getY();
if (mRenderer != null && mRenderer.isZoomEnabled() && zoomR.contains(oldX, oldY)) {
if (oldX < zoomR.left + zoomR.width() / 3) {
graphicalView.zoomIn();
} else if (oldX < zoomR.left + zoomR.width() * 2 / 3) {
graphicalView.zoomOut();
} else {
graphicalView.zoomReset();
}
return true;
}
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
oldX = 0;
oldY = 0;
oldX2 = 0;
oldY2 = 0;
if (action == MotionEvent.ACTION_POINTER_UP) {
oldX = -1;
oldY = -1;
}
}
return !mRenderer.isClickEnabled();
}
/**
* Adds a new zoom listener.
*
* @param listener zoom listener
*/
public void addZoomListener(ZoomListener listener) {
if (mPinchZoom != null) {
mPinchZoom.addZoomListener(listener);
}
}
/**
* Removes a zoom listener.
*
* @param listener zoom listener
*/
public void removeZoomListener(ZoomListener listener) {
if (mPinchZoom != null) {
mPinchZoom.removeZoomListener(listener);
}
}
/**
* Adds a new pan listener.
*
* @param listener pan listener
*/
public void addPanListener(PanListener listener) {
if (mPan != null) {
mPan.addPanListener(listener);
}
}
/**
* Removes a pan listener.
*
* @param listener pan listener
*/
public void removePanListener(PanListener listener) {
if (mPan != null) {
mPan.removePanListener(listener);
}
}
}

View File

@ -1,431 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import java.io.Serializable;
import java.util.List;
import org.achartengine.model.Point;
import org.achartengine.model.SeriesSelection;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;
import org.achartengine.util.MathHelper;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
/**
* An abstract class to be implemented by the chart rendering classes.
*/
public abstract class AbstractChart implements Serializable {
/**
* The graphical representation of the chart.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint
*/
public abstract void draw(Canvas canvas, int x, int y, int width, int height, Paint paint);
/**
* Draws the chart background.
*
* @param renderer the chart renderer
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint used for drawing
* @param newColor if a new color is to be used
* @param color the color to be used
*/
protected void drawBackground(DefaultRenderer renderer, Canvas canvas, int x, int y, int width,
int height, Paint paint, boolean newColor, int color) {
if (renderer.isApplyBackgroundColor() || newColor) {
if (newColor) {
paint.setColor(color);
} else {
paint.setColor(renderer.getBackgroundColor());
}
paint.setStyle(Style.FILL);
canvas.drawRect(x, y, x + width, y + height, paint);
}
}
/**
* Draws the chart legend.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param titles the titles to go to the legend
* @param left the left X value of the area to draw to
* @param right the right X value of the area to draw to
* @param y the y value of the area to draw to
* @param width the width of the area to draw to
* @param height the height of the area to draw to
* @param legendSize the legend size
* @param paint the paint to be used for drawing
* @param calculate if only calculating the legend size
*
* @return the legend height
*/
protected int drawLegend(Canvas canvas, DefaultRenderer renderer, String[] titles, int left,
int right, int y, int width, int height, int legendSize, Paint paint, boolean calculate) {
float size = 32;
if (renderer.isShowLegend()) {
float currentX = left;
float currentY = y + height - legendSize + size;
paint.setTextAlign(Align.LEFT);
paint.setTextSize(renderer.getLegendTextSize());
int sLength = Math.min(titles.length, renderer.getSeriesRendererCount());
for (int i = 0; i < sLength; i++) {
final float lineSize = getLegendShapeWidth(i);
String text = titles[i];
if (titles.length == renderer.getSeriesRendererCount()) {
paint.setColor(renderer.getSeriesRendererAt(i).getColor());
} else {
paint.setColor(Color.LTGRAY);
}
float[] widths = new float[text.length()];
paint.getTextWidths(text, widths);
float sum = 0;
for (float value : widths) {
sum += value;
}
float extraSize = lineSize + 10 + sum;
float currentWidth = currentX + extraSize;
if (i > 0 && getExceed(currentWidth, renderer, right, width)) {
currentX = left;
currentY += renderer.getLegendTextSize();
size += renderer.getLegendTextSize();
currentWidth = currentX + extraSize;
}
if (getExceed(currentWidth, renderer, right, width)) {
float maxWidth = right - currentX - lineSize - 10;
if (isVertical(renderer)) {
maxWidth = width - currentX - lineSize - 10;
}
int nr = paint.breakText(text, true, maxWidth, widths);
text = text.substring(0, nr) + "...";
}
if (!calculate) {
drawLegendShape(canvas, renderer.getSeriesRendererAt(i), currentX, currentY, i, paint);
canvas.drawText(text, currentX + lineSize + 5, currentY + 5, paint);
}
currentX += extraSize;
}
}
return Math.round(size + renderer.getLegendTextSize());
}
/**
* Calculates if the current width exceeds the total width.
*
* @param currentWidth the current width
* @param renderer the renderer
* @param right the right side pixel value
* @param width the total width
* @return if the current width exceeds the total width
*/
protected boolean getExceed(float currentWidth, DefaultRenderer renderer, int right, int width) {
boolean exceed = currentWidth > right;
if (isVertical(renderer)) {
exceed = currentWidth > width;
}
return exceed;
}
/**
* Checks if the current chart is rendered as vertical.
*
* @param renderer the renderer
* @return if the chart is rendered as a vertical one
*/
public boolean isVertical(DefaultRenderer renderer) {
return renderer instanceof XYMultipleSeriesRenderer
&& ((XYMultipleSeriesRenderer) renderer).getOrientation() == Orientation.VERTICAL;
}
private static float[] calculateDrawPoints(float p1x, float p1y, float p2x, float p2y,
int screenHeight, int screenWidth) {
float drawP1x;
float drawP1y;
float drawP2x;
float drawP2y;
if (p1y > screenHeight) {
// Intersection with the top of the screen
float m = (p2y - p1y) / (p2x - p1x);
drawP1x = (screenHeight - p1y + m * p1x) / m;
drawP1y = screenHeight;
if (drawP1x < 0) {
// If Intersection is left of the screen we calculate the intersection
// with the left border
drawP1x = 0;
drawP1y = p1y - m * p1x;
} else if (drawP1x > screenWidth) {
// If Intersection is right of the screen we calculate the intersection
// with the right border
drawP1x = screenWidth;
drawP1y = m * screenWidth + p1y - m * p1x;
}
} else if (p1y < 0) {
float m = (p2y - p1y) / (p2x - p1x);
drawP1x = (-p1y + m * p1x) / m;
drawP1y = 0;
if (drawP1x < 0) {
drawP1x = 0;
drawP1y = p1y - m * p1x;
} else if (drawP1x > screenWidth) {
drawP1x = screenWidth;
drawP1y = m * screenWidth + p1y - m * p1x;
}
} else {
// If the point is in the screen use it
drawP1x = p1x;
drawP1y = p1y;
}
if (p2y > screenHeight) {
float m = (p2y - p1y) / (p2x - p1x);
drawP2x = (screenHeight - p1y + m * p1x) / m;
drawP2y = screenHeight;
if (drawP2x < 0) {
drawP2x = 0;
drawP2y = p1y - m * p1x;
} else if (drawP2x > screenWidth) {
drawP2x = screenWidth;
drawP2y = m * screenWidth + p1y - m * p1x;
}
} else if (p2y < 0) {
float m = (p2y - p1y) / (p2x - p1x);
drawP2x = (-p1y + m * p1x) / m;
drawP2y = 0;
if (drawP2x < 0) {
drawP2x = 0;
drawP2y = p1y - m * p1x;
} else if (drawP2x > screenWidth) {
drawP2x = screenWidth;
drawP2y = m * screenWidth + p1y - m * p1x;
}
} else {
// If the point is in the screen use it
drawP2x = p2x;
drawP2y = p2y;
}
return new float[] { drawP1x, drawP1y, drawP2x, drawP2y };
}
/**
* The graphical representation of a path.
*
* @param canvas the canvas to paint to
* @param points the points that are contained in the path to paint
* @param paint the paint to be used for painting
* @param circular if the path ends with the start point
*/
protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {
Path path = new Path();
int height = canvas.getHeight();
int width = canvas.getWidth();
float[] tempDrawPoints;
if (points.length < 4) {
return;
}
tempDrawPoints = calculateDrawPoints(points[0], points[1], points[2], points[3], height, width);
path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
for (int i = 4; i < points.length; i += 2) {
if ((points[i - 1] < 0 && points[i + 1] < 0)
|| (points[i - 1] > height && points[i + 1] > height)) {
continue;
}
tempDrawPoints = calculateDrawPoints(points[i - 2], points[i - 1], points[i], points[i + 1],
height, width);
if (!circular) {
path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
}
path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
}
if (circular) {
path.lineTo(points[0], points[1]);
}
canvas.drawPath(path, paint);
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public abstract int getLegendShapeWidth(int seriesIndex);
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public abstract void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x,
float y, int seriesIndex, Paint paint);
/**
* Calculates the best text to fit into the available space.
*
* @param text the entire text
* @param width the width to fit the text into
* @param paint the paint
* @return the text to fit into the space
*/
private String getFitText(String text, float width, Paint paint) {
String newText = text;
int length = text.length();
int diff = 0;
while (paint.measureText(newText) > width && diff < length) {
diff++;
newText = text.substring(0, length - diff) + "...";
}
if (diff == length) {
newText = "...";
}
return newText;
}
/**
* Calculates the current legend size.
*
* @param renderer the renderer
* @param defaultHeight the default height
* @param extraHeight the added extra height
* @return the legend size
*/
protected int getLegendSize(DefaultRenderer renderer, int defaultHeight, float extraHeight) {
int legendSize = renderer.getLegendHeight();
if (renderer.isShowLegend() && legendSize == 0) {
legendSize = defaultHeight;
}
if (!renderer.isShowLegend() && renderer.isShowLabels()) {
legendSize = (int) (renderer.getLabelsTextSize() * 4 / 3 + extraHeight);
}
return legendSize;
}
/**
* Draws a text label.
*
* @param canvas the canvas
* @param labelText the label text
* @param renderer the renderer
* @param prevLabelsBounds the previous rendered label bounds
* @param centerX the round chart center on X axis
* @param centerY the round chart center on Y axis
* @param shortRadius the short radius for the round chart
* @param longRadius the long radius for the round chart
* @param currentAngle the current angle
* @param angle the label extra angle
* @param left the left side
* @param right the right side
* @param color the label color
* @param paint the paint
*/
protected void drawLabel(Canvas canvas, String labelText, DefaultRenderer renderer,
List<RectF> prevLabelsBounds, int centerX, int centerY, float shortRadius, float longRadius,
float currentAngle, float angle, int left, int right, int color, Paint paint) {
if (renderer.isShowLabels()) {
paint.setColor(color);
double rAngle = Math.toRadians(90 - (currentAngle + angle / 2));
double sinValue = Math.sin(rAngle);
double cosValue = Math.cos(rAngle);
int x1 = Math.round(centerX + (float) (shortRadius * sinValue));
int y1 = Math.round(centerY + (float) (shortRadius * cosValue));
int x2 = Math.round(centerX + (float) (longRadius * sinValue));
int y2 = Math.round(centerY + (float) (longRadius * cosValue));
float size = renderer.getLabelsTextSize();
float extra = Math.max(size / 2, 10);
paint.setTextAlign(Align.LEFT);
if (x1 > x2) {
extra = -extra;
paint.setTextAlign(Align.RIGHT);
}
float xLabel = x2 + extra;
float yLabel = y2;
float width = right - xLabel;
if (x1 > x2) {
width = xLabel - left;
}
labelText = getFitText(labelText, width, paint);
float widthLabel = paint.measureText(labelText);
boolean okBounds = false;
while (!okBounds) {
boolean intersects = false;
int length = prevLabelsBounds.size();
for (int j = 0; j < length && !intersects; j++) {
RectF prevLabelBounds = prevLabelsBounds.get(j);
if (prevLabelBounds.intersects(xLabel, yLabel, xLabel + widthLabel, yLabel + size)) {
intersects = true;
yLabel = Math.max(yLabel, prevLabelBounds.bottom);
}
}
okBounds = !intersects;
}
y2 = (int) (yLabel - size / 2);
canvas.drawLine(x1, y1, x2, y2, paint);
canvas.drawLine(x2, y2, x2 + extra, y2, paint);
canvas.drawText(labelText, xLabel, yLabel, paint);
prevLabelsBounds.add(new RectF(xLabel, yLabel, xLabel + widthLabel, yLabel + size));
}
}
public boolean isNullValue(double value) {
return Double.isNaN(value) || Double.isInfinite(value) || value == MathHelper.NULL_VALUE;
}
/**
* Given screen coordinates, returns the series and point indexes of a chart
* element. If there is no chart element (line, point, bar, etc) at those
* coordinates, null is returned.
*
* @param screenPoint
* @return Always returns null
*/
public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
return null;
}
}

View File

@ -1,316 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
/**
* The bar chart rendering class.
*/
public class BarChart extends XYChart {
/** The constant to identify this chart type. */
public static final String TYPE = "Bar";
/** The legend shape width. */
private static final int SHAPE_WIDTH = 12;
/** The chart type. */
protected Type mType = Type.DEFAULT;
/**
* The bar chart type enum.
*/
public enum Type {
DEFAULT, STACKED;
}
BarChart() {
}
/**
* Builds a new bar chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
* @param type the bar chart type
*/
public BarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
super(dataset, renderer);
mType = type;
}
@Override
protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
float yAxisValue, int seriesIndex, int startIndex, int range) {
int seriesNr = mDataset.getSeriesCount();
int length = points.length;
ClickableArea[] ret = new ClickableArea[length / 2];
float halfDiffX = getHalfDiffX(points, length, seriesNr, range);
for (int i = 0; i < length; i += 2) {
float x = points[i];
float y = points[i + 1];
if (mType == Type.STACKED) {
ret[i / 2] = new ClickableArea(new RectF(x - halfDiffX, y, x + halfDiffX, yAxisValue),
values[i], values[i + 1]);
} else {
float startX = x - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;
ret[i / 2] = new ClickableArea(new RectF(startX, y, startX + 2 * halfDiffX, yAxisValue),
values[i], values[i + 1]);
}
}
return ret;
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range) {
int seriesNr = mDataset.getSeriesCount();
int length = points.length;
paint.setColor(seriesRenderer.getColor());
paint.setStyle(Style.FILL);
float halfDiffX = getHalfDiffX(points, length, seriesNr, range);
for (int i = 0; i < length; i += 2) {
float x = points[i];
float y = points[i + 1];
drawBar(canvas, x, yAxisValue, x, y, halfDiffX, seriesNr, seriesIndex, paint);
}
paint.setColor(seriesRenderer.getColor());
}
/**
* Draws a bar.
*
* @param canvas the canvas
* @param xMin the X axis minimum
* @param yMin the Y axis minimum
* @param xMax the X axis maximum
* @param yMax the Y axis maximum
* @param halfDiffX half the size of a bar
* @param seriesNr the total number of series
* @param seriesIndex the current series index
* @param paint the paint
*/
protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax,
float halfDiffX, int seriesNr, int seriesIndex, Paint paint) {
int scale = mDataset.getSeriesAt(seriesIndex).getScaleNumber();
if (mType == Type.STACKED) {
drawBar(canvas, xMin - halfDiffX, yMax, xMax + halfDiffX, yMin, scale, seriesIndex, paint);
} else {
float startX = xMin - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;
drawBar(canvas, startX, yMax, startX + 2 * halfDiffX, yMin, scale, seriesIndex, paint);
}
}
/**
* Draws a bar.
*
* @param canvas the canvas
* @param xMin the X axis minimum
* @param yMin the Y axis minimum
* @param xMax the X axis maximum
* @param yMax the Y axis maximum
* @param scale the scale index
* @param seriesIndex the current series index
* @param paint the paint
*/
private void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax, int scale,
int seriesIndex, Paint paint) {
SimpleSeriesRenderer renderer = mRenderer.getSeriesRendererAt(seriesIndex);
if (renderer.isGradientEnabled()) {
float minY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStopValue() }, scale)[1];
float maxY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStartValue() },
scale)[1];
float gradientMinY = Math.max(minY, yMin);
float gradientMaxY = Math.min(maxY, yMax);
int gradientMinColor = renderer.getGradientStopColor();
int gradientMaxColor = renderer.getGradientStartColor();
int gradientStartColor = gradientMaxColor;
int gradientStopColor = gradientMinColor;
if (yMin < minY) {
paint.setColor(gradientMinColor);
canvas.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax),
Math.round(gradientMinY), paint);
} else {
gradientStopColor = getGradientPartialColor(gradientMinColor, gradientMaxColor,
(maxY - gradientMinY) / (maxY - minY));
}
if (yMax > maxY) {
paint.setColor(gradientMaxColor);
canvas.drawRect(Math.round(xMin), Math.round(gradientMaxY), Math.round(xMax),
Math.round(yMax), paint);
} else {
gradientStartColor = getGradientPartialColor(gradientMaxColor, gradientMinColor,
(gradientMaxY - minY) / (maxY - minY));
}
GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {
gradientStartColor, gradientStopColor });
gradient.setBounds(Math.round(xMin), Math.round(gradientMinY), Math.round(xMax),
Math.round(gradientMaxY));
gradient.draw(canvas);
} else {
if (Math.abs(yMin - yMax) < 1) {
if (yMin < yMax) {
yMax = yMin + 1;
} else {
yMax = yMin - 1;
}
}
canvas
.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax), Math.round(yMax), paint);
}
}
private int getGradientPartialColor(int minColor, int maxColor, float fraction) {
int alpha = Math.round(fraction * Color.alpha(minColor) + (1 - fraction)
* Color.alpha(maxColor));
int r = Math.round(fraction * Color.red(minColor) + (1 - fraction) * Color.red(maxColor));
int g = Math.round(fraction * Color.green(minColor) + (1 - fraction) * Color.green(maxColor));
int b = Math.round(fraction * Color.blue(minColor) + (1 - fraction) * Color.blue((maxColor)));
return Color.argb(alpha, r, g, b);
}
/**
* The graphical representation of the series values as text.
*
* @param canvas the canvas to paint to
* @param series the series to be painted
* @param renderer the series renderer
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,
Paint paint, float[] points, int seriesIndex, int startIndex, int range) {
int seriesNr = mDataset.getSeriesCount();
float halfDiffX = getHalfDiffX(points, points.length, seriesNr, range);
for (int i = 0; i < points.length; i += 2) {
int index = startIndex + i / 2;
if (!isNullValue(series.getY(index))) {
float x = points[i];
if (mType == Type.DEFAULT) {
x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;
}
drawText(canvas, getLabel(series.getY(index)), x,
points[i + 1] - renderer.getChartValuesSpacing(), paint, 0);
}
}
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return SHAPE_WIDTH;
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
float halfShapeWidth = SHAPE_WIDTH / 2;
canvas.drawRect(x, y - halfShapeWidth, x + SHAPE_WIDTH, y + halfShapeWidth, paint);
}
/**
* Calculates and returns the half-distance in the graphical representation of
* 2 consecutive points.
*
* @param points the points
* @param length the points length
* @param seriesNr the series number
* @return the calculated half-distance value
*/
protected float getHalfDiffX(float[] points, int length, int seriesNr, int range) {
int div = range * 2;
float halfDiffX = (points[length - 2] - points[0]) / div;
if (halfDiffX == 0) {
halfDiffX = 10;
}
if (mType != Type.STACKED) {
halfDiffX /= seriesNr;
}
return (float) (halfDiffX / (getCoeficient() * (1 + mRenderer.getBarSpacing())));
}
/**
* Returns the value of a constant used to calculate the half-distance.
*
* @return the constant value
*/
protected float getCoeficient() {
return 1f;
}
/**
* Returns if the chart should display the null values.
*
* @return if null values should be rendered
*/
protected boolean isRenderNullValues() {
return true;
}
/**
* Returns the default axis minimum.
*
* @return the default axis minimum
*/
public double getDefaultMinimum() {
return 0;
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
}

View File

@ -1,146 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYValueSeries;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
/**
* The bubble chart rendering class.
*/
public class BubbleChart extends XYChart {
/** The constant to identify this chart type. */
public static final String TYPE = "Bubble";
/** The legend shape width. */
private static final int SHAPE_WIDTH = 10;
/** The minimum bubble size. */
private static final int MIN_BUBBLE_SIZE = 2;
/** The maximum bubble size. */
private static final int MAX_BUBBLE_SIZE = 20;
BubbleChart() {
}
/**
* Builds a new bubble chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
*/
public BubbleChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
super(dataset, renderer);
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range) {
XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;
paint.setColor(renderer.getColor());
paint.setStyle(Style.FILL);
int length = points.length;
XYValueSeries series = (XYValueSeries) mDataset.getSeriesAt(seriesIndex);
double max = series.getMaxValue();
double coef = MAX_BUBBLE_SIZE / max;
for (int i = 0; i < length; i += 2) {
double size = series.getValue(startIndex + i / 2) * coef + MIN_BUBBLE_SIZE;
drawCircle(canvas, paint, points[i], points[i + 1], (float) size);
}
}
@Override
protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
float yAxisValue, int seriesIndex, int startIndex, int range) {
int length = points.length;
XYValueSeries series = (XYValueSeries) mDataset.getSeriesAt(seriesIndex);
double max = series.getMaxValue();
double coef = MAX_BUBBLE_SIZE / max;
ClickableArea[] ret = new ClickableArea[length / 2];
for (int i = 0; i < length; i += 2) {
double size = series.getValue(startIndex + i / 2) * coef + MIN_BUBBLE_SIZE;
ret[i / 2] = new ClickableArea(new RectF(points[i] - (float) size, points[i + 1]
- (float) size, points[i] + (float) size, points[i + 1] + (float) size), values[i],
values[i + 1]);
}
return ret;
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return SHAPE_WIDTH;
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
paint.setStyle(Style.FILL);
drawCircle(canvas, paint, x + SHAPE_WIDTH, y, 3);
}
/**
* The graphical representation of a circle point shape.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param radius the bubble radius
*/
private void drawCircle(Canvas canvas, Paint paint, float x, float y, float radius) {
canvas.drawCircle(x, y, radius, paint);
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
}

View File

@ -1,44 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import android.graphics.RectF;
public class ClickableArea {
private RectF rect;
private double x;
private double y;
public ClickableArea(RectF rect, double x, double y) {
super();
this.rect = rect;
this.x = x;
this.y = y;
}
public RectF getRect() {
return rect;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}

View File

@ -1,177 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import java.util.List;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* The combined XY chart rendering class.
*/
public class CombinedXYChart extends XYChart {
/** The embedded XY charts. */
private XYChart[] mCharts;
/** The supported charts for being combined. */
private Class[] xyChartTypes = new Class[] { TimeChart.class, LineChart.class,
CubicLineChart.class, BarChart.class, BubbleChart.class, ScatterChart.class,
RangeBarChart.class };
/**
* Builds a new combined XY chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
* @param types the XY chart types
*/
public CombinedXYChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer,
String[] types) {
super(dataset, renderer);
int length = types.length;
mCharts = new XYChart[length];
for (int i = 0; i < length; i++) {
try {
mCharts[i] = getXYChart(types[i]);
} catch (Exception e) {
// ignore
}
if (mCharts[i] == null) {
throw new IllegalArgumentException("Unknown chart type " + types[i]);
} else {
XYMultipleSeriesDataset newDataset = new XYMultipleSeriesDataset();
newDataset.addSeries(dataset.getSeriesAt(i));
XYMultipleSeriesRenderer newRenderer = new XYMultipleSeriesRenderer();
// TODO: copy other parameters here
newRenderer.setBarSpacing(renderer.getBarSpacing());
newRenderer.setPointSize(renderer.getPointSize());
int scale = dataset.getSeriesAt(i).getScaleNumber();
if (renderer.isMinXSet(scale)) {
newRenderer.setXAxisMin(renderer.getXAxisMin(scale));
}
if (renderer.isMaxXSet(scale)) {
newRenderer.setXAxisMax(renderer.getXAxisMax(scale));
}
if (renderer.isMinYSet(scale)) {
newRenderer.setYAxisMin(renderer.getYAxisMin(scale));
}
if (renderer.isMaxYSet(scale)) {
newRenderer.setYAxisMax(renderer.getYAxisMax(scale));
}
newRenderer.addSeriesRenderer(renderer.getSeriesRendererAt(i));
mCharts[i].setDatasetRenderer(newDataset, newRenderer);
}
}
}
/**
* Returns a chart instance based on the provided type.
*
* @param type the chart type
* @return an instance of a chart implementation
* @throws IllegalAccessException
* @throws InstantiationException
*/
private XYChart getXYChart(String type) throws IllegalAccessException, InstantiationException {
XYChart chart = null;
int length = xyChartTypes.length;
for (int i = 0; i < length && chart == null; i++) {
XYChart newChart = (XYChart) xyChartTypes[i].newInstance();
if (type.equals(newChart.getChartType())) {
chart = newChart;
}
}
return chart;
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range) {
mCharts[seriesIndex].setScreenR(getScreenR());
mCharts[seriesIndex].setCalcRange(getCalcRange(mDataset.getSeriesAt(seriesIndex)
.getScaleNumber()), 0);
mCharts[seriesIndex].drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, 0,
startIndex, range);
}
@Override
protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
float yAxisValue, int seriesIndex, int startIndex, int range) {
return mCharts[seriesIndex].clickableAreasForPoints(points, values, yAxisValue, 0, startIndex, range);
}
@Override
protected void drawSeries(XYSeries series, Canvas canvas, Paint paint, List<Float> pointsList,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, Orientation or,
int startIndex, int range) {
mCharts[seriesIndex].setScreenR(getScreenR());
mCharts[seriesIndex].setCalcRange(getCalcRange(mDataset.getSeriesAt(seriesIndex)
.getScaleNumber()), 0);
mCharts[seriesIndex].drawSeries(series, canvas, paint, pointsList, seriesRenderer, yAxisValue,
0, or, startIndex, range);
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return mCharts[seriesIndex].getLegendShapeWidth(0);
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
mCharts[seriesIndex].drawLegendShape(canvas, renderer, x, y, 0, paint);
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return "Combined";
}
}

View File

@ -1,120 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.Point;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
/**
* The interpolated (cubic) line chart rendering class.
*/
public class CubicLineChart extends LineChart {
/** The chart type. */
public static final String TYPE = "Cubic";
private float firstMultiplier;
private float secondMultiplier;
private Point p1 = new Point();
private Point p2 = new Point();
private Point p3 = new Point();
public CubicLineChart() {
// default is to have first control point at about 33% of the distance,
firstMultiplier = 0.33f;
// and the next at 66% of the distance.
secondMultiplier = 1 - firstMultiplier;
}
/**
* Builds a cubic line chart.
*
* @param dataset the dataset
* @param renderer the renderer
* @param smoothness smoothness determines how smooth the curve should be,
* range [0->0.5] super smooth, 0.5, means that it might not get
* close to control points if you have random data // less smooth,
* (close to 0) means that it will most likely touch all control //
* points
*/
public CubicLineChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer,
float smoothness) {
super(dataset, renderer);
firstMultiplier = smoothness;
secondMultiplier = 1 - firstMultiplier;
}
@Override
protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {
Path p = new Path();
float x = points[0];
float y = points[1];
p.moveTo(x, y);
int length = points.length;
if (circular) {
length -= 4;
}
for (int i = 0; i < length; i += 2) {
int nextIndex = i + 2 < length ? i + 2 : i;
int nextNextIndex = i + 4 < length ? i + 4 : nextIndex;
calc(points, p1, i, nextIndex, secondMultiplier);
p2.setX(points[nextIndex]);
p2.setY(points[nextIndex + 1]);
calc(points, p3, nextIndex, nextNextIndex, firstMultiplier);
// From last point, approaching x1/y1 and x2/y2 and ends up at x3/y3
p.cubicTo(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY());
}
if (circular) {
for (int i = length; i < length + 4; i += 2) {
p.lineTo(points[i], points[i + 1]);
}
p.lineTo(points[0], points[1]);
}
canvas.drawPath(p, paint);
}
private void calc(float[] points, Point result, int index1, int index2, final float multiplier) {
float p1x = points[index1];
float p1y = points[index1 + 1];
float p2x = points[index2];
float p2y = points[index2 + 1];
float diffX = p2x - p1x; // p2.x - p1.x;
float diffY = p2y - p1y; // p2.y - p1.y;
result.setX(p1x + (diffX * multiplier));
result.setY(p1y + (diffY * multiplier));
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
}

View File

@ -1,236 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.CategorySeries;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.DialRenderer;
import org.achartengine.renderer.DialRenderer.Type;
import org.achartengine.util.MathHelper;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
/**
* The dial chart rendering class.
*/
public class DialChart extends RoundChart {
/** The radius of the needle. */
private static final int NEEDLE_RADIUS = 10;
/** The series renderer. */
private DialRenderer mRenderer;
/**
* Builds a new dial chart instance.
*
* @param dataset the series dataset
* @param renderer the dial renderer
*/
public DialChart(CategorySeries dataset, DialRenderer renderer) {
super(dataset, renderer);
mRenderer = renderer;
}
/**
* The graphical representation of the dial chart.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint
*/
@Override
public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
paint.setAntiAlias(mRenderer.isAntialiasing());
paint.setStyle(Style.FILL);
paint.setTextSize(mRenderer.getLabelsTextSize());
int legendSize = getLegendSize(mRenderer, height / 5, 0);
int left = x;
int top = y;
int right = x + width;
int sLength = mDataset.getItemCount();
String[] titles = new String[sLength];
for (int i = 0; i < sLength; i++) {
titles[i] = mDataset.getCategory(i);
}
if (mRenderer.isFitLegend()) {
legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,
paint, true);
}
int bottom = y + height - legendSize;
drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
int radius = (int) (mRadius * 0.35 * mRenderer.getScale());
if (mCenterX == NO_VALUE) {
mCenterX = (left + right) / 2;
}
if (mCenterY == NO_VALUE) {
mCenterY = (bottom + top) / 2;
}
float shortRadius = radius * 0.9f;
float longRadius = radius * 1.1f;
double min = mRenderer.getMinValue();
double max = mRenderer.getMaxValue();
double angleMin = mRenderer.getAngleMin();
double angleMax = mRenderer.getAngleMax();
if (!mRenderer.isMinValueSet() || !mRenderer.isMaxValueSet()) {
int count = mRenderer.getSeriesRendererCount();
for (int i = 0; i < count; i++) {
double value = mDataset.getValue(i);
if (!mRenderer.isMinValueSet()) {
min = Math.min(min, value);
}
if (!mRenderer.isMaxValueSet()) {
max = Math.max(max, value);
}
}
}
if (min == max) {
min = min * 0.5;
max = max * 1.5;
}
paint.setColor(mRenderer.getLabelsColor());
double minorTicks = mRenderer.getMinorTicksSpacing();
double majorTicks = mRenderer.getMajorTicksSpacing();
if (minorTicks == MathHelper.NULL_VALUE) {
minorTicks = (max - min) / 30;
}
if (majorTicks == MathHelper.NULL_VALUE) {
majorTicks = (max - min) / 10;
}
drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, radius,
minorTicks, paint, false);
drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, shortRadius,
majorTicks, paint, true);
int count = mRenderer.getSeriesRendererCount();
for (int i = 0; i < count; i++) {
double angle = getAngleForValue(mDataset.getValue(i), angleMin, angleMax, min, max);
paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());
boolean type = mRenderer.getVisualTypeForIndex(i) == Type.ARROW;
drawNeedle(canvas, angle, mCenterX, mCenterY, shortRadius, type, paint);
}
drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
drawTitle(canvas, x, y, width, paint);
}
/**
* Returns the angle for a specific chart value.
*
* @param value the chart value
* @param minAngle the minimum chart angle value
* @param maxAngle the maximum chart angle value
* @param min the minimum chart value
* @param max the maximum chart value
* @return the angle
*/
private double getAngleForValue(double value, double minAngle, double maxAngle, double min,
double max) {
double angleDiff = maxAngle - minAngle;
double diff = max - min;
return Math.toRadians(minAngle + (value - min) * angleDiff / diff);
}
/**
* Draws the chart tick lines.
*
* @param canvas the canvas
* @param min the minimum chart value
* @param max the maximum chart value
* @param minAngle the minimum chart angle value
* @param maxAngle the maximum chart angle value
* @param centerX the center x value
* @param centerY the center y value
* @param longRadius the long radius
* @param shortRadius the short radius
* @param ticks the tick spacing
* @param paint the paint settings
* @param labels paint the labels
* @return the angle
*/
private void drawTicks(Canvas canvas, double min, double max, double minAngle, double maxAngle,
int centerX, int centerY, double longRadius, double shortRadius, double ticks, Paint paint,
boolean labels) {
for (double i = min; i <= max; i += ticks) {
double angle = getAngleForValue(i, minAngle, maxAngle, min, max);
double sinValue = Math.sin(angle);
double cosValue = Math.cos(angle);
int x1 = Math.round(centerX + (float) (shortRadius * sinValue));
int y1 = Math.round(centerY + (float) (shortRadius * cosValue));
int x2 = Math.round(centerX + (float) (longRadius * sinValue));
int y2 = Math.round(centerY + (float) (longRadius * cosValue));
canvas.drawLine(x1, y1, x2, y2, paint);
if (labels) {
paint.setTextAlign(Align.LEFT);
if (x1 <= x2) {
paint.setTextAlign(Align.RIGHT);
}
String text = i + "";
if (Math.round(i) == (long) i) {
text = (long) i + "";
}
canvas.drawText(text, x1, y1, paint);
}
}
}
/**
* Returns the angle for a specific chart value.
*
* @param canvas the canvas
* @param angle the needle angle value
* @param centerX the center x value
* @param centerY the center y value
* @param radius the radius
* @param arrow if a needle or an arrow to be painted
* @param paint the paint settings
* @return the angle
*/
private void drawNeedle(Canvas canvas, double angle, int centerX, int centerY, double radius,
boolean arrow, Paint paint) {
double diff = Math.toRadians(90);
int needleSinValue = (int) (NEEDLE_RADIUS * Math.sin(angle - diff));
int needleCosValue = (int) (NEEDLE_RADIUS * Math.cos(angle - diff));
int needleX = (int) (radius * Math.sin(angle));
int needleY = (int) (radius * Math.cos(angle));
int needleCenterX = centerX + needleX;
int needleCenterY = centerY + needleY;
float[] points;
if (arrow) {
int arrowBaseX = centerX + (int) (radius * 0.85 * Math.sin(angle));
int arrowBaseY = centerY + (int) (radius * 0.85 * Math.cos(angle));
points = new float[] { arrowBaseX - needleSinValue, arrowBaseY - needleCosValue,
needleCenterX, needleCenterY, arrowBaseX + needleSinValue, arrowBaseY + needleCosValue };
float width = paint.getStrokeWidth();
paint.setStrokeWidth(5);
canvas.drawLine(centerX, centerY, needleCenterX, needleCenterY, paint);
paint.setStrokeWidth(width);
} else {
points = new float[] { centerX - needleSinValue, centerY - needleCosValue, needleCenterX,
needleCenterY, centerX + needleSinValue, centerY + needleCosValue };
}
drawPath(canvas, points, paint, true);
}
}

View File

@ -1,162 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import java.util.ArrayList;
import java.util.List;
import org.achartengine.model.MultipleCategorySeries;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.SimpleSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
/**
* The doughnut chart rendering class.
*/
public class DoughnutChart extends RoundChart {
/** The series dataset. */
private MultipleCategorySeries mDataset;
/** A step variable to control the size of the legend shape. */
private int mStep;
/**
* Builds a new doughnut chart instance.
*
* @param dataset the series dataset
* @param renderer the series renderer
*/
public DoughnutChart(MultipleCategorySeries dataset, DefaultRenderer renderer) {
super(null, renderer);
mDataset = dataset;
}
/**
* The graphical representation of the doughnut chart.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint
*/
@Override
public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
paint.setAntiAlias(mRenderer.isAntialiasing());
paint.setStyle(Style.FILL);
paint.setTextSize(mRenderer.getLabelsTextSize());
int legendSize = getLegendSize(mRenderer, height / 5, 0);
int left = x;
int top = y;
int right = x + width;
int cLength = mDataset.getCategoriesCount();
String[] categories = new String[cLength];
for (int category = 0; category < cLength; category++) {
categories[category] = mDataset.getCategory(category);
}
if (mRenderer.isFitLegend()) {
legendSize = drawLegend(canvas, mRenderer, categories, left, right, y, width, height,
legendSize, paint, true);
}
int bottom = y + height - legendSize;
drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
mStep = SHAPE_WIDTH * 3 / 4;
int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
double rCoef = 0.35 * mRenderer.getScale();
double decCoef = 0.2 / cLength;
int radius = (int) (mRadius * rCoef);
if (mCenterX == NO_VALUE) {
mCenterX = (left + right) / 2;
}
if (mCenterY == NO_VALUE) {
mCenterY = (bottom + top) / 2;
}
float shortRadius = radius * 0.9f;
float longRadius = radius * 1.1f;
List<RectF> prevLabelsBounds = new ArrayList<RectF>();
for (int category = 0; category < cLength; category++) {
int sLength = mDataset.getItemCount(category);
double total = 0;
String[] titles = new String[sLength];
for (int i = 0; i < sLength; i++) {
total += mDataset.getValues(category)[i];
titles[i] = mDataset.getTitles(category)[i];
}
float currentAngle = mRenderer.getStartAngle();
RectF oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY
+ radius);
for (int i = 0; i < sLength; i++) {
paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());
float value = (float) mDataset.getValues(category)[i];
float angle = (float) (value / total * 360);
canvas.drawArc(oval, currentAngle, angle, true, paint);
drawLabel(canvas, mDataset.getTitles(category)[i], mRenderer, prevLabelsBounds, mCenterX,
mCenterY, shortRadius, longRadius, currentAngle, angle, left, right,
mRenderer.getLabelsColor(), paint);
currentAngle += angle;
}
radius -= (int) mRadius * decCoef;
shortRadius -= mRadius * decCoef - 2;
if (mRenderer.getBackgroundColor() != 0) {
paint.setColor(mRenderer.getBackgroundColor());
} else {
paint.setColor(Color.WHITE);
}
paint.setStyle(Style.FILL);
oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY + radius);
canvas.drawArc(oval, 0, 360, true, paint);
radius -= 1;
}
prevLabelsBounds.clear();
drawLegend(canvas, mRenderer, categories, left, right, y, width, height, legendSize, paint,
false);
drawTitle(canvas, x, y, width, paint);
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return SHAPE_WIDTH;
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
mStep--;
canvas.drawCircle(x + SHAPE_WIDTH - mStep, y, mStep, paint);
}
}

View File

@ -1,170 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
/**
* The line chart rendering class.
*/
public class LineChart extends XYChart {
/** The constant to identify this chart type. */
public static final String TYPE = "Line";
/** The legend shape width. */
private static final int SHAPE_WIDTH = 30;
/** The scatter chart to be used to draw the data points. */
private ScatterChart pointsChart;
LineChart() {
}
/**
* Builds a new line chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
*/
public LineChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
super(dataset, renderer);
pointsChart = new ScatterChart(dataset, renderer);
}
/**
* Sets the series and the renderer.
*
* @param dataset the series dataset
* @param renderer the series renderer
*/
protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
super.setDatasetRenderer(dataset, renderer);
pointsChart = new ScatterChart(dataset, renderer);
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range) {
int length = points.length;
XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;
float lineWidth = paint.getStrokeWidth();
paint.setStrokeWidth(renderer.getLineWidth());
if (renderer.isFillBelowLine()) {
paint.setColor(renderer.getFillBelowLineColor());
int pLength = points.length;
float[] fillPoints = new float[pLength + 4];
System.arraycopy(points, 0, fillPoints, 0, length);
fillPoints[0] = points[0] + 1;
fillPoints[length] = fillPoints[length - 2];
fillPoints[length + 1] = yAxisValue;
fillPoints[length + 2] = fillPoints[0];
fillPoints[length + 3] = fillPoints[length + 1];
paint.setStyle(Style.FILL);
drawPath(canvas, fillPoints, paint, true);
}
paint.setColor(seriesRenderer.getColor());
paint.setStyle(Style.STROKE);
drawPath(canvas, points, paint, false);
paint.setStrokeWidth(lineWidth);
}
@Override
protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
float yAxisValue, int seriesIndex, int startIndex, int range) {
int length = points.length;
ClickableArea[] ret = new ClickableArea[length / 2];
for (int i = 0; i < length; i += 2) {
int selectableBuffer = mRenderer.getSelectableBuffer();
ret[i / 2] = new ClickableArea(new RectF(points[i] - selectableBuffer, points[i + 1]
- selectableBuffer, points[i] + selectableBuffer, points[i + 1] + selectableBuffer),
values[i], values[i + 1]);
}
return ret;
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return SHAPE_WIDTH;
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
canvas.drawLine(x, y, x + SHAPE_WIDTH, y, paint);
if (isRenderPoints(renderer)) {
pointsChart.drawLegendShape(canvas, renderer, x + 5, y, seriesIndex, paint);
}
}
/**
* Returns if the chart should display the points as a certain shape.
*
* @param renderer the series renderer
*/
public boolean isRenderPoints(SimpleSeriesRenderer renderer) {
return ((XYSeriesRenderer) renderer).getPointStyle() != PointStyle.POINT;
}
/**
* Returns the scatter chart to be used for drawing the data points.
*
* @return the data points scatter chart
*/
public ScatterChart getPointsChart() {
return pointsChart;
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
}

View File

@ -1,131 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import java.util.ArrayList;
import java.util.List;
import org.achartengine.model.CategorySeries;
import org.achartengine.model.Point;
import org.achartengine.model.SeriesSelection;
import org.achartengine.renderer.DefaultRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
/**
* The pie chart rendering class.
*/
public class PieChart extends RoundChart {
/** Handles returning values when tapping on PieChart. */
private PieMapper mPieMapper;
/**
* Builds a new pie chart instance.
*
* @param dataset the series dataset
* @param renderer the series renderer
*/
public PieChart(CategorySeries dataset, DefaultRenderer renderer) {
super(dataset, renderer);
mPieMapper = new PieMapper();
}
/**
* The graphical representation of the pie chart.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint
*/
@Override
public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
paint.setAntiAlias(mRenderer.isAntialiasing());
paint.setStyle(Style.FILL);
paint.setTextSize(mRenderer.getLabelsTextSize());
int legendSize = getLegendSize(mRenderer, height / 5, 0);
int left = x;
int top = y;
int right = x + width;
int sLength = mDataset.getItemCount();
double total = 0;
String[] titles = new String[sLength];
for (int i = 0; i < sLength; i++) {
total += mDataset.getValue(i);
titles[i] = mDataset.getCategory(i);
}
if (mRenderer.isFitLegend()) {
legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,
paint, true);
}
int bottom = y + height - legendSize;
drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
float currentAngle = 0;
int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
int radius = (int) (mRadius * 0.35 * mRenderer.getScale());
if (mCenterX == NO_VALUE) {
mCenterX = (left + right) / 2;
}
if (mCenterY == NO_VALUE) {
mCenterY = (bottom + top) / 2;
}
// Hook in clip detection after center has been calculated
mPieMapper.setDimensions(radius, mCenterX, mCenterY);
boolean loadPieCfg = !mPieMapper.areAllSegmentPresent(sLength);
if (loadPieCfg) {
mPieMapper.clearPieSegments();
}
float shortRadius = radius * 0.9f;
float longRadius = radius * 1.1f;
RectF oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY
+ radius);
List<RectF> prevLabelsBounds = new ArrayList<RectF>();
for (int i = 0; i < sLength; i++) {
paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());
float value = (float) mDataset.getValue(i);
float angle = (float) (value / total * 360);
canvas.drawArc(oval, currentAngle, angle, true, paint);
drawLabel(canvas, mDataset.getCategory(i), mRenderer, prevLabelsBounds, mCenterX, mCenterY,
shortRadius, longRadius, currentAngle, angle, left, right, mRenderer.getLabelsColor(), paint);
// Save details for getSeries functionality
if (loadPieCfg) {
mPieMapper.addPieSegment(i, value, currentAngle, angle);
}
currentAngle += angle;
}
prevLabelsBounds.clear();
drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
drawTitle(canvas, x, y, width, paint);
}
public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
return mPieMapper.getSeriesAndPointForScreenCoordinate(screenPoint);
}
}

View File

@ -1,124 +0,0 @@
package org.achartengine.chart;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.achartengine.model.Point;
import org.achartengine.model.SeriesSelection;
/**
* PieChart Segment Selection Management.
*/
public class PieMapper implements Serializable {
private List<PieSegment> mPieSegmentList = new ArrayList<PieSegment>();
private int mPieChartRadius;
private int mCenterX, mCenterY;
/**
* Set PieChart location on screen.
*
* @param pieRadius
* @param centerX
* @param centerY
*/
public void setDimensions(int pieRadius, int centerX, int centerY) {
mPieChartRadius = pieRadius;
mCenterX = centerX;
mCenterY = centerY;
}
/**
* If we have all PieChart Config then there is no point in reloading it
*
* @param datasetSize
* @return true if cfg for each segment is present
*/
public boolean areAllSegmentPresent(int datasetSize) {
return mPieSegmentList.size() == datasetSize;
}
/**
* Add configuration for a PieChart Segment
*
* @param dataIndex
* @param value
* @param startAngle
* @param angle
*/
public void addPieSegment(int dataIndex, float value, float startAngle, float angle) {
mPieSegmentList.add(new PieSegment(dataIndex, value, startAngle, angle));
}
/**
* Clears the pie segments list.
*/
public void clearPieSegments() {
mPieSegmentList.clear();
}
/**
* Fetches angle relative to pie chart center point where 3 O'Clock is 0 and
* 12 O'Clock is 270degrees
*
* @param screenPoint
* @return angle in degress from 0-360.
*/
public double getAngle(Point screenPoint) {
double dx = screenPoint.getX() - mCenterX;
// Minus to correct for coord re-mapping
double dy = -(screenPoint.getY() - mCenterY);
double inRads = Math.atan2(dy, dx);
// We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12
// O'clock
if (inRads < 0) {
inRads = Math.abs(inRads);
} else {
inRads = 2 * Math.PI - inRads;
}
return Math.toDegrees(inRads);
}
/**
* Checks if Point falls within PieChart
*
* @param screenPoint
* @return true if in PieChart
*/
public boolean isOnPieChart(Point screenPoint) {
// Using a bit of Pythagoras
// inside circle if (x-center_x)**2 + (y-center_y)**2 <= radius**2:
double sqValue = (Math.pow(mCenterX - screenPoint.getX(), 2) + Math.pow(
mCenterY - screenPoint.getY(), 2));
double radiusSquared = mPieChartRadius * mPieChartRadius;
return sqValue <= radiusSquared;
}
/**
* Fetches the SeriesSelection for the PieSegment selected.
*
* @param screenPoint - the user tap location
* @return null if screen point is not in PieChart or its config if it is
*/
public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
if (isOnPieChart(screenPoint)) {
double angleFromPieCenter = getAngle(screenPoint);
for (PieSegment pieSeg : mPieSegmentList) {
if (pieSeg.isInSegment(angleFromPieCenter)) {
return new SeriesSelection(0, pieSeg.getDataIndex(), pieSeg.getValue(),
pieSeg.getValue());
}
}
}
return null;
}
}

View File

@ -1,55 +0,0 @@
package org.achartengine.chart;
import java.io.Serializable;
/**
* Holds An PieChart Segment
*/
public class PieSegment implements Serializable {
private float mStartAngle;
private float mEndAngle;
private int mDataIndex;
private float mValue;
public PieSegment(int dataIndex, float value, float startAngle, float angle) {
mStartAngle = startAngle;
mEndAngle = angle + startAngle;
mDataIndex = dataIndex;
mValue = value;
}
/**
* Checks if angle falls in segment.
*
* @param angle
* @return true if in segment, false otherwise.
*/
public boolean isInSegment(double angle) {
return angle >= mStartAngle && angle <= mEndAngle;
}
protected float getStartAngle() {
return mStartAngle;
}
protected float getEndAngle() {
return mEndAngle;
}
protected int getDataIndex() {
return mDataIndex;
}
protected float getValue() {
return mValue;
}
public String toString() {
return "mDataIndex=" + mDataIndex + ",mValue=" + mValue + ",mStartAngle=" + mStartAngle
+ ",mEndAngle=" + mEndAngle;
}
}

View File

@ -1,90 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
/**
* The chart point style enumerator.
*/
public enum PointStyle {
X("x"), CIRCLE("circle"), TRIANGLE("triangle"), SQUARE("square"), DIAMOND("diamond"), POINT(
"point");
/** The point shape name. */
private String mName;
/**
* The point style enum constructor.
*
* @param name the name
*/
private PointStyle(String name) {
mName = name;
}
/**
* Returns the point shape name.
*
* @return the point shape name
*/
public String getName() {
return mName;
}
/**
* Returns the point shape name.
*
* @return the point shape name
*/
public String toString() {
return getName();
}
/**
* Return the point shape that has the provided symbol.
*
* @param name the point style name
* @return the point shape
*/
public static PointStyle getPointStyleForName(String name) {
PointStyle pointStyle = null;
PointStyle[] styles = values();
int length = styles.length;
for (int i = 0; i < length && pointStyle == null; i++) {
if (styles[i].mName.equals(name)) {
pointStyle = styles[i];
}
}
return pointStyle;
}
/**
* Returns the point shape index based on the given name.
*
* @return the point shape index
*/
public static int getIndexForName(String name) {
int index = -1;
PointStyle[] styles = values();
int length = styles.length;
for (int i = 0; i < length && index < 0; i++) {
if (styles[i].mName.equals(name)) {
index = i;
}
}
return Math.max(0, index);
}
}

View File

@ -1,141 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
/**
* The range bar chart rendering class.
*/
public class RangeBarChart extends BarChart {
/** The chart type. */
public static final String TYPE = "RangeBar";
RangeBarChart() {
}
/**
* Builds a new range bar chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
* @param type the range bar chart type
*/
public RangeBarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
super(dataset, renderer, type);
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range) {
int seriesNr = mDataset.getSeriesCount();
int length = points.length;
paint.setColor(seriesRenderer.getColor());
paint.setStyle(Style.FILL);
float halfDiffX = getHalfDiffX(points, length, seriesNr, range);
int start = 0;
if (startIndex > 0) {
start = 2;
}
for (int i = start; i < length; i += 4) {
if (points.length > i + 3) {
float xMin = points[i];
float yMin = points[i + 1];
// xMin = xMax
float xMax = points[i + 2];
float yMax = points[i + 3];
drawBar(canvas, xMin, yMin, xMax, yMax, halfDiffX, seriesNr, seriesIndex, paint);
}
}
paint.setColor(seriesRenderer.getColor());
}
/**
* The graphical representation of the series values as text.
*
* @param canvas the canvas to paint to
* @param series the series to be painted
* @param renderer the series renderer
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,
Paint paint, float[] points, int seriesIndex, int startIndex) {
int seriesNr = mDataset.getSeriesCount();
float halfDiffX = getHalfDiffX(points, points.length, seriesNr, 0);
int start = 0;
if (startIndex > 0) {
start = 2;
}
for (int i = start; i < points.length; i += 4) {
int index = startIndex + i / 2;
float x = points[i];
if (mType == Type.DEFAULT) {
x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;
}
if (!isNullValue(series.getY(index + 1)) && points.length > i + 3) {
// draw the maximum value
drawText(canvas, getLabel(series.getY(index + 1)), x,
points[i + 3] - renderer.getChartValuesSpacing(), paint, 0);
}
if (!isNullValue(series.getY(index)) && points.length > i + 1) {
// draw the minimum value
drawText(canvas, getLabel(series.getY(index)), x,
points[i + 1] + renderer.getChartValuesTextSize() + renderer.getChartValuesSpacing()
- 3, paint, 0);
}
}
}
/**
* Returns the value of a constant used to calculate the half-distance.
*
* @return the constant value
*/
protected float getCoeficient() {
return 0.5f;
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
}

View File

@ -1,143 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.CategorySeries;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.SimpleSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
/**
* An abstract class to be extended by round like chart rendering classes.
*/
public abstract class RoundChart extends AbstractChart {
/** The legend shape width. */
protected static final int SHAPE_WIDTH = 10;
/** The series dataset. */
protected CategorySeries mDataset;
/** The series renderer. */
protected DefaultRenderer mRenderer;
/** A no value constant. */
protected static final int NO_VALUE = Integer.MAX_VALUE;
/** The chart center X axis. */
protected int mCenterX = NO_VALUE;
/** The chart center y axis. */
protected int mCenterY = NO_VALUE;
/**
* Round chart.
*
* @param dataset the series dataset
* @param renderer the series renderer
*/
public RoundChart(CategorySeries dataset, DefaultRenderer renderer) {
mDataset = dataset;
mRenderer = renderer;
}
/**
* The graphical representation of the round chart title.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param paint the paint
*/
public void drawTitle(Canvas canvas, int x, int y, int width, Paint paint) {
if (mRenderer.isShowLabels()) {
paint.setColor(mRenderer.getLabelsColor());
paint.setTextAlign(Align.CENTER);
paint.setTextSize(mRenderer.getChartTitleTextSize());
canvas.drawText(mRenderer.getChartTitle(), x + width / 2,
y + mRenderer.getChartTitleTextSize(), paint);
}
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return SHAPE_WIDTH;
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
canvas.drawRect(x, y - SHAPE_WIDTH / 2, x + SHAPE_WIDTH, y + SHAPE_WIDTH / 2, paint);
}
/**
* Returns the renderer.
*
* @return the renderer
*/
public DefaultRenderer getRenderer() {
return mRenderer;
}
/**
* Returns the center on X axis.
*
* @return the center on X axis
*/
public int getCenterX() {
return mCenterX;
}
/**
* Returns the center on Y axis.
*
* @return the center on Y axis
*/
public int getCenterY() {
return mCenterY;
}
/**
* Sets a new center on X axis.
*
* @param centerX center on X axis
*/
public void setCenterX(int centerX) {
mCenterX = centerX;
}
/**
* Sets a new center on Y axis.
*
* @param centerY center on Y axis
*/
public void setCenterY(int centerY) {
mCenterY = centerY;
}
}

View File

@ -1,266 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
/**
* The scatter chart rendering class.
*/
public class ScatterChart extends XYChart {
/** The constant to identify this chart type. */
public static final String TYPE = "Scatter";
/** The default point shape size. */
private static final float SIZE = 3;
/** The legend shape width. */
private static final int SHAPE_WIDTH = 10;
/** The point shape size. */
private float size = SIZE;
ScatterChart() {
}
/**
* Builds a new scatter chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
*/
public ScatterChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
super(dataset, renderer);
size = renderer.getPointSize();
}
// TODO: javadoc
protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
super.setDatasetRenderer(dataset, renderer);
size = renderer.getPointSize();
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range) {
XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;
paint.setColor(renderer.getColor());
if (renderer.isFillPoints()) {
paint.setStyle(Style.FILL);
} else {
paint.setStyle(Style.STROKE);
}
int length = points.length;
switch (renderer.getPointStyle()) {
case X:
for (int i = 0; i < length; i += 2) {
drawX(canvas, paint, points[i], points[i + 1]);
}
break;
case CIRCLE:
for (int i = 0; i < length; i += 2) {
drawCircle(canvas, paint, points[i], points[i + 1]);
}
break;
case TRIANGLE:
float[] path = new float[6];
for (int i = 0; i < length; i += 2) {
drawTriangle(canvas, paint, path, points[i], points[i + 1]);
}
break;
case SQUARE:
for (int i = 0; i < length; i += 2) {
drawSquare(canvas, paint, points[i], points[i + 1]);
}
break;
case DIAMOND:
path = new float[8];
for (int i = 0; i < length; i += 2) {
drawDiamond(canvas, paint, path, points[i], points[i + 1]);
}
break;
case POINT:
canvas.drawPoints(points, paint);
break;
}
}
@Override
protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
float yAxisValue, int seriesIndex, int startIndex, int range) {
int length = points.length;
ClickableArea[] ret = new ClickableArea[length / 2];
for (int i = 0; i < length; i += 2) {
int selectableBuffer = mRenderer.getSelectableBuffer();
ret[i / 2] = new ClickableArea(new RectF(points[i] - selectableBuffer, points[i + 1]
- selectableBuffer, points[i] + selectableBuffer, points[i + 1] + selectableBuffer),
values[i], values[i + 1]);
}
return ret;
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public int getLegendShapeWidth(int seriesIndex) {
return SHAPE_WIDTH;
}
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
int seriesIndex, Paint paint) {
if (((XYSeriesRenderer) renderer).isFillPoints()) {
paint.setStyle(Style.FILL);
} else {
paint.setStyle(Style.STROKE);
}
switch (((XYSeriesRenderer) renderer).getPointStyle()) {
case X:
drawX(canvas, paint, x + SHAPE_WIDTH, y);
break;
case CIRCLE:
drawCircle(canvas, paint, x + SHAPE_WIDTH, y);
break;
case TRIANGLE:
drawTriangle(canvas, paint, new float[6], x + SHAPE_WIDTH, y);
break;
case SQUARE:
drawSquare(canvas, paint, x + SHAPE_WIDTH, y);
break;
case DIAMOND:
drawDiamond(canvas, paint, new float[8], x + SHAPE_WIDTH, y);
break;
case POINT:
canvas.drawPoint(x + SHAPE_WIDTH, y, paint);
break;
}
}
/**
* The graphical representation of an X point shape.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
*/
private void drawX(Canvas canvas, Paint paint, float x, float y) {
canvas.drawLine(x - size, y - size, x + size, y + size, paint);
canvas.drawLine(x + size, y - size, x - size, y + size, paint);
}
/**
* The graphical representation of a circle point shape.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
*/
private void drawCircle(Canvas canvas, Paint paint, float x, float y) {
canvas.drawCircle(x, y, size, paint);
}
/**
* The graphical representation of a triangle point shape.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param path the triangle path
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
*/
private void drawTriangle(Canvas canvas, Paint paint, float[] path, float x, float y) {
path[0] = x;
path[1] = y - size - size / 2;
path[2] = x - size;
path[3] = y + size;
path[4] = x + size;
path[5] = path[3];
drawPath(canvas, path, paint, true);
}
/**
* The graphical representation of a square point shape.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
*/
private void drawSquare(Canvas canvas, Paint paint, float x, float y) {
canvas.drawRect(x - size, y - size, x + size, y + size, paint);
}
/**
* The graphical representation of a diamond point shape.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param path the diamond path
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
*/
private void drawDiamond(Canvas canvas, Paint paint, float[] path, float x, float y) {
path[0] = x;
path[1] = y - size;
path[2] = x - size;
path[3] = y;
path[4] = x;
path[5] = y + size;
path[6] = x + size;
path[7] = y;
drawPath(canvas, path, paint, true);
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
}

View File

@ -1,208 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* The time chart rendering class.
*/
public class TimeChart extends LineChart {
/** The constant to identify this chart type. */
public static final String TYPE = "Time";
/** The number of milliseconds in a day. */
public static final long DAY = 24 * 60 * 60 * 1000;
/** The date format pattern to be used in formatting the X axis labels. */
private String mDateFormat;
/** If X axis value selection algorithm to be used. */
private boolean mXAxisSmart = true;
/** The starting point for labels. */
private Double mStartPoint;
TimeChart() {
}
/**
* Builds a new time chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
*/
public TimeChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
super(dataset, renderer);
}
/**
* Returns the date format pattern to be used for formatting the X axis
* labels.
*
* @return the date format pattern for the X axis labels
*/
public String getDateFormat() {
return mDateFormat;
}
/**
* Sets the date format pattern to be used for formatting the X axis labels.
*
* @param format the date format pattern for the X axis labels. If null, an
* appropriate default format will be used.
*/
public void setDateFormat(String format) {
mDateFormat = format;
}
/**
* If X axis smart values to be used.
*
* @return if smart values to be used
*/
public boolean isXAxisSmart() {
return mXAxisSmart;
}
/**
* Sets if X axis smart values to be used.
*
* @param smart smart values to be used
*/
public void setXAxisSmart(boolean smart) {
mXAxisSmart = smart;
}
/**
* The graphical representation of the labels on the X axis.
*
* @param xLabels the X labels values
* @param xTextLabelLocations the X text label locations
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param left the left value of the labels area
* @param top the top value of the labels area
* @param bottom the bottom value of the labels area
* @param xPixelsPerUnit the amount of pixels per one unit in the chart labels
* @param minX the minimum value on the X axis in the chart
* @param maxX the maximum value on the X axis in the chart
*/
@Override
protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,
Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {
int length = xLabels.size();
if (length > 0) {
boolean showLabels = mRenderer.isShowLabels();
boolean showGridY = mRenderer.isShowGridY();
DateFormat format = getDateFormat(xLabels.get(0), xLabels.get(length - 1));
for (int i = 0; i < length; i++) {
long label = Math.round(xLabels.get(i));
float xLabel = (float) (left + xPixelsPerUnit * (label - minX));
if (showLabels) {
paint.setColor(mRenderer.getXLabelsColor());
canvas
.drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);
drawText(canvas, format.format(new Date(label)), xLabel,
bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());
}
if (showGridY) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(xLabel, bottom, xLabel, top, paint);
}
}
}
drawXTextLabels(xTextLabelLocations, canvas, paint, true, left, top, bottom, xPixelsPerUnit,
minX, maxX);
}
/**
* Returns the date format pattern to be used, based on the date range.
*
* @param start the start date in milliseconds
* @param end the end date in milliseconds
* @return the date format
*/
private DateFormat getDateFormat(double start, double end) {
if (mDateFormat != null) {
SimpleDateFormat format = null;
try {
format = new SimpleDateFormat(mDateFormat);
return format;
} catch (Exception e) {
// do nothing here
}
}
DateFormat format = SimpleDateFormat.getDateInstance(SimpleDateFormat.MEDIUM);
double diff = end - start;
if (diff > DAY && diff < 5 * DAY) {
format = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);
} else if (diff < DAY) {
format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM);
}
return format;
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public String getChartType() {
return TYPE;
}
protected List<Double> getXLabels(double min, double max, int count) {
if (!mXAxisSmart) {
return super.getXLabels(min, max, count);
}
if (mStartPoint == null) {
mStartPoint = min - (min % DAY) + DAY + new Date(Math.round(min)).getTimezoneOffset() * 60
* 1000;
}
if (count > 25) {
count = 25;
}
final double cycleMath = (max - min) / count;
double cycle = DAY;
if (cycleMath <= DAY) {
while (cycleMath < cycle / 2) {
cycle = cycle / 2;
}
} else {
while (cycleMath > cycle) {
cycle = cycle * 2;
}
}
final List<Double> result = new ArrayList<Double>();
double val = mStartPoint - Math.floor((mStartPoint - min) / cycle) * cycle;
int i = 0;
while (val < max && i++ <= count) {
result.add(val);
val += cycle;
}
return result;
}
}

View File

@ -1,896 +0,0 @@
/**
* Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.chart;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import org.achartengine.model.Point;
import org.achartengine.model.SeriesSelection;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.BasicStroke;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;
import org.achartengine.util.MathHelper;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
/**
* The XY chart rendering class.
*/
public abstract class XYChart extends AbstractChart {
/** The multiple series dataset. */
protected XYMultipleSeriesDataset mDataset;
/** The multiple series renderer. */
protected XYMultipleSeriesRenderer mRenderer;
/** The current scale value. */
private float mScale;
/** The current translate value. */
private float mTranslate;
/** The canvas center point. */
private Point mCenter;
/** The visible chart area, in screen coordinates. */
private Rect mScreenR;
/** The calculated range. */
private final Map<Integer, double[]> mCalcRange = new HashMap<Integer, double[]>();
/**
* The clickable areas for all points. The array index is the series index,
* and the RectF list index is the point index in that series.
*/
private Map<Integer, List<ClickableArea>> clickableAreas = new HashMap<Integer, List<ClickableArea>>();
protected XYChart() {
}
/**
* Builds a new XY chart instance.
*
* @param dataset the multiple series dataset
* @param renderer the multiple series renderer
*/
public XYChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
mDataset = dataset;
mRenderer = renderer;
}
// TODO: javadoc
protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
mDataset = dataset;
mRenderer = renderer;
}
/**
* The graphical representation of the XY chart.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint
*/
public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
paint.setAntiAlias(mRenderer.isAntialiasing());
int legendSize = getLegendSize(mRenderer, height / 5, mRenderer.getAxisTitleTextSize());
int[] margins = mRenderer.getMargins();
int left = x + margins[1];
int top = y + margins[0];
int right = x + width - margins[3];
int sLength = mDataset.getSeriesCount();
String[] titles = new String[sLength];
for (int i = 0; i < sLength; i++) {
titles[i] = mDataset.getSeriesAt(i).getTitle();
}
if (mRenderer.isFitLegend() && mRenderer.isShowLegend()) {
legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,
paint, true);
}
int bottom = y + height - margins[2] - legendSize;
if (mScreenR == null) {
mScreenR = new Rect();
}
mScreenR.set(left, top, right, bottom);
drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
if (paint.getTypeface() == null
|| !paint.getTypeface().toString().equals(mRenderer.getTextTypefaceName())
|| paint.getTypeface().getStyle() != mRenderer.getTextTypefaceStyle()) {
paint.setTypeface(Typeface.create(mRenderer.getTextTypefaceName(),
mRenderer.getTextTypefaceStyle()));
}
Orientation or = mRenderer.getOrientation();
if (or == Orientation.VERTICAL) {
right -= legendSize;
bottom += legendSize - 20;
}
int angle = or.getAngle();
boolean rotate = angle == 90;
mScale = (float) (height) / width;
mTranslate = Math.abs(width - height) / 2;
if (mScale < 1) {
mTranslate *= -1;
}
mCenter = new Point((x + width) / 2, (y + height) / 2);
if (rotate) {
transform(canvas, angle, false);
}
int maxScaleNumber = -Integer.MAX_VALUE;
for (int i = 0; i < sLength; i++) {
maxScaleNumber = Math.max(maxScaleNumber, mDataset.getSeriesAt(i).getScaleNumber());
}
maxScaleNumber++;
if (maxScaleNumber < 0) {
return;
}
double[] minX = new double[maxScaleNumber];
double[] maxX = new double[maxScaleNumber];
double[] minY = new double[maxScaleNumber];
double[] maxY = new double[maxScaleNumber];
boolean[] isMinXSet = new boolean[maxScaleNumber];
boolean[] isMaxXSet = new boolean[maxScaleNumber];
boolean[] isMinYSet = new boolean[maxScaleNumber];
boolean[] isMaxYSet = new boolean[maxScaleNumber];
for (int i = 0; i < maxScaleNumber; i++) {
minX[i] = mRenderer.getXAxisMin(i);
maxX[i] = mRenderer.getXAxisMax(i);
minY[i] = mRenderer.getYAxisMin(i);
maxY[i] = mRenderer.getYAxisMax(i);
isMinXSet[i] = mRenderer.isMinXSet(i);
isMaxXSet[i] = mRenderer.isMaxXSet(i);
isMinYSet[i] = mRenderer.isMinYSet(i);
isMaxYSet[i] = mRenderer.isMaxYSet(i);
if (mCalcRange.get(i) == null) {
mCalcRange.put(i, new double[4]);
}
}
double[] xPixelsPerUnit = new double[maxScaleNumber];
double[] yPixelsPerUnit = new double[maxScaleNumber];
for (int i = 0; i < sLength; i++) {
XYSeries series = mDataset.getSeriesAt(i);
int scale = series.getScaleNumber();
if (series.getItemCount() == 0) {
continue;
}
if (!isMinXSet[scale]) {
double minimumX = series.getMinX();
minX[scale] = Math.min(minX[scale], minimumX);
mCalcRange.get(scale)[0] = minX[scale];
}
if (!isMaxXSet[scale]) {
double maximumX = series.getMaxX();
maxX[scale] = Math.max(maxX[scale], maximumX);
mCalcRange.get(scale)[1] = maxX[scale];
}
if (!isMinYSet[scale]) {
double minimumY = series.getMinY();
minY[scale] = Math.min(minY[scale], (float) minimumY);
mCalcRange.get(scale)[2] = minY[scale];
}
if (!isMaxYSet[scale]) {
double maximumY = series.getMaxY();
maxY[scale] = Math.max(maxY[scale], (float) maximumY);
mCalcRange.get(scale)[3] = maxY[scale];
}
}
for (int i = 0; i < maxScaleNumber; i++) {
if (maxX[i] - minX[i] != 0) {
xPixelsPerUnit[i] = (right - left) / (maxX[i] - minX[i]);
}
if (maxY[i] - minY[i] != 0) {
yPixelsPerUnit[i] = (float) ((bottom - top) / (maxY[i] - minY[i]));
}
}
boolean hasValues = false;
// use a linked list for these reasons:
// 1) Avoid a large contiguous memory allocation
// 2) We don't need random seeking, only sequential reading/writing, so
// linked list makes sense
clickableAreas = new HashMap<Integer, List<ClickableArea>>();
for (int i = 0; i < sLength; i++) {
XYSeries series = mDataset.getSeriesAt(i);
int scale = series.getScaleNumber();
if (series.getItemCount() == 0) {
continue;
}
hasValues = true;
SimpleSeriesRenderer seriesRenderer = mRenderer.getSeriesRendererAt(i);
// int originalValuesLength = series.getItemCount();
// int valuesLength = originalValuesLength;
// int length = valuesLength * 2;
List<Float> points = new ArrayList<Float>();
List<Double> values = new ArrayList<Double>();
float yAxisValue = Math.min(bottom, (float) (bottom + yPixelsPerUnit[scale] * minY[scale]));
LinkedList<ClickableArea> clickableArea = new LinkedList<ClickableArea>();
clickableAreas.put(i, clickableArea);
SortedMap<Double, Double> range = series.getRange(minX[scale], maxX[scale], 1);
int startIndex = -1;
int intRange = range.lastKey().intValue() - range.firstKey().intValue();
for (Entry<Double, Double> value : range.entrySet()) {
double xValue = value.getKey();
double yValue = value.getValue();
if (startIndex < 0) {
startIndex = series.getIndexForKey(xValue);
}
// points.add((float) (left + xPixelsPerUnit[scale]
// * (value.getKey().floatValue() - minX[scale])));
// points.add((float) (bottom - yPixelsPerUnit[scale]
// * (value.getValue().floatValue() - minY[scale])));
values.add(value.getKey());
values.add(value.getValue());
if (!isNullValue(yValue)) {
points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale])));
points.add((float) (bottom - yPixelsPerUnit[scale] * (yValue - minY[scale])));
} else if (isRenderNullValues()) {
points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale])));
points.add((float) (bottom - yPixelsPerUnit[scale] * (-minY[scale])));
} else {
if (points.size() > 0) {
drawSeries(series, canvas, paint, points, seriesRenderer, yAxisValue, i, or, startIndex, intRange);
ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints(
MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i,
startIndex, intRange);
clickableArea.addAll(Arrays.asList(clickableAreasForSubSeries));
points.clear();
values.clear();
}
clickableArea.add(null);
}
}
if (points.size() > 0) {
drawSeries(series, canvas, paint, points, seriesRenderer, yAxisValue, i, or, startIndex, intRange);
ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints(
MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i, startIndex, intRange);
clickableArea.addAll(Arrays.asList(clickableAreasForSubSeries));
}
}
// draw stuff over the margins such as data doesn't render on these areas
drawBackground(mRenderer, canvas, x, bottom, width, height - bottom, paint, true,
mRenderer.getMarginsColor());
drawBackground(mRenderer, canvas, x, y, width, margins[0], paint, true,
mRenderer.getMarginsColor());
if (or == Orientation.HORIZONTAL) {
drawBackground(mRenderer, canvas, x, y, left - x, height - y, paint, true,
mRenderer.getMarginsColor());
drawBackground(mRenderer, canvas, right, y, margins[3], height - y, paint, true,
mRenderer.getMarginsColor());
} else if (or == Orientation.VERTICAL) {
drawBackground(mRenderer, canvas, right, y, width - right, height - y, paint, true,
mRenderer.getMarginsColor());
drawBackground(mRenderer, canvas, x, y, left - x, height - y, paint, true,
mRenderer.getMarginsColor());
}
boolean showLabels = mRenderer.isShowLabels() && hasValues;
boolean showGridX = mRenderer.isShowGridX();
boolean showCustomTextGrid = mRenderer.isShowCustomTextGrid();
if (showLabels || showGridX) {
List<Double> xLabels = getValidLabels(getXLabels(minX[0], maxX[0], mRenderer.getXLabels()));
Map<Integer, List<Double>> allYLabels = getYLabels(minY, maxY, maxScaleNumber);
int xLabelsLeft = left;
if (showLabels) {
paint.setColor(mRenderer.getXLabelsColor());
paint.setTextSize(mRenderer.getLabelsTextSize());
paint.setTextAlign(mRenderer.getXLabelsAlign());
if (mRenderer.getXLabelsAlign() == Align.LEFT) {
xLabelsLeft += mRenderer.getLabelsTextSize() / 4;
}
}
drawXLabels(xLabels, mRenderer.getXTextLabelLocations(), canvas, paint, xLabelsLeft, top,
bottom, xPixelsPerUnit[0], minX[0], maxX[0]);
drawYLabels(allYLabels, canvas, paint, maxScaleNumber, left, right, bottom, yPixelsPerUnit,
minY);
if (showLabels) {
paint.setColor(mRenderer.getLabelsColor());
for (int i = 0; i < maxScaleNumber; i++) {
Align axisAlign = mRenderer.getYAxisAlign(i);
Double[] yTextLabelLocations = mRenderer.getYTextLabelLocations(i);
for (Double location : yTextLabelLocations) {
if (minY[i] <= location && location <= maxY[i]) {
float yLabel = (float) (bottom - yPixelsPerUnit[i]
* (location - minY[i]));
String label = mRenderer.getYTextLabel(location, i);
paint.setColor(mRenderer.getYLabelsColor(i));
paint.setTextAlign(mRenderer.getYLabelsAlign(i));
if (or == Orientation.HORIZONTAL) {
if (axisAlign == Align.LEFT) {
canvas.drawLine(left + getLabelLinePos(axisAlign), yLabel, left, yLabel, paint);
drawText(canvas, label, left, yLabel - 2, paint, mRenderer.getYLabelsAngle());
} else {
canvas.drawLine(right, yLabel, right + getLabelLinePos(axisAlign), yLabel, paint);
drawText(canvas, label, right, yLabel - 2, paint, mRenderer.getYLabelsAngle());
}
if (showCustomTextGrid) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(left, yLabel, right, yLabel, paint);
}
} else {
canvas.drawLine(right - getLabelLinePos(axisAlign), yLabel, right, yLabel, paint);
drawText(canvas, label, right + 10, yLabel - 2, paint, mRenderer.getYLabelsAngle());
if (showCustomTextGrid) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(right, yLabel, left, yLabel, paint);
}
}
}
}
}
}
if (showLabels) {
paint.setColor(mRenderer.getLabelsColor());
float size = mRenderer.getAxisTitleTextSize();
paint.setTextSize(size);
paint.setTextAlign(Align.CENTER);
if (or == Orientation.HORIZONTAL) {
drawText(canvas, mRenderer.getXTitle(), x + width / 2,
bottom + mRenderer.getLabelsTextSize() * 4 / 3 + size, paint, 0);
for (int i = 0; i < maxScaleNumber; i++) {
Align axisAlign = mRenderer.getYAxisAlign(i);
if (axisAlign == Align.LEFT) {
drawText(canvas, mRenderer.getYTitle(i), x + size, y + height / 2, paint, -90);
} else {
drawText(canvas, mRenderer.getYTitle(i), x + width, y + height / 2, paint, -90);
}
}
paint.setTextSize(mRenderer.getChartTitleTextSize());
drawText(canvas, mRenderer.getChartTitle(), x + width / 2,
y + mRenderer.getChartTitleTextSize(), paint, 0);
} else if (or == Orientation.VERTICAL) {
drawText(canvas, mRenderer.getXTitle(), x + width / 2, y + height - size, paint, -90);
drawText(canvas, mRenderer.getYTitle(), right + 20, y + height / 2, paint, 0);
paint.setTextSize(mRenderer.getChartTitleTextSize());
drawText(canvas, mRenderer.getChartTitle(), x + size, top + height / 2, paint, 0);
}
}
}
if (or == Orientation.HORIZONTAL) {
drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
} else if (or == Orientation.VERTICAL) {
transform(canvas, angle, true);
drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
transform(canvas, angle, false);
}
if (mRenderer.isShowAxes()) {
paint.setColor(mRenderer.getAxesColor());
canvas.drawLine(left, bottom, right, bottom, paint);
boolean rightAxis = false;
for (int i = 0; i < maxScaleNumber && !rightAxis; i++) {
rightAxis = mRenderer.getYAxisAlign(i) == Align.RIGHT;
}
if (or == Orientation.HORIZONTAL) {
canvas.drawLine(left, top, left, bottom, paint);
if (rightAxis) {
canvas.drawLine(right, top, right, bottom, paint);
}
} else if (or == Orientation.VERTICAL) {
canvas.drawLine(right, top, right, bottom, paint);
}
}
if (rotate) {
transform(canvas, angle, true);
}
}
protected List<Double> getXLabels(double min, double max, int count) {
return MathHelper.getLabels(min, max, count);
}
protected Map<Integer, List<Double>> getYLabels(double[] minY, double[] maxY, int maxScaleNumber) {
Map<Integer, List<Double>> allYLabels = new HashMap<Integer, List<Double>>();
for (int i = 0; i < maxScaleNumber; i++) {
allYLabels.put(i,
getValidLabels(MathHelper.getLabels(minY[i], maxY[i], mRenderer.getYLabels())));
}
return allYLabels;
}
protected Rect getScreenR() {
return mScreenR;
}
protected void setScreenR(Rect screenR) {
mScreenR = screenR;
}
private List<Double> getValidLabels(List<Double> labels) {
List<Double> result = new ArrayList<Double>(labels);
for (Double label : labels) {
if (label.isNaN()) {
result.remove(label);
}
}
return result;
}
/**
* Draws the series.
*
* @param series the series
* @param canvas the canvas
* @param paint the paint object
* @param pointsList the points to be rendered
* @param seriesRenderer the series renderer
* @param yAxisValue the y axis value in pixels
* @param seriesIndex the series index
* @param or the orientation
* @param startIndex the start index of the rendering points
*/
protected void drawSeries(XYSeries series, Canvas canvas, Paint paint, List<Float> pointsList,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, Orientation or,
int startIndex, int range) {
BasicStroke stroke = seriesRenderer.getStroke();
Cap cap = paint.getStrokeCap();
Join join = paint.getStrokeJoin();
float miter = paint.getStrokeMiter();
PathEffect pathEffect = paint.getPathEffect();
Style style = paint.getStyle();
if (stroke != null) {
PathEffect effect = null;
if (stroke.getIntervals() != null) {
effect = new DashPathEffect(stroke.getIntervals(), stroke.getPhase());
}
setStroke(stroke.getCap(), stroke.getJoin(), stroke.getMiter(), Style.FILL_AND_STROKE,
effect, paint);
}
float[] points = MathHelper.getFloats(pointsList);
drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, seriesIndex, startIndex, range);
if (isRenderPoints(seriesRenderer)) {
ScatterChart pointsChart = getPointsChart();
if (pointsChart != null) {
pointsChart.drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, seriesIndex,
startIndex, range);
}
}
paint.setTextSize(seriesRenderer.getChartValuesTextSize());
if (or == Orientation.HORIZONTAL) {
paint.setTextAlign(Align.CENTER);
} else {
paint.setTextAlign(Align.LEFT);
}
if (seriesRenderer.isDisplayChartValues()) {
paint.setTextAlign(seriesRenderer.getChartValuesTextAlign());
drawChartValuesText(canvas, series, seriesRenderer, paint, points, seriesIndex, startIndex);
}
if (stroke != null) {
setStroke(cap, join, miter, style, pathEffect, paint);
}
}
private void setStroke(Cap cap, Join join, float miter, Style style, PathEffect pathEffect,
Paint paint) {
paint.setStrokeCap(cap);
paint.setStrokeJoin(join);
paint.setStrokeMiter(miter);
paint.setPathEffect(pathEffect);
paint.setStyle(style);
}
/**
* The graphical representation of the series values as text.
*
* @param canvas the canvas to paint to
* @param series the series to be painted
* @param renderer the series renderer
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,
Paint paint, float[] points, int seriesIndex, int startIndex) {
for (int k = 0; k < points.length; k += 2) {
drawText(canvas, getLabel(series.getY(startIndex + k / 2)), points[k], points[k + 1]
- renderer.getChartValuesSpacing(), paint, 0);
}
}
/**
* The graphical representation of a text, to handle both HORIZONTAL and
* VERTICAL orientations and extra rotation angles.
*
* @param canvas the canvas to paint to
* @param text the text to be rendered
* @param x the X axis location of the text
* @param y the Y axis location of the text
* @param paint the paint to be used for drawing
* @param extraAngle the text angle
*/
protected void drawText(Canvas canvas, String text, float x, float y, Paint paint,
float extraAngle) {
float angle = -mRenderer.getOrientation().getAngle() + extraAngle;
if (angle != 0) {
// canvas.scale(1 / mScale, mScale);
canvas.rotate(angle, x, y);
}
canvas.drawText(text, x, y, paint);
if (angle != 0) {
canvas.rotate(-angle, x, y);
// canvas.scale(mScale, 1 / mScale);
}
}
/**
* Transform the canvas such as it can handle both HORIZONTAL and VERTICAL
* orientations.
*
* @param canvas the canvas to paint to
* @param angle the angle of rotation
* @param inverse if the inverse transform needs to be applied
*/
private void transform(Canvas canvas, float angle, boolean inverse) {
if (inverse) {
canvas.scale(1 / mScale, mScale);
canvas.translate(mTranslate, -mTranslate);
canvas.rotate(-angle, mCenter.getX(), mCenter.getY());
} else {
canvas.rotate(angle, mCenter.getX(), mCenter.getY());
canvas.translate(-mTranslate, mTranslate);
canvas.scale(mScale, 1 / mScale);
}
}
/**
* Makes sure the fraction digit is not displayed, if not needed.
*
* @param label the input label value
* @return the label without the useless fraction digit
*/
protected String getLabel(double label) {
String text = "";
if (label == Math.round(label)) {
text = Math.round(label) + "";
} else {
text = label + "";
}
return text;
}
/**
* The graphical representation of the labels on the X axis.
*
* @param xLabels the X labels values
* @param xTextLabelLocations the X text label locations
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param left the left value of the labels area
* @param top the top value of the labels area
* @param bottom the bottom value of the labels area
* @param xPixelsPerUnit the amount of pixels per one unit in the chart labels
* @param minX the minimum value on the X axis in the chart
* @param maxX the maximum value on the X axis in the chart
*/
protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,
Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {
int length = xLabels.size();
boolean showLabels = mRenderer.isShowLabels();
boolean showGridY = mRenderer.isShowGridY();
for (int i = 0; i < length; i++) {
double label = xLabels.get(i);
float xLabel = (float) (left + xPixelsPerUnit * (label - minX));
if (showLabels) {
paint.setColor(mRenderer.getXLabelsColor());
canvas.drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);
drawText(canvas, getLabel(label), xLabel, bottom + mRenderer.getLabelsTextSize() * 4 / 3,
paint, mRenderer.getXLabelsAngle());
}
if (showGridY) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(xLabel, bottom, xLabel, top, paint);
}
}
drawXTextLabels(xTextLabelLocations, canvas, paint, showLabels, left, top, bottom,
xPixelsPerUnit, minX, maxX);
}
/**
* The graphical representation of the labels on the X axis.
*
* @param xLabels the X labels values
* @param xTextLabelLocations the X text label locations
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param left the left value of the labels area
* @param top the top value of the labels area
* @param bottom the bottom value of the labels area
* @param xPixelsPerUnit the amount of pixels per one unit in the chart labels
* @param minX the minimum value on the X axis in the chart
* @param maxX the maximum value on the X axis in the chart
*/
protected void drawYLabels(Map<Integer, List<Double>> allYLabels, Canvas canvas, Paint paint,
int maxScaleNumber, int left, int right, int bottom, double[] yPixelsPerUnit, double[] minY) {
Orientation or = mRenderer.getOrientation();
boolean showGridX = mRenderer.isShowGridX();
boolean showLabels = mRenderer.isShowLabels();
for (int i = 0; i < maxScaleNumber; i++) {
paint.setTextAlign(mRenderer.getYLabelsAlign(i));
List<Double> yLabels = allYLabels.get(i);
int length = yLabels.size();
for (int j = 0; j < length; j++) {
double label = yLabels.get(j);
Align axisAlign = mRenderer.getYAxisAlign(i);
boolean textLabel = mRenderer.getYTextLabel(label, i) != null;
float yLabel = (float) (bottom - yPixelsPerUnit[i] * (label - minY[i]));
if (or == Orientation.HORIZONTAL) {
if (showLabels && !textLabel) {
paint.setColor(mRenderer.getYLabelsColor(i));
if (axisAlign == Align.LEFT) {
canvas.drawLine(left + getLabelLinePos(axisAlign), yLabel, left, yLabel, paint);
drawText(canvas, getLabel(label), left - 10, yLabel - 2, paint,
mRenderer.getYLabelsAngle());
} else {
canvas.drawLine(right, yLabel, right + getLabelLinePos(axisAlign), yLabel, paint);
drawText(canvas, getLabel(label), right, yLabel - 2, paint,
mRenderer.getYLabelsAngle());
}
}
if (showGridX) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(left, yLabel, right, yLabel, paint);
}
} else if (or == Orientation.VERTICAL) {
if (showLabels && !textLabel) {
paint.setColor(mRenderer.getYLabelsColor(i));
canvas.drawLine(right - getLabelLinePos(axisAlign), yLabel, right, yLabel, paint);
drawText(canvas, getLabel(label), right + 10, yLabel - 2, paint,
mRenderer.getYLabelsAngle());
}
if (showGridX) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(right, yLabel, left, yLabel, paint);
}
}
}
}
}
/**
* The graphical representation of the text labels on the X axis.
*
* @param xTextLabelLocations the X text label locations
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param left the left value of the labels area
* @param top the top value of the labels area
* @param bottom the bottom value of the labels area
* @param xPixelsPerUnit the amount of pixels per one unit in the chart labels
* @param minX the minimum value on the X axis in the chart
* @param maxX the maximum value on the X axis in the chart
*/
protected void drawXTextLabels(Double[] xTextLabelLocations, Canvas canvas, Paint paint,
boolean showLabels, int left, int top, int bottom, double xPixelsPerUnit, double minX,
double maxX) {
boolean showCustomTextGrid = mRenderer.isShowCustomTextGrid();
if (showLabels) {
paint.setColor(mRenderer.getXLabelsColor());
for (Double location : xTextLabelLocations) {
if (minX <= location && location <= maxX) {
float xLabel = (float) (left + xPixelsPerUnit * (location - minX));
paint.setColor(mRenderer.getXLabelsColor());
canvas
.drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);
drawText(canvas, mRenderer.getXTextLabel(location), xLabel,
bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());
if (showCustomTextGrid) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(xLabel, bottom, xLabel, top, paint);
}
}
}
}
}
// TODO: docs
public XYMultipleSeriesRenderer getRenderer() {
return mRenderer;
}
public XYMultipleSeriesDataset getDataset() {
return mDataset;
}
public double[] getCalcRange(int scale) {
return mCalcRange.get(scale);
}
public void setCalcRange(double[] range, int scale) {
mCalcRange.put(scale, range);
}
public double[] toRealPoint(float screenX, float screenY) {
return toRealPoint(screenX, screenY, 0);
}
public double[] toScreenPoint(double[] realPoint) {
return toScreenPoint(realPoint, 0);
}
private int getLabelLinePos(Align align) {
int pos = 4;
if (align == Align.LEFT) {
pos = -pos;
}
return pos;
}
/**
* Transforms a screen point to a real coordinates point.
*
* @param screenX the screen x axis value
* @param screenY the screen y axis value
* @return the real coordinates point
*/
public double[] toRealPoint(float screenX, float screenY, int scale) {
double realMinX = mRenderer.getXAxisMin(scale);
double realMaxX = mRenderer.getXAxisMax(scale);
double realMinY = mRenderer.getYAxisMin(scale);
double realMaxY = mRenderer.getYAxisMax(scale);
return new double[] {
(screenX - mScreenR.left) * (realMaxX - realMinX) / mScreenR.width() + realMinX,
(mScreenR.top + mScreenR.height() - screenY) * (realMaxY - realMinY) / mScreenR.height()
+ realMinY };
}
public double[] toScreenPoint(double[] realPoint, int scale) {
double realMinX = mRenderer.getXAxisMin(scale);
double realMaxX = mRenderer.getXAxisMax(scale);
double realMinY = mRenderer.getYAxisMin(scale);
double realMaxY = mRenderer.getYAxisMax(scale);
if (!mRenderer.isMinXSet(scale) || !mRenderer.isMaxXSet(scale) || !mRenderer.isMinXSet(scale)
|| !mRenderer.isMaxYSet(scale)) {
double[] calcRange = getCalcRange(scale);
realMinX = calcRange[0];
realMaxX = calcRange[1];
realMinY = calcRange[2];
realMaxY = calcRange[3];
}
return new double[] {
(realPoint[0] - realMinX) * mScreenR.width() / (realMaxX - realMinX) + mScreenR.left,
(realMaxY - realPoint[1]) * mScreenR.height() / (realMaxY - realMinY) + mScreenR.top };
}
public SeriesSelection getSeriesAndPointForScreenCoordinate(final Point screenPoint) {
if (clickableAreas != null) {
for (int seriesIndex = clickableAreas.size() - 1; seriesIndex >= 0; seriesIndex--) {
// series 0 is drawn first. Then series 1 is drawn on top, and series 2
// on top of that.
// we want to know what the user clicked on, so traverse them in the
// order they appear on the screen.
int pointIndex = 0;
if (clickableAreas.get(seriesIndex) != null) {
RectF rectangle;
for (ClickableArea area : clickableAreas.get(seriesIndex)) {
rectangle = area.getRect();
if (rectangle != null && rectangle.contains(screenPoint.getX(), screenPoint.getY())) {
return new SeriesSelection(seriesIndex, pointIndex, area.getX(), area.getY());
}
pointIndex++;
}
}
}
}
return super.getSeriesAndPointForScreenCoordinate(screenPoint);
}
/**
* The graphical representation of a series.
*
* @param canvas the canvas to paint to
* @param paint the paint to be used for drawing
* @param points the array of points to be used for drawing the series
* @param seriesRenderer the series renderer
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series currently being drawn
* @param startIndex the start index of the rendering points
*/
public abstract void drawSeries(Canvas canvas, Paint paint, float[] points,
SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex, int range);
/**
* Returns the clickable areas for all passed points
*
* @param points the array of points
* @param values the array of values of each point
* @param yAxisValue the minimum value of the y axis
* @param seriesIndex the index of the series to which the points belong
* @return an array of rectangles with the clickable area
* @param startIndex the start index of the rendering points
*/
protected abstract ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
float yAxisValue, int seriesIndex, int startIndex, int range);
/**
* Returns if the chart should display the null values.
*
* @return if null values should be rendered
*/
protected boolean isRenderNullValues() {
return false;
}
/**
* Returns if the chart should display the points as a certain shape.
*
* @param renderer the series renderer
*/
public boolean isRenderPoints(SimpleSeriesRenderer renderer) {
return false;
}
/**
* Returns the default axis minimum.
*
* @return the default axis minimum
*/
public double getDefaultMinimum() {
return MathHelper.NULL_VALUE;
}
/**
* Returns the scatter chart to be used for drawing the data points.
*
* @return the data points scatter chart
*/
public ScatterChart getPointsChart() {
return null;
}
/**
* Returns the chart type identifier.
*
* @return the chart type
*/
public abstract String getChartType();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,143 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* A series for the category charts like the pie ones.
*/
public class CategorySeries implements Serializable {
/** The series title. */
private String mTitle;
/** The series categories. */
private List<String> mCategories = new ArrayList<String>();
/** The series values. */
private List<Double> mValues = new ArrayList<Double>();
/**
* Builds a new category series.
*
* @param title the series title
*/
public CategorySeries(String title) {
mTitle = title;
}
/**
* Returns the series title.
*
* @return the series title
*/
public String getTitle() {
return mTitle;
}
/**
* Adds a new value to the series
*
* @param value the new value
*/
public synchronized void add(double value) {
add(mCategories.size() + "", value);
}
/**
* Adds a new value to the series.
*
* @param category the category
* @param value the new value
*/
public synchronized void add(String category, double value) {
mCategories.add(category);
mValues.add(value);
}
/**
* Replaces the value at the specific index in the series.
*
* @param index the index in the series
* @param category the category
* @param value the new value
*/
public synchronized void set(int index, String category, double value) {
mCategories.set(index, category);
mValues.set(index, value);
}
/**
* Removes an existing value from the series.
*
* @param index the index in the series of the value to remove
*/
public synchronized void remove(int index) {
mCategories.remove(index);
mValues.remove(index);
}
/**
* Removes all the existing values from the series.
*/
public synchronized void clear() {
mCategories.clear();
mValues.clear();
}
/**
* Returns the value at the specified index.
*
* @param index the index
* @return the value at the index
*/
public synchronized double getValue(int index) {
return mValues.get(index);
}
/**
* Returns the category name at the specified index.
*
* @param index the index
* @return the category name at the index
*/
public synchronized String getCategory(int index) {
return mCategories.get(index);
}
/**
* Returns the series item count.
*
* @return the series item count
*/
public synchronized int getItemCount() {
return mCategories.size();
}
/**
* Transforms the category series to an XY series.
*
* @return the XY series
*/
public XYSeries toXYSeries() {
XYSeries xySeries = new XYSeries(mTitle);
int k = 0;
for (double value : mValues) {
xySeries.add(++k, value);
}
return xySeries;
}
}

View File

@ -1,144 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* A series for the multiple category charts like the doughnut.
*/
public class MultipleCategorySeries implements Serializable {
/** The series title. */
private String mTitle;
/** The series local keys. */
private List<String> mCategories = new ArrayList<String>();
/** The series name. */
private List<String[]> mTitles = new ArrayList<String[]>();
/** The series values. */
private List<double[]> mValues = new ArrayList<double[]>();
/**
* Builds a new category series.
*
* @param title the series title
*/
public MultipleCategorySeries(String title) {
mTitle = title;
}
/**
* Adds a new value to the series
*
* @param titles the titles to be used as labels
* @param values the new value
*/
public void add(String[] titles, double[] values) {
add(mCategories.size() + "", titles, values);
}
/**
* Adds a new value to the series.
*
* @param category the category name
* @param titles the titles to be used as labels
* @param values the new value
*/
public void add(String category, String[] titles, double[] values) {
mCategories.add(category);
mTitles.add(titles);
mValues.add(values);
}
/**
* Removes an existing value from the series.
*
* @param index the index in the series of the value to remove
*/
public void remove(int index) {
mCategories.remove(index);
mTitles.remove(index);
mValues.remove(index);
}
/**
* Removes all the existing values from the series.
*/
public void clear() {
mCategories.clear();
mTitles.clear();
mValues.clear();
}
/**
* Returns the values at the specified index.
*
* @param index the index
* @return the value at the index
*/
public double[] getValues(int index) {
return mValues.get(index);
}
/**
* Returns the category name at the specified index.
*
* @param index the index
* @return the category name at the index
*/
public String getCategory(int index) {
return mCategories.get(index);
}
/**
* Returns the categories count.
*
* @return the categories count
*/
public int getCategoriesCount() {
return mCategories.size();
}
/**
* Returns the series item count.
*
* @param index the index
* @return the series item count
*/
public int getItemCount(int index) {
return mValues.get(index).length;
}
/**
* Returns the series titles.
*
* @param index the index
* @return the series titles
*/
public String[] getTitles(int index) {
return mTitles.get(index);
}
/**
* Transforms the category series to an XY series.
*
* @return the XY series
*/
public XYSeries toXYSeries() {
return new XYSeries(mTitle);
}
}

View File

@ -1,52 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.io.Serializable;
/**
* A class to encapsulate the definition of a point.
*/
public final class Point implements Serializable {
/** The X axis coordinate value. */
private float mX;
/** The Y axis coordinate value. */
private float mY;
public Point() {
}
public Point(float x, float y) {
mX = x;
mY = y;
}
public float getX() {
return mX;
}
public float getY() {
return mY;
}
public void setX(float x) {
mX = x;
}
public void setY(float y) {
mY = y;
}
}

View File

@ -1,111 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.util.ArrayList;
import java.util.List;
/**
* A series for the range category charts like the range bar.
*/
public class RangeCategorySeries extends CategorySeries {
/** The series values. */
private List<Double> mMaxValues = new ArrayList<Double>();
/**
* Builds a new category series.
*
* @param title the series title
*/
public RangeCategorySeries(String title) {
super(title);
}
/**
* Adds new values to the series
*
* @param minValue the new minimum value
* @param maxValue the new maximum value
*/
public synchronized void add(double minValue, double maxValue) {
super.add(minValue);
mMaxValues.add(maxValue);
}
/**
* Adds new values to the series.
*
* @param category the category
* @param minValue the new minimum value
* @param maxValue the new maximum value
*/
public synchronized void add(String category, double minValue, double maxValue) {
super.add(category, minValue);
mMaxValues.add(maxValue);
}
/**
* Removes existing values from the series.
*
* @param index the index in the series of the values to remove
*/
public synchronized void remove(int index) {
super.remove(index);
mMaxValues.remove(index);
}
/**
* Removes all the existing values from the series.
*/
public synchronized void clear() {
super.clear();
mMaxValues.clear();
}
/**
* Returns the minimum value at the specified index.
*
* @param index the index
* @return the minimum value at the index
*/
public double getMinimumValue(int index) {
return getValue(index);
}
/**
* Returns the maximum value at the specified index.
*
* @param index the index
* @return the maximum value at the index
*/
public double getMaximumValue(int index) {
return mMaxValues.get(index);
}
/**
* Transforms the range category series to an XY series.
*
* @return the XY series
*/
public XYSeries toXYSeries() {
XYSeries xySeries = new XYSeries(getTitle());
int length = getItemCount();
for (int k = 0; k < length; k++) {
xySeries.add(k + 1, getMinimumValue(k));
// the new fast XYSeries implementation doesn't allow 2 values at the same X,
// so I had to do a hack until I find a better solution
xySeries.add(k + 1.000001, getMaximumValue(k));
}
return xySeries;
}
}

View File

@ -1,49 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
public class SeriesSelection {
private int mSeriesIndex;
private int mPointIndex;
private double mXValue;
private double mValue;
public SeriesSelection(int seriesIndex, int pointIndex, double xValue, double value) {
mSeriesIndex = seriesIndex;
mPointIndex = pointIndex;
mXValue = xValue;
mValue = value;
}
public int getSeriesIndex() {
return mSeriesIndex;
}
public int getPointIndex() {
return mPointIndex;
}
public double getXValue() {
return mXValue;
}
public double getValue() {
return mValue;
}
}

View File

@ -1,43 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.util.Date;
/**
* A series for the date / time charts.
*/
public class TimeSeries extends XYSeries {
/**
* Builds a new date / time series.
*
* @param title the series title
*/
public TimeSeries(String title) {
super(title);
}
/**
* Adds a new value to the series.
*
* @param x the date / time value for the X axis
* @param y the value for the Y axis
*/
public synchronized void add(Date x, double y) {
super.add(x.getTime(), y);
}
}

View File

@ -1,94 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* A series that includes 0 to many XYSeries.
*/
public class XYMultipleSeriesDataset implements Serializable {
/** The included series. */
private List<XYSeries> mSeries = new ArrayList<XYSeries>();
/**
* Adds a new XY series to the list.
*
* @param series the XY series to ass
*/
public synchronized void addSeries(XYSeries series) {
mSeries.add(series);
}
/**
* Adds a new XY series to the list.
*
* @param index the index in the series list
* @param series the XY series to ass
*/
public synchronized void addSeries(int index, XYSeries series) {
mSeries.add(index, series);
}
/**
* Removes the XY series from the list.
*
* @param index the index in the series list of the series to remove
*/
public synchronized void removeSeries(int index) {
mSeries.remove(index);
}
/**
* Removes the XY series from the list.
*
* @param series the XY series to be removed
*/
public synchronized void removeSeries(XYSeries series) {
mSeries.remove(series);
}
/**
* Returns the XY series at the specified index.
*
* @param index the index
* @return the XY series at the index
*/
public synchronized XYSeries getSeriesAt(int index) {
return mSeries.get(index);
}
/**
* Returns the XY series count.
*
* @return the XY series count
*/
public synchronized int getSeriesCount() {
return mSeries.size();
}
/**
* Returns an array of the XY series.
*
* @return the XY series array
*/
public synchronized XYSeries[] getSeries() {
return mSeries.toArray(new XYSeries[mSeries.size()]);
}
}

View File

@ -1,254 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.io.Serializable;
import java.util.Collection;
import java.util.SortedMap;
import org.achartengine.util.IndexXYMap;
import org.achartengine.util.MathHelper;
import org.achartengine.util.XYEntry;
/**
* An XY series encapsulates values for XY charts like line, time, area,
* scatter... charts.
*/
public class XYSeries implements Serializable {
/** The series title. */
private String mTitle;
/** A map to contain values for X and Y axes and index for each bundle */
private final IndexXYMap<Double, Double> mXY = new IndexXYMap<Double, Double>();
/** The minimum value for the X axis. */
private double mMinX = MathHelper.NULL_VALUE;
/** The maximum value for the X axis. */
private double mMaxX = -MathHelper.NULL_VALUE;
/** The minimum value for the Y axis. */
private double mMinY = MathHelper.NULL_VALUE;
/** The maximum value for the Y axis. */
private double mMaxY = -MathHelper.NULL_VALUE;
/** The scale number for this series. */
private final int mScaleNumber;
/**
* Builds a new XY series.
*
* @param title the series title.
*/
public XYSeries(String title) {
this(title, 0);
}
/**
* Builds a new XY series.
*
* @param title the series title.
* @param scaleNumber the series scale number
*/
public XYSeries(String title, int scaleNumber) {
mTitle = title;
mScaleNumber = scaleNumber;
initRange();
}
public int getScaleNumber() {
return mScaleNumber;
}
/**
* Initializes the range for both axes.
*/
private void initRange() {
mMinX = MathHelper.NULL_VALUE;
mMaxX = -MathHelper.NULL_VALUE;
mMinY = MathHelper.NULL_VALUE;
mMaxY = -MathHelper.NULL_VALUE;
int length = getItemCount();
for (int k = 0; k < length; k++) {
double x = getX(k);
double y = getY(k);
updateRange(x, y);
}
}
/**
* Updates the range on both axes.
*
* @param x the new x value
* @param y the new y value
*/
private void updateRange(double x, double y) {
mMinX = Math.min(mMinX, x);
mMaxX = Math.max(mMaxX, x);
mMinY = Math.min(mMinY, y);
mMaxY = Math.max(mMaxY, y);
}
/**
* Returns the series title.
*
* @return the series title
*/
public String getTitle() {
return mTitle;
}
/**
* Sets the series title.
*
* @param title the series title
*/
public void setTitle(String title) {
mTitle = title;
}
/**
* Adds a new value to the series.
*
* @param x the value for the X axis
* @param y the value for the Y axis
*/
public synchronized void add(double x, double y) {
mXY.put(x, y);
updateRange(x, y);
}
/**
* Removes an existing value from the series.
*
* @param index the index in the series of the value to remove
*/
public synchronized void remove(int index) {
XYEntry<Double, Double> removedEntry = mXY.removeByIndex(index);
double removedX = removedEntry.getKey();
double removedY = removedEntry.getValue();
if (removedX == mMinX || removedX == mMaxX || removedY == mMinY || removedY == mMaxY) {
initRange();
}
}
/**
* Removes all the existing values from the series.
*/
public synchronized void clear() {
mXY.clear();
initRange();
}
/**
* Returns the X axis value at the specified index.
*
* @param index the index
* @return the X value
*/
public synchronized double getX(int index) {
return mXY.getXByIndex(index);
}
/**
* Returns the Y axis value at the specified index.
*
* @param index the index
* @return the Y value
*/
public synchronized double getY(int index) {
return mXY.getYByIndex(index);
}
/**
* Returns submap of x and y values according to the given start and end
*
* @param start start x value
* @param stop stop x value
* @return
*/
public synchronized SortedMap<Double, Double> getRange(double start, double stop,
int beforeAfterPoints) {
// we need to add one point before the start and one point after the end (if
// there are any)
// to ensure that line doesn't end before the end of the screen
// this would be simply: start = mXY.lowerKey(start) but NavigableMap is
// available since API 9
SortedMap<Double, Double> headMap = mXY.headMap(start);
if (headMap.size() != 0) {
start = headMap.lastKey();
}
// this would be simply: end = mXY.higherKey(end) but NavigableMap is
// available since API 9
// so we have to do this hack in order to support older versions
SortedMap<Double, Double> tailMap = mXY.tailMap(stop);
if (tailMap.size() != 0) {
Collection<Double> tailCollection = tailMap.keySet();
if (tailMap.size() > 1) {
stop = (Double) tailCollection.toArray()[1];
} else {
stop += tailMap.firstKey();
}
}
return mXY.subMap(start, stop);
}
public int getIndexForKey(double key) {
return mXY.getIndexForKey(key);
}
/**
* Returns the series item count.
*
* @return the series item count
*/
public synchronized int getItemCount() {
return mXY.size();
}
/**
* Returns the minimum value on the X axis.
*
* @return the X axis minimum value
*/
public double getMinX() {
return mMinX;
}
/**
* Returns the minimum value on the Y axis.
*
* @return the Y axis minimum value
*/
public double getMinY() {
return mMinY;
}
/**
* Returns the maximum value on the X axis.
*
* @return the X axis maximum value
*/
public double getMaxX() {
return mMaxX;
}
/**
* Returns the maximum value on the Y axis.
*
* @return the Y axis maximum value
*/
public double getMaxY() {
return mMaxY;
}
}

View File

@ -1,139 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.model;
import java.util.ArrayList;
import java.util.List;
import org.achartengine.util.MathHelper;
/**
* An extension of the XY series which adds a third dimension. It is used for XY
* charts like bubble.
*/
public class XYValueSeries extends XYSeries {
/** A list to contain the series values. */
private List<Double> mValue = new ArrayList<Double>();
/** The minimum value. */
private double mMinValue = MathHelper.NULL_VALUE;
/** The maximum value. */
private double mMaxValue = -MathHelper.NULL_VALUE;
/**
* Builds a new XY value series.
*
* @param title the series title.
*/
public XYValueSeries(String title) {
super(title);
}
/**
* Adds a new value to the series.
*
* @param x the value for the X axis
* @param y the value for the Y axis
* @param value the value
*/
public synchronized void add(double x, double y, double value) {
super.add(x, y);
mValue.add(value);
updateRange(value);
}
/**
* Initializes the values range.
*/
private void initRange() {
mMinValue = MathHelper.NULL_VALUE;
mMaxValue = MathHelper.NULL_VALUE;
int length = getItemCount();
for (int k = 0; k < length; k++) {
updateRange(getValue(k));
}
}
/**
* Updates the values range.
*
* @param value the new value
*/
private void updateRange(double value) {
mMinValue = Math.min(mMinValue, value);
mMaxValue = Math.max(mMaxValue, value);
}
/**
* Adds a new value to the series.
*
* @param x the value for the X axis
* @param y the value for the Y axis
*/
public synchronized void add(double x, double y) {
add(x, y, 0d);
}
/**
* Removes an existing value from the series.
*
* @param index the index in the series of the value to remove
*/
public synchronized void remove(int index) {
super.remove(index);
double removedValue = mValue.remove(index);
if (removedValue == mMinValue || removedValue == mMaxValue) {
initRange();
}
}
/**
* Removes all the values from the series.
*/
public synchronized void clear() {
super.clear();
mValue.clear();
initRange();
}
/**
* Returns the value at the specified index.
*
* @param index the index
* @return the value
*/
public synchronized double getValue(int index) {
return mValue.get(index);
}
/**
* Returns the minimum value.
*
* @return the minimum value
*/
public double getMinValue() {
return mMinValue;
}
/**
* Returns the maximum value.
*
* @return the maximum value
*/
public double getMaxValue() {
return mMaxValue;
}
}

View File

@ -1,107 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.renderer;
import java.io.Serializable;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
/**
* A descriptor for the stroke style.
*/
public class BasicStroke implements Serializable {
/** The solid line style. */
public static final BasicStroke SOLID = new BasicStroke(Cap.BUTT, Join.MITER, 4, null, 0);
/** The dashed line style. */
public static final BasicStroke DASHED = new BasicStroke(Cap.ROUND, Join.BEVEL, 10, new float[] {
10, 10 }, 1);
/** The dot line style. */
public static final BasicStroke DOTTED = new BasicStroke(Cap.ROUND, Join.BEVEL, 5, new float[] {
2, 10 }, 1);
/** The stroke cap. */
private Cap mCap;
/** The stroke join. */
private Join mJoin;
/** The stroke miter. */
private float mMiter;
/** The path effect intervals. */
private float[] mIntervals;
/** The path effect phase. */
private float mPhase;
/**
* Build a new basic stroke style.
*
* @param cap the stroke cap
* @param join the stroke join
* @param miter the stroke miter
* @param intervals the path effect intervals
* @param phase the path effect phase
*/
public BasicStroke(Cap cap, Join join, float miter, float[] intervals, float phase) {
mCap = cap;
mJoin = join;
mMiter = miter;
mIntervals = intervals;
}
/**
* Returns the stroke cap.
*
* @return the stroke cap
*/
public Cap getCap() {
return mCap;
}
/**
* Returns the stroke join.
*
* @return the stroke join
*/
public Join getJoin() {
return mJoin;
}
/**
* Returns the stroke miter.
*
* @return the stroke miter
*/
public float getMiter() {
return mMiter;
}
/**
* Returns the path effect intervals.
*
* @return the path effect intervals
*/
public float[] getIntervals() {
return mIntervals;
}
/**
* Returns the path effect phase.
*
* @return the path effect phase
*/
public float getPhase() {
return mPhase;
}
}

View File

@ -1,724 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.renderer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Color;
import android.graphics.Typeface;
/**
* An abstract renderer to be extended by the multiple series classes.
*/
public class DefaultRenderer implements Serializable {
/** The chart title. */
private String mChartTitle = "";
/** The chart title text size. */
private float mChartTitleTextSize = 15;
/** A no color constant. */
public static final int NO_COLOR = 0;
/** The default background color. */
public static final int BACKGROUND_COLOR = Color.BLACK;
/** The default color for text. */
public static final int TEXT_COLOR = Color.LTGRAY;
/** A text font for regular text, like the chart labels. */
private static final Typeface REGULAR_TEXT_FONT = Typeface
.create(Typeface.SERIF, Typeface.NORMAL);
/** The typeface name for the texts. */
private String mTextTypefaceName = REGULAR_TEXT_FONT.toString();
/** The typeface style for the texts. */
private int mTextTypefaceStyle = Typeface.NORMAL;
/** The chart background color. */
private int mBackgroundColor;
/** If the background color is applied. */
private boolean mApplyBackgroundColor;
/** If the axes are visible. */
private boolean mShowAxes = true;
/** The axes color. */
private int mAxesColor = TEXT_COLOR;
/** If the labels are visible. */
private boolean mShowLabels = true;
/** The labels color. */
private int mLabelsColor = TEXT_COLOR;
/** The labels text size. */
private float mLabelsTextSize = 10;
/** If the legend is visible. */
private boolean mShowLegend = true;
/** The legend text size. */
private float mLegendTextSize = 12;
/** If the legend should size to fit. */
private boolean mFitLegend = false;
/** If the X axis grid should be displayed. */
private boolean mShowGridX = false;
/** If the Y axis grid should be displayed. */
private boolean mShowGridY = false;
/** If the custom text grid should be displayed. */
private boolean mShowCustomTextGrid = false;
/** The simple renderers that are included in this multiple series renderer. */
private List<SimpleSeriesRenderer> mRenderers = new ArrayList<SimpleSeriesRenderer>();
/** The antialiasing flag. */
private boolean mAntialiasing = true;
/** The legend height. */
private int mLegendHeight = 0;
/** The margins size. */
private int[] mMargins = new int[] { 20, 30, 10, 20 };
/** A value to be used for scaling the chart. */
private float mScale = 1;
/** A flag for enabling the pan. */
private boolean mPanEnabled = true;
/** A flag for enabling the zoom. */
private boolean mZoomEnabled = true;
/** A flag for enabling the visibility of the zoom buttons. */
private boolean mZoomButtonsVisible = false;
/** The zoom rate. */
private float mZoomRate = 1.5f;
/** A flag for enabling the external zoom. */
private boolean mExternalZoomEnabled = false;
/** The original chart scale. */
private float mOriginalScale = mScale;
/** A flag for enabling the click on elements. */
private boolean mClickEnabled = false;
/** The selectable radius around a clickable point. */
private int selectableBuffer = 15;
/**
* A flag to be set if the chart is inside a scroll and doesn't need to shrink
* when not enough space.
*/
private boolean mInScroll;
/** The start angle for circular charts such as pie, doughnut, etc. */
private float mStartAngle = 0;
/**
* Returns the chart title.
*
* @return the chart title
*/
public String getChartTitle() {
return mChartTitle;
}
/**
* Sets the chart title.
*
* @param title the chart title
*/
public void setChartTitle(String title) {
mChartTitle = title;
}
/**
* Returns the chart title text size.
*
* @return the chart title text size
*/
public float getChartTitleTextSize() {
return mChartTitleTextSize;
}
/**
* Sets the chart title text size.
*
* @param textSize the chart title text size
*/
public void setChartTitleTextSize(float textSize) {
mChartTitleTextSize = textSize;
}
/**
* Adds a simple renderer to the multiple renderer.
*
* @param renderer the renderer to be added
*/
public void addSeriesRenderer(SimpleSeriesRenderer renderer) {
mRenderers.add(renderer);
}
/**
* Adds a simple renderer to the multiple renderer.
*
* @param index the index in the renderers list
* @param renderer the renderer to be added
*/
public void addSeriesRenderer(int index, SimpleSeriesRenderer renderer) {
mRenderers.add(index, renderer);
}
/**
* Removes a simple renderer from the multiple renderer.
*
* @param renderer the renderer to be removed
*/
public void removeSeriesRenderer(SimpleSeriesRenderer renderer) {
mRenderers.remove(renderer);
}
/**
* Returns the simple renderer from the multiple renderer list.
*
* @param index the index in the simple renderers list
* @return the simple renderer at the specified index
*/
public SimpleSeriesRenderer getSeriesRendererAt(int index) {
return mRenderers.get(index);
}
/**
* Returns the simple renderers count in the multiple renderer list.
*
* @return the simple renderers count
*/
public int getSeriesRendererCount() {
return mRenderers.size();
}
/**
* Returns an array of the simple renderers in the multiple renderer list.
*
* @return the simple renderers array
*/
public SimpleSeriesRenderer[] getSeriesRenderers() {
return mRenderers.toArray(new SimpleSeriesRenderer[mRenderers.size()]);
}
/**
* Returns the background color.
*
* @return the background color
*/
public int getBackgroundColor() {
return mBackgroundColor;
}
/**
* Sets the background color.
*
* @param color the background color
*/
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
/**
* Returns if the background color should be applied.
*
* @return the apply flag for the background color.
*/
public boolean isApplyBackgroundColor() {
return mApplyBackgroundColor;
}
/**
* Sets if the background color should be applied.
*
* @param apply the apply flag for the background color
*/
public void setApplyBackgroundColor(boolean apply) {
mApplyBackgroundColor = apply;
}
/**
* Returns the axes color.
*
* @return the axes color
*/
public int getAxesColor() {
return mAxesColor;
}
/**
* Sets the axes color.
*
* @param color the axes color
*/
public void setAxesColor(int color) {
mAxesColor = color;
}
/**
* Returns the labels color.
*
* @return the labels color
*/
public int getLabelsColor() {
return mLabelsColor;
}
/**
* Sets the labels color.
*
* @param color the labels color
*/
public void setLabelsColor(int color) {
mLabelsColor = color;
}
/**
* Returns the labels text size.
*
* @return the labels text size
*/
public float getLabelsTextSize() {
return mLabelsTextSize;
}
/**
* Sets the labels text size.
*
* @param textSize the labels text size
*/
public void setLabelsTextSize(float textSize) {
mLabelsTextSize = textSize;
}
/**
* Returns if the axes should be visible.
*
* @return the visibility flag for the axes
*/
public boolean isShowAxes() {
return mShowAxes;
}
/**
* Sets if the axes should be visible.
*
* @param showAxes the visibility flag for the axes
*/
public void setShowAxes(boolean showAxes) {
mShowAxes = showAxes;
}
/**
* Returns if the labels should be visible.
*
* @return the visibility flag for the labels
*/
public boolean isShowLabels() {
return mShowLabels;
}
/**
* Sets if the labels should be visible.
*
* @param showLabels the visibility flag for the labels
*/
public void setShowLabels(boolean showLabels) {
mShowLabels = showLabels;
}
/**
* Returns if the X axis grid should be visible.
*
* @return the visibility flag for the X axis grid
*/
public boolean isShowGridX() {
return mShowGridX;
}
/**
* Returns if the Y axis grid should be visible.
*
* @return the visibility flag for the Y axis grid
*/
public boolean isShowGridY() {
return mShowGridY;
}
/**
* Sets if the X axis grid should be visible.
*
* @param showGrid the visibility flag for the X axis grid
*/
public void setShowGridX(boolean showGrid) {
mShowGridX = showGrid;
}
/**
* Sets if the Y axis grid should be visible.
*
* @param showGrid the visibility flag for the Y axis grid
*/
public void setShowGridY(boolean showGrid) {
mShowGridY = showGrid;
}
/**
* Sets if the grid should be visible.
*
* @param showGrid the visibility flag for the grid
*/
public void setShowGrid(boolean showGrid) {
setShowGridX(showGrid);
setShowGridY(showGrid);
}
/**
* Returns if the grid should be visible for custom X or Y labels.
*
* @return the visibility flag for the custom text grid
*/
public boolean isShowCustomTextGrid() {
return mShowCustomTextGrid;
}
/**
* Sets if the grid for custom X or Y labels should be visible.
*
* @param showGrid the visibility flag for the custom text grid
*/
public void setShowCustomTextGrid(boolean showGrid) {
mShowCustomTextGrid = showGrid;
}
/**
* Returns if the legend should be visible.
*
* @return the visibility flag for the legend
*/
public boolean isShowLegend() {
return mShowLegend;
}
/**
* Sets if the legend should be visible.
*
* @param showLegend the visibility flag for the legend
*/
public void setShowLegend(boolean showLegend) {
mShowLegend = showLegend;
}
/**
* Returns if the legend should size to fit.
*
* @return the fit behavior
*/
public boolean isFitLegend() {
return mFitLegend;
}
/**
* Sets if the legend should size to fit.
*
* @param fit the fit behavior
*/
public void setFitLegend(boolean fit) {
mFitLegend = fit;
}
/**
* Returns the text typeface name.
*
* @return the text typeface name
*/
public String getTextTypefaceName() {
return mTextTypefaceName;
}
/**
* Returns the text typeface style.
*
* @return the text typeface style
*/
public int getTextTypefaceStyle() {
return mTextTypefaceStyle;
}
/**
* Returns the legend text size.
*
* @return the legend text size
*/
public float getLegendTextSize() {
return mLegendTextSize;
}
/**
* Sets the legend text size.
*
* @param textSize the legend text size
*/
public void setLegendTextSize(float textSize) {
mLegendTextSize = textSize;
}
/**
* Sets the text typeface name and style.
*
* @param typefaceName the text typeface name
* @param style the text typeface style
*/
public void setTextTypeface(String typefaceName, int style) {
mTextTypefaceName = typefaceName;
mTextTypefaceStyle = style;
}
/**
* Returns the antialiasing flag value.
*
* @return the antialiasing value
*/
public boolean isAntialiasing() {
return mAntialiasing;
}
/**
* Sets the antialiasing value.
*
* @param antialiasing the antialiasing
*/
public void setAntialiasing(boolean antialiasing) {
mAntialiasing = antialiasing;
}
/**
* Returns the value to be used for scaling the chart.
*
* @return the scale value
*/
public float getScale() {
return mScale;
}
/**
* Returns the original value to be used for scaling the chart.
*
* @return the original scale value
*/
public float getOriginalScale() {
return mOriginalScale;
}
/**
* Sets the value to be used for scaling the chart. It works on some charts
* like pie, doughnut, dial.
*
* @param scale the scale value
*/
public void setScale(float scale) {
mScale = scale;
}
/**
* Returns the enabled state of the zoom.
*
* @return if zoom is enabled
*/
public boolean isZoomEnabled() {
return mZoomEnabled;
}
/**
* Sets the enabled state of the zoom.
*
* @param enabled zoom enabled
*/
public void setZoomEnabled(boolean enabled) {
mZoomEnabled = enabled;
}
/**
* Returns the visible state of the zoom buttons.
*
* @return if zoom buttons are visible
*/
public boolean isZoomButtonsVisible() {
return mZoomButtonsVisible;
}
/**
* Sets the visible state of the zoom buttons.
*
* @param visible if the zoom buttons are visible
*/
public void setZoomButtonsVisible(boolean visible) {
mZoomButtonsVisible = visible;
}
/**
* Returns the enabled state of the external (application implemented) zoom.
*
* @return if external zoom is enabled
*/
public boolean isExternalZoomEnabled() {
return mExternalZoomEnabled;
}
/**
* Sets the enabled state of the external (application implemented) zoom.
*
* @param enabled external zoom enabled
*/
public void setExternalZoomEnabled(boolean enabled) {
mExternalZoomEnabled = enabled;
}
/**
* Returns the zoom rate.
*
* @return the zoom rate
*/
public float getZoomRate() {
return mZoomRate;
}
/**
* Returns the enabled state of the pan.
*
* @return if pan is enabled
*/
public boolean isPanEnabled() {
return mPanEnabled;
}
/**
* Sets the enabled state of the pan.
*
* @param enabled pan enabled
*/
public void setPanEnabled(boolean enabled) {
mPanEnabled = enabled;
}
/**
* Sets the zoom rate.
*
* @param rate the zoom rate
*/
public void setZoomRate(float rate) {
mZoomRate = rate;
}
/**
* Returns the enabled state of the click.
*
* @return if click is enabled
*/
public boolean isClickEnabled() {
return mClickEnabled;
}
/**
* Sets the enabled state of the click.
*
* @param enabled click enabled
*/
public void setClickEnabled(boolean enabled) {
mClickEnabled = enabled;
}
/**
* Returns the selectable radius value around clickable points.
*
* @return the selectable radius
*/
public int getSelectableBuffer() {
return selectableBuffer;
}
/**
* Sets the selectable radius value around clickable points.
*
* @param buffer the selectable radius
*/
public void setSelectableBuffer(int buffer) {
selectableBuffer = buffer;
}
/**
* Returns the legend height.
*
* @return the legend height
*/
public int getLegendHeight() {
return mLegendHeight;
}
/**
* Sets the legend height, in pixels.
*
* @param height the legend height
*/
public void setLegendHeight(int height) {
mLegendHeight = height;
}
/**
* Returns the margin sizes. An array containing the margins in this order:
* top, left, bottom, right
*
* @return the margin sizes
*/
public int[] getMargins() {
return mMargins;
}
/**
* Sets the margins, in pixels.
*
* @param margins an array containing the margin size values, in this order:
* top, left, bottom, right
*/
public void setMargins(int[] margins) {
mMargins = margins;
}
/**
* Returns if the chart is inside a scroll view and doesn't need to shrink.
*
* @return if it is inside a scroll view
*/
public boolean isInScroll() {
return mInScroll;
}
/**
* To be set if the chart is inside a scroll view and doesn't need to shrink
* when not enough space.
*
* @param inScroll if it is inside a scroll view
*/
public void setInScroll(boolean inScroll) {
mInScroll = inScroll;
}
/**
* Returns the start angle for circular charts such as pie, doughnut. An angle
* of 0 degrees correspond to the geometric angle of 0 degrees (3 o'clock on a
* watch.)
*
* @return the start angle
*/
public float getStartAngle() {
return mStartAngle;
}
/**
* Sets the start angle for circular charts such as pie, doughnut, etc. An
* angle of 0 degrees correspond to the geometric angle of 0 degrees (3
* o'clock on a watch.)
*
* @param startAngle the start angle
*/
public void setStartAngle(float startAngle) {
mStartAngle = startAngle;
}
}

View File

@ -1,196 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.renderer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.achartengine.util.MathHelper;
/**
* Dial chart renderer.
*/
public class DialRenderer extends DefaultRenderer {
/** The start angle in the dial range. */
private double mAngleMin = 330;
/** The end angle in the dial range. */
private double mAngleMax = 30;
/** The start value in dial range. */
private double mMinValue = MathHelper.NULL_VALUE;
/** The end value in dial range. */
private double mMaxValue = -MathHelper.NULL_VALUE;
/** The spacing for the minor ticks. */
private double mMinorTickSpacing = MathHelper.NULL_VALUE;
/** The spacing for the major ticks. */
private double mMajorTickSpacing = MathHelper.NULL_VALUE;
/** An array of the renderers types (default is NEEDLE). */
private List<Type> mVisualTypes = new ArrayList<Type>();
public enum Type {
NEEDLE, ARROW;
}
/**
* Returns the start angle value of the dial.
*
* @return the angle start value
*/
public double getAngleMin() {
return mAngleMin;
}
/**
* Sets the start angle value of the dial.
*
* @param min the dial angle start value
*/
public void setAngleMin(double min) {
mAngleMin = min;
}
/**
* Returns the end angle value of the dial.
*
* @return the angle end value
*/
public double getAngleMax() {
return mAngleMax;
}
/**
* Sets the end angle value of the dial.
*
* @param max the dial angle end value
*/
public void setAngleMax(double max) {
mAngleMax = max;
}
/**
* Returns the start value to be rendered on the dial.
*
* @return the start value on dial
*/
public double getMinValue() {
return mMinValue;
}
/**
* Sets the start value to be rendered on the dial.
*
* @param min the start value on the dial
*/
public void setMinValue(double min) {
mMinValue = min;
}
/**
* Returns if the minimum dial value was set.
*
* @return the minimum dial value was set or not
*/
public boolean isMinValueSet() {
return mMinValue != MathHelper.NULL_VALUE;
}
/**
* Returns the end value to be rendered on the dial.
*
* @return the end value on the dial
*/
public double getMaxValue() {
return mMaxValue;
}
/**
* Sets the end value to be rendered on the dial.
*
* @param max the end value on the dial
*/
public void setMaxValue(double max) {
mMaxValue = max;
}
/**
* Returns if the maximum dial value was set.
*
* @return the maximum dial was set or not
*/
public boolean isMaxValueSet() {
return mMaxValue != -MathHelper.NULL_VALUE;
}
/**
* Returns the minor ticks spacing.
*
* @return the minor ticks spacing
*/
public double getMinorTicksSpacing() {
return mMinorTickSpacing;
}
/**
* Sets the minor ticks spacing.
*
* @param spacing the minor ticks spacing
*/
public void setMinorTicksSpacing(double spacing) {
mMinorTickSpacing = spacing;
}
/**
* Returns the major ticks spacing.
*
* @return the major ticks spacing
*/
public double getMajorTicksSpacing() {
return mMajorTickSpacing;
}
/**
* Sets the major ticks spacing.
*
* @param spacing the major ticks spacing
*/
public void setMajorTicksSpacing(double spacing) {
mMajorTickSpacing = spacing;
}
/**
* Returns the visual type at the specified index.
*
* @param index the index
* @return the visual type
*/
public Type getVisualTypeForIndex(int index) {
if (index < mVisualTypes.size()) {
return mVisualTypes.get(index);
}
return Type.NEEDLE;
}
/**
* Sets the visual types.
*
* @param types the visual types
*/
public void setVisualTypes(Type[] types) {
mVisualTypes.clear();
mVisualTypes.addAll(Arrays.asList(types));
}
}

View File

@ -1,227 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.renderer;
import java.io.Serializable;
import android.graphics.Color;
import android.graphics.Paint.Align;
/**
* A simple series renderer.
*/
public class SimpleSeriesRenderer implements Serializable {
/** The series color. */
private int mColor = Color.BLUE;
/** If the values should be displayed above the chart points. */
private boolean mDisplayChartValues;
/** The chart values text size. */
private float mChartValuesTextSize = 10;
/** The chart values text alignment. */
private Align mChartValuesTextAlign = Align.CENTER;
/** The chart values spacing from the data point. */
private float mChartValuesSpacing = 5f;
/** The stroke style. */
private BasicStroke mStroke;
/** If gradient is enabled. */
private boolean mGradientEnabled = false;
/** The gradient start value. */
private double mGradientStartValue;
/** The gradient start color. */
private int mGradientStartColor;
/** The gradient stop value. */
private double mGradientStopValue;
/** The gradient stop color. */
private int mGradientStopColor;
/**
* Returns the series color.
*
* @return the series color
*/
public int getColor() {
return mColor;
}
/**
* Sets the series color.
*
* @param color the series color
*/
public void setColor(int color) {
mColor = color;
}
/**
* Returns if the chart point values should be displayed as text.
*
* @return if the chart point values should be displayed as text
*/
public boolean isDisplayChartValues() {
return mDisplayChartValues;
}
/**
* Sets if the chart point values should be displayed as text.
*
* @param display if the chart point values should be displayed as text
*/
public void setDisplayChartValues(boolean display) {
mDisplayChartValues = display;
}
/**
* Returns the chart values text size.
*
* @return the chart values text size
*/
public float getChartValuesTextSize() {
return mChartValuesTextSize;
}
/**
* Sets the chart values text size.
*
* @param textSize the chart values text size
*/
public void setChartValuesTextSize(float textSize) {
mChartValuesTextSize = textSize;
}
/**
* Returns the chart values text align.
*
* @return the chart values text align
*/
public Align getChartValuesTextAlign() {
return mChartValuesTextAlign;
}
/**
* Sets the chart values text align.
*
* @param align the chart values text align
*/
public void setChartValuesTextAlign(Align align) {
mChartValuesTextAlign = align;
}
/**
* Returns the chart values spacing from the data point.
*
* @return the chart values spacing
*/
public float getChartValuesSpacing() {
return mChartValuesSpacing;
}
/**
* Sets the chart values spacing from the data point.
*
* @param spacing the chart values spacing (in pixels) from the chart data point
*/
public void setChartValuesSpacing(float spacing) {
mChartValuesSpacing = spacing;
}
/**
* Returns the stroke style.
*
* @return the stroke style
*/
public BasicStroke getStroke() {
return mStroke;
}
/**
* Sets the stroke style.
*
* @param stroke the stroke style
*/
public void setStroke(BasicStroke stroke) {
mStroke = stroke;
}
/**
* Returns the gradient is enabled value.
* @return the gradient enabled
*/
public boolean isGradientEnabled() {
return mGradientEnabled;
}
/**
* Sets the gradient enabled value.
* @param enabled the gradient enabled
*/
public void setGradientEnabled(boolean enabled) {
mGradientEnabled = enabled;
}
/**
* Returns the gradient start value.
* @return the gradient start value
*/
public double getGradientStartValue() {
return mGradientStartValue;
}
/**
* Returns the gradient start color.
* @return the gradient start color
*/
public int getGradientStartColor() {
return mGradientStartColor;
}
/**
* Sets the gradient start value and color.
* @param start the gradient start value
* @param color the gradient start color
*/
public void setGradientStart(double start, int color) {
mGradientStartValue = start;
mGradientStartColor = color;
}
/**
* Returns the gradient stop value.
* @return the gradient stop value
*/
public double getGradientStopValue() {
return mGradientStopValue;
}
/**
* Returns the gradient stop color.
* @return the gradient stop color
*/
public int getGradientStopColor() {
return mGradientStopColor;
}
/**
* Sets the gradient stop value and color.
* @param start the gradient stop value
* @param color the gradient stop color
*/
public void setGradientStop(double start, int color) {
mGradientStopValue = start;
mGradientStopColor = color;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.renderer;
import org.achartengine.chart.PointStyle;
import android.graphics.Color;
/**
* A renderer for the XY type series.
*/
public class XYSeriesRenderer extends SimpleSeriesRenderer {
/** If the chart points should be filled. */
private boolean mFillPoints = false;
/** If the chart should be filled below its line. */
private boolean mFillBelowLine = false;
/** The fill below the chart line color. */
private int mFillColor = Color.argb(125, 0, 0, 200);
/** The point style. */
private PointStyle mPointStyle = PointStyle.POINT;
/** The chart line width. */
private float mLineWidth = 1;
/**
* Returns if the chart should be filled below the line.
*
* @return the fill below line status
*/
public boolean isFillBelowLine() {
return mFillBelowLine;
}
/**
* Sets if the line chart should be filled below its line. Filling below the
* line transforms a line chart into an area chart.
*
* @param fill the fill below line flag value
*/
public void setFillBelowLine(boolean fill) {
mFillBelowLine = fill;
}
/**
* Returns if the chart points should be filled.
*
* @return the points fill status
*/
public boolean isFillPoints() {
return mFillPoints;
}
/**
* Sets if the chart points should be filled.
*
* @param fill the points fill flag value
*/
public void setFillPoints(boolean fill) {
mFillPoints = fill;
}
/**
* Returns the fill below line color.
*
* @return the fill below line color
*/
public int getFillBelowLineColor() {
return mFillColor;
}
/**
* Sets the fill below the line color.
*
* @param color the fill below line color
*/
public void setFillBelowLineColor(int color) {
mFillColor = color;
}
/**
* Returns the point style.
*
* @return the point style
*/
public PointStyle getPointStyle() {
return mPointStyle;
}
/**
* Sets the point style.
*
* @param style the point style
*/
public void setPointStyle(PointStyle style) {
mPointStyle = style;
}
/**
* Returns the chart line width.
*
* @return the line width
*/
public float getLineWidth() {
return mLineWidth;
}
/**
* Sets the chart line width.
*
* @param lineWidth the line width
*/
public void setLineWidth(float lineWidth) {
mLineWidth = lineWidth;
}
}

View File

@ -1,111 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.XYChart;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
/**
* Abstract class for being extended by graphical view tools.
*/
public abstract class AbstractTool {
/** The chart. */
protected AbstractChart mChart;
/** The renderer. */
protected XYMultipleSeriesRenderer mRenderer;
/**
* Abstract tool constructor.
*
* @param chart the chart
*/
public AbstractTool(AbstractChart chart) {
mChart = chart;
if (chart instanceof XYChart) {
mRenderer = ((XYChart) chart).getRenderer();
}
}
/**
* Returns the current chart range.
*
* @param scale the scale
* @return the chart range
*/
public double[] getRange(int scale) {
double minX = mRenderer.getXAxisMin(scale);
double maxX = mRenderer.getXAxisMax(scale);
double minY = mRenderer.getYAxisMin(scale);
double maxY = mRenderer.getYAxisMax(scale);
return new double[] { minX, maxX, minY, maxY };
}
/**
* Sets the range to the calculated one, if not already set.
*
* @param range the range
* @param scale the scale
*/
public void checkRange(double[] range, int scale) {
if (mChart instanceof XYChart) {
double[] calcRange = ((XYChart) mChart).getCalcRange(scale);
if (calcRange != null) {
if (!mRenderer.isMinXSet(scale)) {
range[0] = calcRange[0];
mRenderer.setXAxisMin(range[0], scale);
}
if (!mRenderer.isMaxXSet(scale)) {
range[1] = calcRange[1];
mRenderer.setXAxisMax(range[1], scale);
}
if (!mRenderer.isMinYSet(scale)) {
range[2] = calcRange[2];
mRenderer.setYAxisMin(range[2], scale);
}
if (!mRenderer.isMaxYSet(scale)) {
range[3] = calcRange[3];
mRenderer.setYAxisMax(range[3], scale);
}
}
}
}
/**
* Sets a new range on the X axis.
*
* @param min the minimum value
* @param max the maximum value
* @param scale the scale
*/
protected void setXRange(double min, double max, int scale) {
mRenderer.setXAxisMin(min, scale);
mRenderer.setXAxisMax(max, scale);
}
/**
* Sets a new range on the Y axis.
*
* @param min the minimum value
* @param max the maximum value
* @param scale the scale
*/
protected void setYRange(double min, double max, int scale) {
mRenderer.setYAxisMin(min, scale);
mRenderer.setYAxisMax(max, scale);
}
}

View File

@ -1,78 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.RoundChart;
import org.achartengine.chart.XYChart;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.util.MathHelper;
public class FitZoom extends AbstractTool {
/**
* Builds an instance of the fit zoom tool.
*
* @param chart the XY chart
*/
public FitZoom(AbstractChart chart) {
super(chart);
}
/**
* Apply the tool.
*/
public void apply() {
if (mChart instanceof XYChart) {
if (((XYChart) mChart).getDataset() == null) {
return;
}
int scales = mRenderer.getScalesCount();
if (mRenderer.isInitialRangeSet()) {
for (int i = 0; i < scales; i++) {
if (mRenderer.isInitialRangeSet(i)) {
mRenderer.setRange(mRenderer.getInitialRange(i), i);
}
}
} else {
XYSeries[] series = ((XYChart) mChart).getDataset().getSeries();
double[] range = null;
int length = series.length;
if (length > 0) {
for (int i = 0; i < scales; i++) {
range = new double[] { MathHelper.NULL_VALUE, -MathHelper.NULL_VALUE,
MathHelper.NULL_VALUE, -MathHelper.NULL_VALUE };
for (int j = 0; j < length; j++) {
if (i == series[j].getScaleNumber()) {
range[0] = Math.min(range[0], series[j].getMinX());
range[1] = Math.max(range[1], series[j].getMaxX());
range[2] = Math.min(range[2], series[j].getMinY());
range[3] = Math.max(range[3], series[j].getMaxY());
}
}
double marginX = Math.abs(range[1] - range[0]) / 40;
double marginY = Math.abs(range[3] - range[2]) / 40;
mRenderer.setRange(new double[] { range[0] - marginX, range[1] + marginX,
range[2] - marginY, range[3] + marginY }, i);
}
}
}
} else {
DefaultRenderer renderer = ((RoundChart) mChart).getRenderer();
renderer.setScale(renderer.getOriginalScale());
}
}
}

View File

@ -1,169 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
import java.util.ArrayList;
import java.util.List;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.RoundChart;
import org.achartengine.chart.XYChart;
/**
* The pan tool.
*/
public class Pan extends AbstractTool {
/** The pan listeners. */
private List<PanListener> mPanListeners = new ArrayList<PanListener>();
/** Pan limits reached on the X axis. */
private boolean limitsReachedX = false;
/** Pan limits reached on the X axis. */
private boolean limitsReachedY = false;
/**
* Builds and instance of the pan tool.
*
* @param chart the XY chart
*/
public Pan(AbstractChart chart) {
super(chart);
}
/**
* Apply the tool.
*
* @param oldX the previous location on X axis
* @param oldY the previous location on Y axis
* @param newX the current location on X axis
* @param newY the current location on the Y axis
*/
public void apply(float oldX, float oldY, float newX, float newY) {
boolean notLimitedUp = true;
boolean notLimitedBottom = true;
boolean notLimitedLeft = true;
boolean notLimitedRight = true;
if (mChart instanceof XYChart) {
int scales = mRenderer.getScalesCount();
double[] limits = mRenderer.getPanLimits();
boolean limited = limits != null && limits.length == 4;
XYChart chart = (XYChart) mChart;
for (int i = 0; i < scales; i++) {
double[] range = getRange(i);
double[] calcRange = chart.getCalcRange(i);
if (limitsReachedX
&& limitsReachedY
&& (range[0] == range[1] && calcRange[0] == calcRange[1] || range[2] == range[3]
&& calcRange[2] == calcRange[3])) {
return;
}
checkRange(range, i);
double[] realPoint = chart.toRealPoint(oldX, oldY, i);
double[] realPoint2 = chart.toRealPoint(newX, newY, i);
double deltaX = realPoint[0] - realPoint2[0];
double deltaY = realPoint[1] - realPoint2[1];
double ratio = getAxisRatio(range);
if (chart.isVertical(mRenderer)) {
double newDeltaX = -deltaY * ratio;
double newDeltaY = deltaX / ratio;
deltaX = newDeltaX;
deltaY = newDeltaY;
}
if (mRenderer.isPanXEnabled()) {
if (limits != null) {
if (notLimitedLeft) {
notLimitedLeft = limits[0] <= range[0] + deltaX;
}
if (notLimitedRight) {
notLimitedRight = limits[1] >= range[1] + deltaX;
}
}
if (!limited || (notLimitedLeft && notLimitedRight)) {
setXRange(range[0] + deltaX, range[1] + deltaX, i);
limitsReachedX = false;
} else {
limitsReachedX = true;
}
}
if (mRenderer.isPanYEnabled()) {
if (notLimitedBottom && limits != null) {
notLimitedBottom = limits[2] <= range[2] - deltaY;
}
if (notLimitedUp && limits != null) {
notLimitedUp = limits[3] >= range[3] - deltaY;
}
if (limited && (!notLimitedBottom && !notLimitedUp)) {
limitsReachedY = true;
} else {
if (!notLimitedUp && deltaY < 0) {
setYRange(range[2] + deltaY, range[3] + deltaY, i);
notLimitedUp = true;
} else if (!notLimitedBottom && deltaY > 0) {
setYRange(range[2] + deltaY, range[3] + deltaY, i);
notLimitedBottom = true;
} else if (notLimitedBottom && notLimitedUp) {
setYRange(range[2] + deltaY, range[3] + deltaY, i);
}
limitsReachedY = false;
}
}
}
} else {
RoundChart chart = (RoundChart) mChart;
chart.setCenterX(chart.getCenterX() + (int) (newX - oldX));
chart.setCenterY(chart.getCenterY() + (int) (newY - oldY));
}
notifyPanListeners();
}
/**
* Return the X / Y axis range ratio.
*
* @param range the axis range
* @return the ratio
*/
private double getAxisRatio(double[] range) {
return Math.abs(range[1] - range[0]) / Math.abs(range[3] - range[2]);
}
/**
* Notify the pan listeners about a pan.
*/
private synchronized void notifyPanListeners() {
for (PanListener listener : mPanListeners) {
listener.panApplied();
}
}
/**
* Adds a new pan listener.
*
* @param listener pan listener
*/
public synchronized void addPanListener(PanListener listener) {
mPanListeners.add(listener);
}
/**
* Removes a pan listener.
*
* @param listener pan listener
*/
public synchronized void removePanListener(PanListener listener) {
mPanListeners.add(listener);
}
}

View File

@ -1,28 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
/**
* A pan listener.
*/
public interface PanListener {
/**
* Called when a pan change is triggered.
*/
void panApplied();
}

View File

@ -1,168 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
import java.util.ArrayList;
import java.util.List;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.RoundChart;
import org.achartengine.chart.XYChart;
import org.achartengine.renderer.DefaultRenderer;
/**
* The zoom tool.
*/
public class Zoom extends AbstractTool {
/** A flag to be used to know if this is a zoom in or out. */
private boolean mZoomIn;
/** The zoom rate. */
private float mZoomRate;
/** The zoom listeners. */
private List<ZoomListener> mZoomListeners = new ArrayList<ZoomListener>();
/** Zoom limits reached on the X axis. */
private boolean limitsReachedX = false;
/** Zoom limits reached on the Y axis. */
private boolean limitsReachedY = false;
/**
* Builds the zoom tool.
*
* @param chart the chart
* @param in zoom in or out
* @param rate the zoom rate
*/
public Zoom(AbstractChart chart, boolean in, float rate) {
super(chart);
mZoomIn = in;
setZoomRate(rate);
}
/**
* Sets the zoom rate.
*
* @param rate
*/
public void setZoomRate(float rate) {
mZoomRate = rate;
}
/**
* Apply the zoom.
*/
public void apply() {
if (mChart instanceof XYChart) {
int scales = mRenderer.getScalesCount();
for (int i = 0; i < scales; i++) {
double[] range = getRange(i);
checkRange(range, i);
double[] limits = mRenderer.getZoomLimits();
boolean limited = limits != null && limits.length == 4;
double centerX = (range[0] + range[1]) / 2;
double centerY = (range[2] + range[3]) / 2;
double newWidth = range[1] - range[0];
double newHeight = range[3] - range[2];
if (mZoomIn) {
if (mRenderer.isZoomXEnabled()) {
limitsReachedX = false;
newWidth /= mZoomRate;
}
if (mRenderer.isZoomYEnabled()) {
limitsReachedY = false;
newHeight /= mZoomRate;
}
} else {
if (mRenderer.isZoomXEnabled()) {
if (limitsReachedX) {
newWidth *= mZoomRate;
}
}
if (mRenderer.isZoomYEnabled()) {
if (limitsReachedY) {
newHeight *= mZoomRate;
}
}
}
if (mRenderer.isZoomXEnabled()) {
double newXMin = centerX - newWidth / 2;
double newXMax = centerX + newWidth / 2;
if (!limited || limits[0] <= newXMin && limits[1] >= newXMax) {
setXRange(newXMin, newXMax, i);
} else {
limitsReachedX = true;
}
}
if (mRenderer.isZoomYEnabled()) {
double newYMin = centerY - newHeight / 2;
double newYMax = centerY + newHeight / 2;
if (!limited || limits[2] <= newYMin && limits[3] >= newYMax) {
setYRange(newYMin, newYMax, i);
} else {
limitsReachedY = true;
}
}
}
} else {
DefaultRenderer renderer = ((RoundChart) mChart).getRenderer();
if (mZoomIn) {
renderer.setScale(renderer.getScale() * mZoomRate);
} else {
renderer.setScale(renderer.getScale() / mZoomRate);
}
}
notifyZoomListeners(new ZoomEvent(mZoomIn, mZoomRate));
}
/**
* Notify the zoom listeners about a zoom change.
*
* @param e the zoom event
*/
private synchronized void notifyZoomListeners(ZoomEvent e) {
for (ZoomListener listener : mZoomListeners) {
listener.zoomApplied(e);
}
}
/**
* Notify the zoom listeners about a zoom reset.
*/
public synchronized void notifyZoomResetListeners() {
for (ZoomListener listener : mZoomListeners) {
listener.zoomReset();
}
}
/**
* Adds a new zoom listener.
*
* @param listener zoom listener
*/
public synchronized void addZoomListener(ZoomListener listener) {
mZoomListeners.add(listener);
}
/**
* Removes a zoom listener.
*
* @param listener zoom listener
*/
public synchronized void removeZoomListener(ZoomListener listener) {
mZoomListeners.add(listener);
}
}

View File

@ -1,56 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
/**
* A zoom event.
*/
public class ZoomEvent {
/** A flag to be used to know if this is a zoom in or out. */
private boolean mZoomIn;
/** The zoom rate. */
private float mZoomRate;
/**
* Builds the zoom tool.
*
* @param in zoom in or out
* @param rate the zoom rate
*/
public ZoomEvent(boolean in, float rate) {
mZoomIn = in;
mZoomRate = rate;
}
/**
* Returns the zoom type.
*
* @return true if zoom in, false otherwise
*/
public boolean isZoomIn() {
return mZoomIn;
}
/**
* Returns the zoom rate.
*
* @return the zoom rate
*/
public float getZoomRate() {
return mZoomRate;
}
}

View File

@ -1,33 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.tools;
/**
* A zoom listener.
*/
public interface ZoomListener {
/**
* Called when a zoom change is triggered.
* @param e the zoom event
*/
void zoomApplied(ZoomEvent e);
/**
* Called when a zoom reset is done.
*/
void zoomReset();
}

View File

@ -1,108 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.util;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
/**
* This class requires sorted x values
*/
public class IndexXYMap<K, V> extends TreeMap<K, V> {
private final List<K> indexList = new ArrayList<K>();
private double maxXDifference = 0;
public IndexXYMap() {
super();
}
public V put(K key, V value) {
indexList.add(key);
updateMaxXDifference();
return super.put(key, value);
}
private void updateMaxXDifference() {
if (indexList.size() < 2) {
maxXDifference = 0;
return;
}
if (Math.abs((Double) indexList.get(indexList.size() - 1)
- (Double) indexList.get(indexList.size() - 2)) > maxXDifference) {
maxXDifference = Math.abs((Double) indexList.get(indexList.size() - 1)
- (Double) indexList.get(indexList.size() - 2));
}
}
public double getMaxXDifference() {
return maxXDifference;
}
public void clear() {
updateMaxXDifference();
super.clear();
indexList.clear();
}
/**
* Returns X-value according to the given index
*
* @param index
* @return
*/
public K getXByIndex(int index) {
return indexList.get(index);
}
/**
* Returns Y-value according to the given index
*
* @param index
* @return
*/
public V getYByIndex(int index) {
K key = indexList.get(index);
return this.get(key);
}
/**
* Returns XY-entry according to the given index
*
* @param index
* @return
*/
public XYEntry<K, V> getByIndex(int index) {
K key = indexList.get(index);
return new XYEntry<K, V>(key, this.get(key));
}
/**
* Removes entry from map by index
*
* @param index
*/
public XYEntry<K, V> removeByIndex(int index) {
K key = indexList.remove(index);
return new XYEntry<K, V>(key, this.remove(key));
}
public int getIndexForKey(K key) {
return indexList.indexOf(key);
}
}

View File

@ -1,174 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.util;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for math operations.
*/
public class MathHelper {
/** A value that is used a null value. */
public static final double NULL_VALUE = Double.MAX_VALUE;
/**
* A number formatter to be used to make sure we have a maximum number of
* fraction digits in the labels.
*/
private static final NumberFormat FORMAT = NumberFormat.getNumberInstance();
private MathHelper() {
// empty constructor
}
/**
* Calculate the minimum and maximum values out of a list of doubles.
*
* @param values the input values
* @return an array with the minimum and maximum values
*/
public static double[] minmax(List<Double> values) {
if (values.size() == 0) {
return new double[2];
}
double min = values.get(0);
double max = min;
int length = values.size();
for (int i = 1; i < length; i++) {
double value = values.get(i);
min = Math.min(min, value);
max = Math.max(max, value);
}
return new double[] { min, max };
}
/**
* Computes a reasonable set of labels for a data interval and number of
* labels.
*
* @param start start value
* @param end final value
* @param approxNumLabels desired number of labels
* @return collection containing {start value, end value, increment}
*/
public static List<Double> getLabels(final double start, final double end,
final int approxNumLabels) {
FORMAT.setMaximumFractionDigits(5);
List<Double> labels = new ArrayList<Double>();
double[] labelParams = computeLabels(start, end, approxNumLabels);
// when the start > end the inc will be negative so it will still work
int numLabels = 1 + (int) ((labelParams[1] - labelParams[0]) / labelParams[2]);
// we want the range to be inclusive but we don't want to blow up when
// looping for the case where the min and max are the same. So we loop
// on
// numLabels not on the values.
for (int i = 0; i < numLabels; i++) {
double z = labelParams[0] + i * labelParams[2];
try {
// this way, we avoid a label value like 0.4000000000000000001 instead
// of 0.4
z = FORMAT.parse(FORMAT.format(z)).doubleValue();
} catch (ParseException e) {
// do nothing here
}
labels.add(z);
}
return labels;
}
/**
* Computes a reasonable number of labels for a data range.
*
* @param start start value
* @param end final value
* @param approxNumLabels desired number of labels
* @return double[] array containing {start value, end value, increment}
*/
private static double[] computeLabels(final double start, final double end,
final int approxNumLabels) {
if (Math.abs(start - end) < 0.0000001f) {
return new double[] { start, start, 0 };
}
double s = start;
double e = end;
boolean switched = false;
if (s > e) {
switched = true;
double tmp = s;
s = e;
e = tmp;
}
double xStep = roundUp(Math.abs(s - e) / approxNumLabels);
// Compute x starting point so it is a multiple of xStep.
double xStart = xStep * Math.ceil(s / xStep);
double xEnd = xStep * Math.floor(e / xStep);
if (switched) {
return new double[] { xEnd, xStart, -1.0 * xStep };
}
return new double[] { xStart, xEnd, xStep };
}
/**
* Given a number, round up to the nearest power of ten times 1, 2, or 5. The
* argument must be strictly positive.
*/
private static double roundUp(final double val) {
int exponent = (int) Math.floor(Math.log10(val));
double rval = val * Math.pow(10, -exponent);
if (rval > 5.0) {
rval = 10.0;
} else if (rval > 2.0) {
rval = 5.0;
} else if (rval > 1.0) {
rval = 2.0;
}
rval *= Math.pow(10, exponent);
return rval;
}
/**
* Transforms a list of Float values into an array of float.
*
* @param values the list of Float
* @return the array of floats
*/
public static float[] getFloats(List<Float> values) {
int length = values.size();
float[] result = new float[length];
for (int i = 0; i < length; i++) {
result[i] = values.get(i);
}
return result;
}
/**
* Transforms a list of Double values into an array of double.
*
* @param values the list of Double
* @return the array of doubles
*/
public static double[] getDoubles(List<Double> values) {
int length = values.size();
double[] result = new double[length];
for (int i = 0; i < length; i++) {
result[i] = values.get(i);
}
return result;
}
}

View File

@ -1,45 +0,0 @@
/**
* Copyright (C) 2009, 2010 SC 4ViewSoft SRL
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.achartengine.util;
import java.util.Map.Entry;
/**
* A map entry value encapsulating an XY point.
*/
public class XYEntry<K, V> implements Entry<K, V> {
private final K key;
private V value;
public XYEntry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V object) {
this.value = object;
return this.value;
}
}