Is it possible? have anyone been doing this before? I don\'t know where to start.
I mostly need the menu, not the context menu.
My \"BudgetPieChart\" class
To get a menu you need only 1 thing. You have to use GraphicalView on your own activity. In order to do that you'll need:
Former BudgetPieChart class
public class ExpByCatPieChartHelper extends AbstractChart{
private DataToArray dta;
@Override
public String getName() {
return MyApplication.getContext().getString(R.string.ExpensesByCategoriesPieChartName);
}
@Override
public String getDesc() {
return "The budget per project for this year (pie chart)";
}
public GraphicalView createView(Context context) {
dta = new DataToArray();
String[] categories = dta.expenseByCategoriesToArray();
double[] values = dta.expensesValuesByCategoriesToArray();
int[] colors = dta.getColorsArray(categories.length);
DefaultRenderer renderer = buildCategoryRenderer(colors);
renderer.setZoomButtonsVisible(true);
renderer.setZoomEnabled(true);
renderer.setChartTitleTextSize(20);
return ChartFactory.getPieChartView(context, buildCategoryDataset("Wydatki kategoriami", categories, values), renderer);
}
@Override
public Intent execute(Context context) {
return null;
}
}
Additional class with activity of your own:
public class ExpByCatPieChart extends Activity{
private IACharts pieChart = new ExpByCatPieChartHelper();
@Override
protected void onCreate(Bundle savedInstanceState) {
GraphicalView mGraphicalView = new ExpByCatPieChartHelper().createView(this);
setContentView(mGraphicalView);
super.onCreate(savedInstanceState);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.chart_settings_menu, menu);
return true;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()) {
case R.id.chart_settings:
Intent i = new Intent(this, PieChartSettings.class);
startActivityForResult(i, 0);
return true;
case R.id.home:
finish();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
}
And this is pretty much everything. You get a default achart view and seit it as a content of a new activity. Viola :)
OK so here it is. In my case CustomGraphicalView extends org.achartengine.GraphicalView but you can extend whatever class you need.
private CustomGraphicalView mGraphicalView = new BudgetPieChart().createView(this); // you edit the createView() with your input data for the graph
private RelativeLayout chart_layout = (RelativeLayout) findViewById(R.id.chart_layout);
android.widget.RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(width, height);
chart_layout.setGravity(Gravity.CENTER);
chart_layout.addView(mGraphicalView, param);
public CustomGraphicalView createView(Context context) {
double[] values = new double[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; //your desired values
int[] colors = new int[] { // Color.BLUE, Color.GREEN, Color.MAGENTA, Color.YELLOW, Color.CYAN (your desired colors)
Color.parseColor("#ff3399ff"), Color.parseColor("#ff0066cc"), Color.parseColor("#ff613592"), Color.parseColor("#ff7d3493"), Color.parseColor("#ffe81f53"), Color.parseColor("#ffeb5531"), Color.parseColor("#fff6bb2d"), Color.parseColor("#fff39f2f"), Color.parseColor("#ffe0d347"), Color.parseColor("#ff78c200") };
// remember to have enough colors to match the number of elements from the data array for each pie slice
DefaultRenderer renderer = buildCategoryRenderer(colors);
renderer.setZoomButtonsVisible(false);
renderer.setZoomEnabled(false);
renderer.setChartTitleTextSize(20);
renderer.setAntialiasing(true);
renderer.setApplyBackgroundColor(false);
renderer.setBackgroundColor(Color.TRANSPARENT);
renderer.setPanEnabled(false);
renderer.setShowLabels(false);
renderer.setShowLegend(false);
return CustomChartFactory.getPieChartView(context, buildCategoryDataset("Project budget", values), renderer);
}
@Override
public Intent execute(Context arg0) {
// NOT USED
return null;
}
public class CustomChartFactory {
/** 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 CustomChartFactory() {
// empty for now
}
/**
* 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 CustomGraphicalView getPieChartView(Context context, CategorySeries dataset, DefaultRenderer renderer) {
checkParameters(dataset, renderer);
CustomPieChart chart = new CustomPieChart(dataset, renderer);
return new CustomGraphicalView(context, chart);
}
/**
* 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");
}
}
}
This should get you going further with your project :) Good luck!
public class CustomGraphicalView extends org.achartengine.GraphicalView {
/** The chart to be drawn. */
private final AbstractChart mChart;
/** The chart renderer. */
private DefaultRenderer mRenderer;
/** The view bounds. */
private final Rect mRect = new Rect();
/** The user interface thread handler. */
private final Handler mHandler;
/** The zoom buttons rectangle. */
private final 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 final 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 final Paint mPaint = new Paint();
/** The touch handler. */
private ITouchHandler mTouchHandler;
/** The old x coordinate. */
private float oldX;
/** The old y coordinate. */
private float oldY;
public boolean isRotating;
private float mX1, mY1, pY1, pX1, mX2, mY2, py, px, lastAngle, angle_rotation, rotation;
/**
* Creates a new graphical view.
*
* @param context
* the context
* @param chart
* the chart to be drawn
*/
public CustomGraphicalView(Context context, AbstractChart chart) {
super(context, chart);
setOnTouchListener(this);
mChart = chart;
mHandler = new Handler();
if (mChart instanceof XYChart) {
mRenderer = ((XYChart) mChart).getRenderer();
} else {
mRenderer = ((RoundChart) mChart).getRenderer();
}
if (mRenderer.isZoomButtonsVisible()) {
zoomInImage = BitmapFactory.decodeStream(CustomGraphicalView.class.getResourceAsStream("image/zoom_in.png"));
zoomOutImage = BitmapFactory.decodeStream(CustomGraphicalView.class.getResourceAsStream("image/zoom_out.png"));
fitZoomImage = BitmapFactory.decodeStream(CustomGraphicalView.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);
}
int version = 7;
try {
version = Integer.valueOf(Build.VERSION.SDK);
} catch (Exception e) {
// do nothing
}
if (version < 7) {
mTouchHandler = new TouchHandlerOld(this, mChart);
} else {
mTouchHandler = new TouchHandler(this, mChart);
}
}
/**
* Returns the current series selection object.
*
* @return the series selection
*/
@Override
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
*/
@Override
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.save();
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 != null) && 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);
}
canvas.restore();
}
/**
* Sets the zoom rate.
*
* @param rate
* the zoom rate
*/
@Override
public void setZoomRate(float rate) {
if ((mZoomIn != null) && (mZoomOut != null)) {
mZoomIn.setZoomRate(rate);
mZoomOut.setZoomRate(rate);
}
}
/**
* Do a chart zoom in.
*/
@Override
public void zoomIn() {
if (mZoomIn != null) {
mZoomIn.apply();
repaint();
}
}
/**
* Do a chart zoom out.
*/
@Override
public void zoomOut() {
if (mZoomOut != null) {
mZoomOut.apply();
repaint();
}
}
/**
* Do a chart zoom reset / fit zoom.
*/
@Override
public void zoomReset() {
if (mFitZoom != null) {
mFitZoom.apply();
mZoomIn.notifyZoomResetListeners();
repaint();
}
}
/**
* Adds a new zoom listener.
*
* @param listener
* zoom listener
*/
@Override
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
*/
@Override
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
*/
@Override
public void addPanListener(PanListener listener) {
mTouchHandler.addPanListener(listener);
}
/**
* Removes a pan listener.
*
* @param listener
* pan listener
*/
@Override
public void removePanListener(PanListener listener) {
mTouchHandler.removePanListener(listener);
}
@Override
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.
*/
@Override
public void repaint() {
mHandler.post(new Runnable() {
@Override
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
*/
@Override
public void repaint(final int left, final int top, final int right, final int bottom) {
mHandler.post(new Runnable() {
@Override
public void run() {
invalidate(left, top, right, bottom);
}
});
}
/**
* Saves the content of the graphical view to a bitmap.
*
* @return the bitmap
*/
@Override
public Bitmap toBitmap() {
setDrawingCacheEnabled(false);
if (!isDrawingCacheEnabled()) {
setDrawingCacheEnabled(true);
}
if (mRenderer.isApplyBackgroundColor()) {
setDrawingCacheBackgroundColor(mRenderer.getBackgroundColor());
}
setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
return getDrawingCache(true);
}
}
public class CustomPieChart extends RoundChart {
public static int radius = 115;
float currentAngle;
/** Handles returning values when tapping on PieChart. */
private final PieMapper mPieMapper;
/**
* Builds a new pie chart instance.
*
* @param dataset
* the series dataset
* @param renderer
* the series renderer
*/
public CustomPieChart(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.setAntiAlias(true);
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);
currentAngle = 0;
int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
// 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(mRadius, 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, 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 static int getRadius() {
return radius;
}
@Override
public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
return mPieMapper.getSeriesAndPointForScreenCoordinate(screenPoint);
}
}
I found the solution to create a context menu here. Once the renderer (XYMultipleSeriesRenderer
) is setClickEnabled(true);
you can use onCreateContextMenuListener
in the usual way.