/** * 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.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.Build; 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); } 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 */ 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 != 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); } } /** * 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); } }