/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2016 HydroloGIS (www.hydrologis.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.geopaparazzi.library.chart;///* =========================================================== // * AFreeChart : a free chart library for Android(tm) platform. // * (based on JFreeChart and JCommon) // * =========================================================== // * // * (C) Copyright 2010, by ICOMSYSTECH Co.,Ltd. // * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors. // * // * Project Info: // * AFreeChart: http://code.google.com/p/afreechart/ // * JFreeChart: http://www.jfree.org/jfreechart/index.html // * JCommon : http://www.jfree.org/jcommon/index.html // * // * This program is free software: you can redistribute it and/or modify // * it under the terms of the GNU Lesser General Public License as published by // * the Free Software Foundation, either version 3 of the License, or // * (at your option) any later version. // * // * This program is distributed in the hope that it will be useful, // * but WITHOUT ANY WARRANTY; without even the implied warranty of // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // * GNU Lesser General Public License for more details. // * // * You should have received a copy of the GNU Lesser General Public License // * along with this program. If not, see <http://www.gnu.org/licenses/>. // * // * [Android is a trademark of Google Inc.] // * // * ----------------- // * ChartView.java // * ----------------- // * (C) Copyright 2010, by ICOMSYSTECH Co.,Ltd. // * // * Original Author: Niwano Masayoshi (for ICOMSYSTECH Co.,Ltd); // * Contributor(s): -; // * // * Changes // * ------- // * 19-Nov-2010 : Version 0.0.1 (NM); // * 14-Jan-2011 : renamed method name // * 14-Jan-2011 : Updated API docs // */ // //package eu.geopaparazzi.library.chart; // //import java.util.ArrayList; //import java.util.Collection; //import java.util.EventListener; //import java.util.Iterator; //import java.util.List; //import java.util.concurrent.CopyOnWriteArrayList; // //import org.afree.chart.AFreeChart; //import org.afree.chart.ChartFactory; //import org.afree.chart.ChartRenderingInfo; //import org.afree.chart.ChartTouchEvent; //import org.afree.chart.ChartTouchListener; //import org.afree.chart.axis.NumberAxis; //import org.afree.chart.axis.ValueAxis; //import org.afree.chart.entity.ChartEntity; //import org.afree.chart.entity.EntityCollection; //import org.afree.chart.event.ChartChangeEvent; //import org.afree.chart.event.ChartChangeListener; //import org.afree.chart.event.ChartProgressEvent; //import org.afree.chart.event.ChartProgressListener; //import org.afree.chart.plot.Marker; //import org.afree.chart.plot.Movable; //import org.afree.chart.plot.Plot; //import org.afree.chart.plot.PlotOrientation; //import org.afree.chart.plot.PlotRenderingInfo; //import org.afree.chart.plot.XYPlot; //import org.afree.chart.plot.Zoomable; //import org.afree.chart.renderer.xy.XYItemRenderer; //import org.afree.chart.renderer.xy.XYLineAndShapeRenderer; //import org.afree.data.xy.XYDataset; //import org.afree.data.xy.XYSeries; //import org.afree.data.xy.XYSeriesCollection; //import org.afree.graphics.SolidColor; //import org.afree.graphics.geom.Dimension; //import org.afree.graphics.geom.RectShape; //import org.afree.ui.Layer; //import org.afree.ui.RectangleInsets; // //import android.content.Context; //import android.graphics.Canvas; //import android.graphics.Color; //import android.graphics.PointF; //import android.location.Location; //import android.os.Handler; //import android.util.AttributeSet; //import android.view.MotionEvent; //import android.view.View; //import eu.geopaparazzi.library.util.DynamicDoubleArray; //import eu.geopaparazzi.library.util.debug.Debug; //import eu.geopaparazzi.library.util.debug.Logger; // ///** // * A view that contains an updatable chart. // * // * <p>The chart is created empty at first and can be populated // * through:</p> // * <ul> // * <li>use of {@link XYChartView#createDatasetFromXY(double[], double[], String)} or // * {@link XYChartView#createDatasetFromProfile(double[], double[], double[], String)} // * to create a dataset from XY values // * </li> // * <li>use of {@link XYChartView#setDataset(XYDataset, String, String, String)} // * to update the chart</li> // * </ul> // */ //public class XYChartView extends View implements ChartChangeListener, ChartProgressListener { // // /** The user interface thread handler. */ // private Handler mHandler; // // public XYChartView( Context context ) { // super(context); // mHandler = new Handler(); // this.initialize(); // } // // public XYChartView( Context context, AttributeSet attrs ) { // super(context, attrs); // // mHandler = new Handler(); // this.initialize(); // } // // /** // * initialize parameters // */ // private void initialize() { // // this.chartMotionListeners = new CopyOnWriteArrayList<ChartTouchListener>(); // this.info = new ChartRenderingInfo(); // this.minimumDrawWidth = DEFAULT_MINIMUM_DRAW_WIDTH; // this.minimumDrawHeight = DEFAULT_MINIMUM_DRAW_HEIGHT; // this.maximumDrawWidth = DEFAULT_MAXIMUM_DRAW_WIDTH; // this.maximumDrawHeight = DEFAULT_MAXIMUM_DRAW_HEIGHT; // this.moveTriggerDistance = DEFAULT_MOVE_TRIGGER_DISTANCE; // new SolidColor(Color.BLUE); // new SolidColor(Color.argb(0, 0, 255, 63)); // // new java.util.ArrayList(); // // final AFreeChart chart = createChart(createEmptyDataset()); // // setChart(chart); // } // // /** // * Create a dataset based on supplied XY data. // * // * <p> // * Note that this also sets the min and max values // * of the chart data, so the dataset created should // * really be used through setDataset, so that the bounds // * are properly zoomed. // * // * @param xArray the array of ordered X values. // * @param yArray the array of ordered Y values. // * @param seriesName the name to label the serie with. // * @return the {@link XYSeriesCollection dataset}. // */ // public XYSeriesCollection createDatasetFromXY( DynamicDoubleArray xArray, DynamicDoubleArray yArray, String seriesName ) { // XYSeries xyS = new XYSeries(seriesName, true, true); // // int size = xArray.size(); // xMin = 0; // xMax = 1.0; // if (size > 0) { // xMin = xArray.get(0); // if (size > 1) { // xMax = xArray.get(size - 1); // } else { // // fake it // xMax = xMin + 1.0; // } // } // yMin = Double.POSITIVE_INFINITY; // yMax = Double.NEGATIVE_INFINITY; // // for( int i = 0; i < size; i++ ) { // double y = yArray.get(i); // yMin = Math.min(yMin, y); // yMax = Math.max(yMax, y); // xyS.add(xArray.get(i), y); // } // // if (Math.abs(yMin - yMax) < 0.000001) { // // wider range // yMin = yMin - 1; // yMax = yMax + 1; // } // // xMaxAll = xMax; // xMinAll = xMin; // yMaxAll = yMax; // yMinAll = yMin; // // XYSeriesCollection xySC = new XYSeriesCollection(); // xySC.addSeries(xyS); // return xySC; // } // // // /** // // * Create a dataset based on supplied XY data. // // * // // * <p> // // * Note that this also sets the min and max values // // * of the chart data, so the dataset created should // // * really be used through setDataset, so that the bounds // // * are properly zoomed. // // * // // * @param xArray the array of ordered X values. // // * @param yArray the array of ordered Y values. // // * @param seriesName the name to label the serie with. // // * @return the {@link XYSeriesCollection dataset}. // // */ // // public XYSeriesCollection createDatasetFromXY( List<Float> xArray, List<Float> yArray, String // // seriesName ) { // // XYSeries xyS = new XYSeries(seriesName, true, true); // // // // int size = xArray.size(); // // xMin = xArray.get(0); // // xMax = xArray.get(size - 1); // // yMin = Double.POSITIVE_INFINITY; // // yMax = Double.NEGATIVE_INFINITY; // // // // for( int i = 0; i < size; i++ ) { // // double y = yArray.get(i); // // yMin = Math.min(yMin, y); // // yMax = Math.max(yMax, y); // // xyS.add(xArray.get(i).doubleValue(), y); // // } // // // // if (Math.abs(yMin - yMax) < 0.000001) { // // // wider range // // yMin = yMin - 1; // // yMax = yMax + 1; // // } // // // // xMaxAll = xMax; // // xMinAll = xMin; // // yMaxAll = yMax; // // yMinAll = yMin; // // // // XYSeriesCollection xySC = new XYSeriesCollection(); // // xySC.addSeries(xyS); // // return xySC; // // } // // /** // * Create a dataset based on supplied data that are supposed to be coordinates and elevations for a profile view. // * // * <p> // * Note that this also sets the min and max values // * of the chart data, so the dataset created should // * really be used through setDataset, so that the bounds // * are properly zoomed. // * </p> // * // * @param lonArray the array of longitudes. // * @param latArray the array of latitudes. // * @param elevArray the array of elevations. // * @param seriesName the name to label the serie with. // * @return the {@link XYSeriesCollection dataset}. // */ // public XYSeriesCollection createDatasetFromProfile( DynamicDoubleArray lonArray, DynamicDoubleArray latArray, // DynamicDoubleArray elevArray, String seriesName ) { // XYSeries xyS = new XYSeries(seriesName, true, true); // // xMin = 0; // xMax = 1; // just in case no points are in // yMin = Double.POSITIVE_INFINITY; // yMax = Double.NEGATIVE_INFINITY; // // double plat = 0; // double plon = 0; // double summedDistance = 0.0; // for( int i = 0; i < lonArray.size(); i++ ) { // double elev = elevArray.get(i); // double lat = latArray.get(i); // double lon = lonArray.get(i); // // double distance = 0.0; // if (i > 0) { // Location thisLoc = new Location("dummy1"); //$NON-NLS-1$ // thisLoc.setLongitude(lon); // thisLoc.setLatitude(lat); // Location thatLoc = new Location("dummy2"); //$NON-NLS-1$ // thatLoc.setLongitude(plon); // thatLoc.setLatitude(plat); // distance = thisLoc.distanceTo(thatLoc); // } // plat = lat; // plon = lon; // summedDistance = summedDistance + distance; // // yMin = Math.min(yMin, elev); // yMax = Math.max(yMax, elev); // // xyS.add(summedDistance, elev); // } // xMax = summedDistance; // // xMaxAll = xMax; // xMinAll = xMin; // yMaxAll = yMax; // yMinAll = yMin; // // XYSeriesCollection xySC = new XYSeriesCollection(); // xySC.addSeries(xyS); // return xySC; // } // // /** // * Draw the given dataset on the chart. // * // * @param xyDataset the dataset to draw. // */ // public void setDataset( XYDataset xyDataset, String title, String xLabel, String yLabel ) { // if (xyDataset == null) { // xyDataset = createEmptyDataset(); // } // // chart.setTitle(title); // XYPlot plot = (XYPlot) chart.getPlot(); // plot.setDataset(xyDataset); // // NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis(); // domainAxis.setRange(xMin, xMax); // domainAxis.setLabel(xLabel); // ValueAxis valueAxis = plot.getRangeAxis(); // valueAxis.setRange(yMin, yMax); // valueAxis.setLabel(yLabel); // // invalidate(); // } // // /** // * Creates a chart, initially empty. Needs a call to createDataset and setDataset. // * // * @param dataset a dataset. // * @return a chart object. // */ // @SuppressWarnings("nls") // private AFreeChart createChart( XYDataset dataset ) { // // AFreeChart chart = ChartFactory.createXYLineChart("", "", "", dataset, // data // PlotOrientation.VERTICAL, false, // create legend? // true, // generate tooltips? // false // generate URLs? // ); // // chart.setBackgroundPaintType(new SolidColor(Color.WHITE)); // // XYPlot plot = (XYPlot) chart.getPlot(); // plot.setBackgroundPaintType(new SolidColor(Color.LTGRAY)); // plot.setDomainGridlinePaintType(new SolidColor(Color.WHITE)); // plot.setRangeGridlinePaintType(new SolidColor(Color.WHITE)); // plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); // // plot.setDomainCrosshairVisible(true); // // plot.setRangeCrosshairVisible(true); // // XYItemRenderer r = plot.getRenderer(); // if (r instanceof XYLineAndShapeRenderer) { // XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; // renderer.setBaseShapesVisible(true); // renderer.setBaseShapesFilled(true); // renderer.setDrawSeriesLineAsPath(true); // } // // NumberAxis axis = (NumberAxis) plot.getDomainAxis(); // axis.setRange(xMin, xMax); // ValueAxis valueAxis = plot.getRangeAxis(); // valueAxis.setRange(yMin, yMax); // // axis.setDateFormatOverride(new SimpleDateFormat("MMM-yyyy")); // // return chart; // // } // // /** // * Creates an empty dataset. // * // * @return The dataset. // */ // private XYDataset createEmptyDataset() { // XYSeries xyS = new XYSeries("", true, true); //$NON-NLS-1$ // xyS.add(0, 0); // xMin = -1; // xMax = 1; // yMin = -1; // yMax = 1; // // XYSeriesCollection xySC = new XYSeriesCollection(); // xySC.addSeries(xyS); // return xySC; // } // // /** // * Default setting for buffer usage. The default has been changed to // * <code>true</code> from version 1.0.13 onwards, because of a severe // * performance problem with drawing the zoom RectShape using XOR (which // * now happens only when the buffer is NOT used). // */ // public static final boolean DEFAULT_BUFFER_USED = true; // // /** The default panel width. */ // public static final int DEFAULT_WIDTH = 680; // // /** The default panel height. */ // public static final int DEFAULT_HEIGHT = 420; // // /** The default limit below which chart scaling kicks in. */ // public static final int DEFAULT_MINIMUM_DRAW_WIDTH = 10; // // /** The default limit below which chart scaling kicks in. */ // public static final int DEFAULT_MINIMUM_DRAW_HEIGHT = 10; // // /** The default limit above which chart scaling kicks in. */ // public static final int DEFAULT_MAXIMUM_DRAW_WIDTH = 1280; // // /** The default limit above which chart scaling kicks in. */ // public static final int DEFAULT_MAXIMUM_DRAW_HEIGHT = 1000; // // /** The minimum size required to perform a zoom on a RectShape */ // public static final int DEFAULT_ZOOM_TRIGGER_DISTANCE = 10; // // /** The minimum size required to perform a move on a RectShape */ // public static final int DEFAULT_MOVE_TRIGGER_DISTANCE = 10; // // /** The chart that is displayed in the panel. */ // private AFreeChart chart; // // /** Storage for registered (chart) touch listeners. */ // private transient CopyOnWriteArrayList<ChartTouchListener> chartMotionListeners; // // /** The drawing info collected the last time the chart was drawn. */ // private ChartRenderingInfo info; // // /** The scale factor used to draw the chart. */ // private double scaleX; // // /** The scale factor used to draw the chart. */ // private double scaleY; // // /** The plot orientation. */ // private PlotOrientation orientation = PlotOrientation.VERTICAL; // // /** // * The zoom RectShape starting point (selected by the user with touch). // * This is a point on the screen, not the chart (which may have // * been scaled up or down to fit the panel). // */ // private PointF zoomPoint = null; // // /** Controls if the zoom RectShape is drawn as an outline or filled. */ // // private boolean fillZoomRectShape = true; // // private int moveTriggerDistance; // // /** The last touch position during panning. */ // // private Point panLast; // // private RectangleInsets insets = null; // // /** // * The minimum width for drawing a chart (uses scaling for smaller widths). // */ // private int minimumDrawWidth; // // /** // * The minimum height for drawing a chart (uses scaling for smaller // * heights). // */ // private int minimumDrawHeight; // // /** // * The maximum width for drawing a chart (uses scaling for bigger // * widths). // */ // private int maximumDrawWidth; // // /** // * The maximum height for drawing a chart (uses scaling for bigger // * heights). // */ // private int maximumDrawHeight; // // private Dimension size = null; // // /** The chart anchor point. */ // private PointF anchor; // // /** A flag that controls whether or not domain moving is enabled. */ // private boolean domainMovable = false; // // /** A flag that controls whether or not range moving is enabled. */ // private boolean rangeMovable = false; // // private double accelX, accelY; // private double friction = 0.8; // private boolean inertialMovedFlag = false; // private PointF lastTouch; // // private float mScale = 1.0f; // // private long mPrevTimeMillis = 0; // private long mNowTimeMillis = System.currentTimeMillis(); // // /** // * touch event // */ // public boolean onTouchEvent( MotionEvent ev ) { // // super.onTouchEvent(ev); // int action = ev.getAction(); // int count = ev.getPointerCount(); // // this.anchor = new PointF(ev.getX(), ev.getY()); // // if (this.info != null) { // EntityCollection entities = this.info.getEntityCollection(); // if (entities != null) { // } // } // // switch( action & MotionEvent.ACTION_MASK ) { // case MotionEvent.ACTION_DOWN: // case MotionEvent.ACTION_POINTER_DOWN: // if (Debug.D) // Logger.i(this, "ACTION_DOWN"); //$NON-NLS-1$ // if (count == 2 && this.multiTouchStartInfo == null) { // setMultiTouchStartInfo(ev); // } else if (count == 1 && this.singleTouchStartInfo == null) { // setSingleTouchStartInfo(ev); // } // // touched(ev); // // break; // case MotionEvent.ACTION_MOVE: // if (Debug.D) // Logger.i(this, "ACTION_MOVE"); //$NON-NLS-1$ // if (count == 1 && this.singleTouchStartInfo != null) { // moveAdjustment(ev); // } else if (count == 2 && this.multiTouchStartInfo != null) { // // scaleAdjustment(ev); // zoomAdjustment(ev); // } // // inertialMovedFlag = false; // // break; // case MotionEvent.ACTION_UP: // case MotionEvent.ACTION_POINTER_UP: // if (Debug.D) // Logger.i(this, "ACTION_UP"); //$NON-NLS-1$ // if (count <= 2) { // this.multiTouchStartInfo = null; // this.singleTouchStartInfo = null; // } // if (count <= 1) { // this.singleTouchStartInfo = null; // } // // // double click check // if (count == 1) { // mNowTimeMillis = System.currentTimeMillis(); // if (mNowTimeMillis - mPrevTimeMillis < 400) { // if (chart.getPlot() instanceof Movable) { // // restoreAutoBounds(); // zoomToSelection(xMinAll, xMaxAll, yMinAll, yMaxAll); // // mScale = 1.0f; // inertialMovedFlag = false; // } // } else { // inertialMovedFlag = true; // } // mPrevTimeMillis = mNowTimeMillis; // } // break; // default: // break; // } // // return true; // } // // /** // * MultiTouchStartInfo setting // * @param ev // */ // private void setMultiTouchStartInfo( MotionEvent ev ) { // // if (this.multiTouchStartInfo == null) { // this.multiTouchStartInfo = new MultiTouchStartInfo(); // } // // // distance // double distance = Math.sqrt(Math.pow(ev.getX(0) - ev.getX(1), 2) + Math.pow(ev.getY(0) - ev.getY(1), 2)); // this.multiTouchStartInfo.setDistance(distance); // } // // /** // * SingleTouchStartInfo setting // * @param ev // */ // private void setSingleTouchStartInfo( MotionEvent ev ) { // // if (this.singleTouchStartInfo == null) { // this.singleTouchStartInfo = new SingleTouchStartInfo(); // } // // // start point // this.singleTouchStartInfo.setX(ev.getX(0)); // this.singleTouchStartInfo.setY(ev.getY(0)); // } // // /** // * Translate MotionEvent as TouchEvent // * @param ev // */ // private void moveAdjustment( MotionEvent ev ) { // // boolean hMove = false; // boolean vMove = false; // if (this.orientation == PlotOrientation.HORIZONTAL) { // hMove = this.rangeMovable; // vMove = this.domainMovable; // } else { // hMove = this.domainMovable; // vMove = this.rangeMovable; // } // // boolean moveTrigger1 = hMove && Math.abs(ev.getX(0) - this.singleTouchStartInfo.getX()) >= this.moveTriggerDistance; // boolean moveTrigger2 = vMove && Math.abs(ev.getY(0) - this.singleTouchStartInfo.getY()) >= this.moveTriggerDistance; // if (moveTrigger1 || moveTrigger2) { // // RectShape dataArea = this.info.getPlotInfo().getDataArea(); // // double moveBoundX; // double moveBoundY; // double dataAreaWidth = dataArea.getWidth(); // double dataAreaHeight = dataArea.getHeight(); // // // for touchReleased event, (horizontalZoom || verticalZoom) // // will be true, so we can just test for either being false; // // otherwise both are true // // if (!vMove) { // moveBoundX = this.singleTouchStartInfo.getX() - ev.getX(0); // moveBoundY = 0; // } else if (!hMove) { // moveBoundX = 0; // moveBoundY = this.singleTouchStartInfo.getY() - ev.getY(0); // } else { // moveBoundX = this.singleTouchStartInfo.getX() - ev.getX(0); // moveBoundY = this.singleTouchStartInfo.getY() - ev.getY(0); // } // accelX = moveBoundX; // accelY = moveBoundY; // // lastTouch = new PointF(ev.getX(0), ev.getY(0)); // move(lastTouch, moveBoundX, moveBoundY, dataAreaWidth, dataAreaHeight); // // } // // setSingleTouchStartInfo(ev); // } // // /** // * // * @param moveBoundX // * @param moveBoundY // * @param dataAreaWidth // * @param dataAreaHeight // */ // private void move( PointF source, double moveBoundX, double moveBoundY, double dataAreaWidth, double dataAreaHeight ) { // // if (source == null) { // throw new IllegalArgumentException("Null 'source' argument"); //$NON-NLS-1$ // } // // double hMovePercent = moveBoundX / dataAreaWidth; // double vMovePercent = -moveBoundY / dataAreaHeight; // // Plot p = this.chart.getPlot(); // if (p instanceof Movable) { // PlotRenderingInfo info = this.info.getPlotInfo(); // // here we tweak the notify flag on the plot so that only // // one notification happens even though we update multiple // // axes... // // boolean savedNotify = p.isNotify(); // // p.setNotify(false); // Movable z = (Movable) p; // if (z.getOrientation() == PlotOrientation.HORIZONTAL) { // z.moveDomainAxes(vMovePercent, info, source); // z.moveRangeAxes(hMovePercent, info, source); // } else { // z.moveDomainAxes(hMovePercent, info, source); // z.moveRangeAxes(vMovePercent, info, source); // } // // p.setNotify(savedNotify); // // // repaint // invalidate(); // } // // } // // /** // * Restores the auto-range calculation on both axes. // */ // public void restoreAutoBounds() { // Plot plot = this.chart.getPlot(); // if (plot == null) { // return; // } // // here we tweak the notify flag on the plot so that only // // one notification happens even though we update multiple // // axes... // // boolean savedNotify = plot.isNotify(); // // plot.setNotify(false); // restoreAutoDomainBounds(); // restoreAutoRangeBounds(); // // plot.setNotify(savedNotify); // } // // /** // * Restores the auto-range calculation on the domain axis. // */ // public void restoreAutoDomainBounds() { // Plot plot = this.chart.getPlot(); // if (plot instanceof Zoomable) { // Zoomable z = (Zoomable) plot; // // here we tweak the notify flag on the plot so that only // // one notification happens even though we update multiple // // axes... // // boolean savedNotify = plot.isNotify(); // // plot.setNotify(false); // // we need to guard against this.zoomPoint being null // PointF zp = (this.zoomPoint != null ? this.zoomPoint : new PointF()); // z.zoomDomainAxes(0.0, this.info.getPlotInfo(), zp); // // plot.setNotify(savedNotify); // } // } // // /** // * Restores the auto-range calculation on the range axis. // */ // public void restoreAutoRangeBounds() { // Plot plot = this.chart.getPlot(); // if (plot instanceof Zoomable) { // Zoomable z = (Zoomable) plot; // // here we tweak the notify flag on the plot so that only // // one notification happens even though we update multiple // // axes... // // boolean savedNotify = plot.isNotify(); // // plot.setNotify(false); // // we need to guard against this.zoomPoint being null // PointF zp = (this.zoomPoint != null ? this.zoomPoint : new PointF()); // z.zoomRangeAxes(0.0, this.info.getPlotInfo(), zp); // // plot.setNotify(savedNotify); // } // } // // protected void onSizeChanged( int w, int h, int oldw, int oldh ) { // this.insets = new RectangleInsets(0, 0, 0, 0); // this.size = new Dimension(w, h); // } // // private RectangleInsets getInsets() { // return this.insets; // } // // /** // * Returns the X scale factor for the chart. This will be 1.0 if no // * scaling has been used. // * // * @return The scale factor. // */ // public double getChartScaleX() { // return this.scaleX; // } // // /** // * Returns the Y scale factory for the chart. This will be 1.0 if no // * scaling has been used. // * // * @return The scale factor. // */ // public double getChartScaleY() { // return this.scaleY; // } // // /** // * Sets the chart that is displayed in the panel. // * // * @param chart the chart (<code>null</code> permitted). // */ // public void setChart( AFreeChart chart ) { // // // stop listening for changes to the existing chart // if (this.chart != null) { // this.chart.removeChangeListener(this); // this.chart.removeProgressListener(this); // } // // // add the new chart // this.chart = chart; // if (chart != null) { // this.chart.addChangeListener(this); // this.chart.addProgressListener(this); // Plot plot = chart.getPlot(); // if (plot instanceof Zoomable) { // Zoomable z = (Zoomable) plot; // z.isRangeZoomable(); // this.orientation = z.getOrientation(); // } // // this.domainMovable = false; // this.rangeMovable = false; // if (plot instanceof Movable) { // Movable z = (Movable) plot; // this.domainMovable = z.isDomainMovable(); // this.rangeMovable = z.isRangeMovable(); // this.orientation = z.getOrientation(); // } // } else { // this.domainMovable = false; // this.rangeMovable = false; // } // // if (this.useBuffer) { // // this.refreshBuffer = true; // // } // repaint(); // // } // // /** // * Returns the minimum drawing width for charts. // * <P> // * If the width available on the panel is less than this, then the chart is // * drawn at the minimum width then scaled down to fit. // * // * @return The minimum drawing width. // */ // public int getMinimumDrawWidth() { // return this.minimumDrawWidth; // } // // /** // * Sets the minimum drawing width for the chart on this panel. // * <P> // * At the time the chart is drawn on the panel, if the available width is // * less than this amount, the chart will be drawn using the minimum width // * then scaled down to fit the available space. // * // * @param width The width. // */ // public void setMinimumDrawWidth( int width ) { // this.minimumDrawWidth = width; // } // // /** // * Returns the maximum drawing width for charts. // * <P> // * If the width available on the panel is greater than this, then the chart // * is drawn at the maximum width then scaled up to fit. // * // * @return The maximum drawing width. // */ // public int getMaximumDrawWidth() { // return this.maximumDrawWidth; // } // // /** // * Sets the maximum drawing width for the chart on this panel. // * <P> // * At the time the chart is drawn on the panel, if the available width is // * greater than this amount, the chart will be drawn using the maximum // * width then scaled up to fit the available space. // * // * @param width The width. // */ // public void setMaximumDrawWidth( int width ) { // this.maximumDrawWidth = width; // } // // /** // * Returns the minimum drawing height for charts. // * <P> // * If the height available on the panel is less than this, then the chart // * is drawn at the minimum height then scaled down to fit. // * // * @return The minimum drawing height. // */ // public int getMinimumDrawHeight() { // return this.minimumDrawHeight; // } // // /** // * Sets the minimum drawing height for the chart on this panel. // * <P> // * At the time the chart is drawn on the panel, if the available height is // * less than this amount, the chart will be drawn using the minimum height // * then scaled down to fit the available space. // * // * @param height The height. // */ // public void setMinimumDrawHeight( int height ) { // this.minimumDrawHeight = height; // } // // /** // * Returns the maximum drawing height for charts. // * <P> // * If the height available on the panel is greater than this, then the // * chart is drawn at the maximum height then scaled up to fit. // * // * @return The maximum drawing height. // */ // public int getMaximumDrawHeight() { // return this.maximumDrawHeight; // } // // /** // * Sets the maximum drawing height for the chart on this panel. // * <P> // * At the time the chart is drawn on the panel, if the available height is // * greater than this amount, the chart will be drawn using the maximum // * height then scaled up to fit the available space. // * // * @param height The height. // */ // public void setMaximumDrawHeight( int height ) { // this.maximumDrawHeight = height; // } // // /** // * Returns the chart rendering info from the most recent chart redraw. // * // * @return The chart rendering info. // */ // public ChartRenderingInfo getChartRenderingInfo() { // return this.info; // } // // protected void onDraw( Canvas canvas ) { // super.onDraw(canvas); // // // inertialMove(); // // paintComponent(canvas); // } // // @Override // protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); // } // // /** // * Paints the component by drawing the chart to fill the entire component, // * but allowing for the insets (which will be non-zero if a border has been // * set for this component). To increase performance (at the expense of // * memory), an off-screen buffer image can be used. // * // * @param canvas the graphics device for drawing on. // */ // public void paintComponent( Canvas canvas ) { // // // first determine the size of the chart rendering area... // Dimension size = getSize(); // RectangleInsets insets = getInsets(); // RectShape available = new RectShape(insets.getLeft(), insets.getTop(), size.getWidth() - insets.getLeft() // - insets.getRight(), size.getHeight() - insets.getTop() - insets.getBottom()); // // double drawWidth = available.getWidth(); // double drawHeight = available.getHeight(); // this.scaleX = 1.0; // this.scaleY = 1.0; // // if (drawWidth < this.minimumDrawWidth) { // this.scaleX = drawWidth / this.minimumDrawWidth; // drawWidth = this.minimumDrawWidth; // } else if (drawWidth > this.maximumDrawWidth) { // this.scaleX = drawWidth / this.maximumDrawWidth; // drawWidth = this.maximumDrawWidth; // } // // if (drawHeight < this.minimumDrawHeight) { // this.scaleY = drawHeight / this.minimumDrawHeight; // drawHeight = this.minimumDrawHeight; // } else if (drawHeight > this.maximumDrawHeight) { // this.scaleY = drawHeight / this.maximumDrawHeight; // drawHeight = this.maximumDrawHeight; // } // // RectShape chartArea = new RectShape(0.0, 0.0, drawWidth, drawHeight); // // // are we using the chart buffer? // // if (this.useBuffer) { // // // // // do we need to resize the buffer? // // if ((this.chartBuffer == null) // // || (this.chartBufferWidth != available.getWidth()) // // || (this.chartBufferHeight != available.getHeight())) { // // this.chartBufferWidth = (int) available.getWidth(); // // this.chartBufferHeight = (int) available.getHeight(); // // GraphicsConfiguration gc = canvas.getDeviceConfiguration(); // // this.chartBuffer = gc.createCompatibleImage( // // this.chartBufferWidth, this.chartBufferHeight, // // Transparency.TRANSLUCENT); // // this.refreshBuffer = true; // // } // // // // // do we need to redraw the buffer? // // if (this.refreshBuffer) { // // // // this.refreshBuffer = false; // clear the flag // // // // RectShape bufferArea = new RectShape( // // 0, 0, this.chartBufferWidth, this.chartBufferHeight); // // // // Graphics2D bufferG2 = (Graphics2D) // // this.chartBuffer.getGraphics(); // // RectShape r = new RectShape(0, 0, this.chartBufferWidth, // // this.chartBufferHeight); // // bufferG2.setPaint(getBackground()); // // bufferG2.fill(r); // // if (scale) { // // AffineTransform saved = bufferG2.getTransform(); // // AffineTransform st = AffineTransform.getScaleInstance( // // this.scaleX, this.scaleY); // // bufferG2.transform(st); // // this.chart.draw(bufferG2, chartArea, this.anchor, // // this.info); // // bufferG2.setTransform(saved); // // } // // else { // // this.chart.draw(bufferG2, bufferArea, this.anchor, // // this.info); // // } // // // // } // // // // // zap the buffer onto the panel... // // canvas.drawImage(this.chartBuffer, insets.left, insets.top, this); // // // // } // // // TODO:AffineTransform // // or redrawing the chart every time... // // else { // // // AffineTransform saved = canvas.getTransform(); // // canvas.translate(insets.left, insets.top); // // if (scale) { // // AffineTransform st = AffineTransform.getScaleInstance( // // this.scaleX, this.scaleY); // // canvas.transform(st); // // } // // this.chart.draw(canvas, chartArea, this.anchor, this.info); // // canvas.setTransform(saved); // // // } // this.chart.draw(canvas, chartArea, this.anchor, this.info); // // // Iterator iterator = this.overlays.iterator(); // // while (iterator.hasNext()) { // // Overlay overlay = (Overlay) iterator.next(); // // overlay.paintOverlay(canvas, this); // // } // // // redraw the zoom RectShape (if present) - if useBuffer is false, // // we use XOR so we can XOR the RectShape away again without redrawing // // the chart // // drawZoomRectShape(canvas, !this.useBuffer); // // // canvas.dispose(); // // this.anchor = null; // // this.verticalTraceLine = null; // // this.horizontalTraceLine = null; // // } // // public Dimension getSize() { // return this.size; // } // // /** // * Returns the anchor point. // * // * @return The anchor point (possibly <code>null</code>). // */ // public PointF getAnchor() { // return this.anchor; // } // // public ChartRenderingInfo getInfo() { // return info; // } // // /** // * Sets the anchor point. This method is provided for the use of // * subclasses, not end users. // * // * @param anchor the anchor point (<code>null</code> permitted). // */ // protected void setAnchor( PointF anchor ) { // this.anchor = anchor; // } // // /** // * Information for multi touch start // * @author ikeda // * // */ // private class MultiTouchStartInfo { // private double distance = 0; // // public double getDistance() { // return distance; // } // public void setDistance( double distance ) { // this.distance = distance; // } // } // // private MultiTouchStartInfo multiTouchStartInfo = null; // // /** // * Information for Single touch start // * @author ikeda // * // */ // private class SingleTouchStartInfo { // private double x = 0; // private double y = 0; // // public double getX() { // return x; // } // public void setX( double x ) { // this.x = x; // } // public double getY() { // return y; // } // public void setY( double y ) { // this.y = y; // } // } // // private SingleTouchStartInfo singleTouchStartInfo = null; // // private double xMin; // private double xMax; // private double yMin; // private double yMax; // private double xMinAll; // private double xMaxAll; // private double yMinAll; // private double yMaxAll; // // /** // * Zoom // * @param ev // */ // private void zoomAdjustment( MotionEvent ev ) { // PointF point = new PointF((ev.getX(0) + ev.getX(1)) / 2, (ev.getY(0) + ev.getY(1)) / 2); // // end distance // double endDistance = Math.sqrt(Math.pow(ev.getX(0) - ev.getX(1), 2) + Math.pow(ev.getY(0) - ev.getY(1), 2)); // // // zoom process // zoom(point, this.multiTouchStartInfo.getDistance(), endDistance); // // // reset start point // setMultiTouchStartInfo(ev); // } // // /** // * zoom // * @param startDistance // * @param endDistance // */ // private void zoom( PointF source, double startDistance, double endDistance ) { // // Plot plot = this.chart.getPlot(); // PlotRenderingInfo info = this.info.getPlotInfo(); // // if (plot instanceof Zoomable) { // float scaleDistance = (float) (startDistance / endDistance); // // if (this.mScale * scaleDistance < 10.0f && this.mScale * scaleDistance > 0.1f) { // this.mScale *= scaleDistance; // Zoomable z = (Zoomable) plot; // z.zoomDomainAxes(scaleDistance, info, source, false); // z.zoomRangeAxes(scaleDistance, info, source, false); // } // } // // // repaint // invalidate(); // } // // // inertialmove has been disabled to avoid infinite panning // @SuppressWarnings("unused") // private void inertialMove() { // if (inertialMovedFlag == true) { // RectShape dataArea = this.info.getPlotInfo().getDataArea(); // // accelX *= friction; // accelY *= friction; // // double dataAreaWidth = dataArea.getWidth(); // double dataAreaHeight = dataArea.getHeight(); // // if (lastTouch != null) { // move(lastTouch, accelX, accelY, dataAreaWidth, dataAreaHeight); // } // // if (accelX < 0.1 && accelX > -0.1) { // accelX = 0; // } // // if (accelY < 0.1 && accelY > -0.1) { // accelY = 0; // } // // if (accelX == 0 && accelY == 0) { // inertialMovedFlag = false; // } // } // } // /** // * Receives notification of touch on the panel. These are // * translated and passed on to any registered {@link ChartTouchListener}s. // * // * @param event Information fragment_about the touch event. // */ // public void touched( MotionEvent event ) { // // int x = (int) (event.getX() / this.scaleX); // int y = (int) (event.getY() / this.scaleY); // // this.anchor = new PointF(x, y); // if (this.chart == null) { // return; // } // this.chart.setNotify(true); // force a redraw // // chart.handleClick((int) event.getX(), (int) event.getY(), info); // inertialMovedFlag = false; // // // new entity code... // if (this.chartMotionListeners.size() == 0) { // return; // } // // ChartEntity entity = null; // if (this.info != null) { // EntityCollection entities = this.info.getEntityCollection(); // if (entities != null) { // entity = entities.getEntity(x, y); // } // } // ChartTouchEvent chartEvent = new ChartTouchEvent(getChart(), event, entity); // for( int i = chartMotionListeners.size() - 1; i >= 0; i-- ) { // this.chartMotionListeners.get(i).chartTouched(chartEvent); // } // // } // // /** // * Returns the chart contained in the panel. // * // * @return The chart (possibly <code>null</code>). // */ // public AFreeChart getChart() { // return this.chart; // } // // /** // * Adds a listener to the list of objects listening for chart touch events. // * // * @param listener the listener (<code>null</code> not permitted). // */ // public void addChartTouchListener( ChartTouchListener listener ) { // if (listener == null) { // throw new IllegalArgumentException("Null 'listener' argument."); //$NON-NLS-1$ // } // this.chartMotionListeners.add(listener); // } // // /** // * Removes a listener from the list of objects listening for chart touch // * events. // * // * @param listener the listener. // */ // public void removeChartTouchListener( ChartTouchListener listener ) { // this.chartMotionListeners.remove(listener); // } // // /** // * Returns an array of the listeners of the given type registered with the // * panel. // * // * @param listenerType the listener type. // * // * @return An array of listeners. // */ // public EventListener[] getListeners() { // return this.chartMotionListeners.toArray(new ChartTouchListener[0]); // } // // /** // * Schedule a user interface repaint. // */ // public void repaint() { // mHandler.post(new Runnable(){ // public void run() { // invalidate(); // } // }); // } // // /** // * Receives notification of changes to the chart, and redraws the chart. // * // * @param event details of the chart change event. // */ // public void chartChanged( ChartChangeEvent event ) { // // this.refreshBuffer = true; // Plot plot = this.chart.getPlot(); // if (plot instanceof Zoomable) { // Zoomable z = (Zoomable) plot; // this.orientation = z.getOrientation(); // } // repaint(); // } // // /** // * Receives notification of a chart progress event. // * // * @param event the event. // */ // public void chartProgress( ChartProgressEvent event ) { // // does nothing - override if necessary // } // // public void clearMarkers() { // Plot plot = chart.getPlot(); // if (plot instanceof XYPlot) { // XYPlot xyPlot = (XYPlot) plot; // Collection< ? > domainMarkers = xyPlot.getDomainMarkers(Layer.BACKGROUND); // if (domainMarkers != null) { // Iterator< ? > iterator = domainMarkers.iterator(); // // store the keys in a list first to escape a ConcurrentModificationException // List<Marker> tmpMarkers = new ArrayList<Marker>(); // while( iterator.hasNext() ) { // Marker marker = (Marker) iterator.next(); // tmpMarkers.add(marker); // } // // now remove them // for( Marker marker : tmpMarkers ) { // xyPlot.removeDomainMarker(marker, Layer.BACKGROUND); // } // // invalidate(); // } // } // } // // public void zoomToSelection( double xMin2, double xMax2, double yMin2, double yMax2 ) { // XYPlot plot = (XYPlot) chart.getPlot(); // // xMin = xMin2; // xMax = xMax2; // // NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis(); // domainAxis.setRange(xMin, xMax); // // if (!Double.isNaN(yMin2) && !Double.isNaN(yMax2)) { // yMin = yMin2; // yMax = yMax2; // ValueAxis valueAxis = plot.getRangeAxis(); // valueAxis.setRange(yMin, yMax); // } // invalidate(); // } // // // public boolean onTouchEvent( MotionEvent ev ) { // // super.onTouchEvent(ev); // // int action = ev.getAction(); // // switch( action & MotionEvent.ACTION_MASK ) { // // case MotionEvent.ACTION_DOWN: // // case MotionEvent.ACTION_POINTER_DOWN: // // case MotionEvent.ACTION_MOVE: // // break; // // case MotionEvent.ACTION_UP: // // case MotionEvent.ACTION_POINTER_UP: // // Plot plot = chart.getPlot(); // // if (plot instanceof XYPlot) { // // double xValue = -1; // // double yValue = -1; // // XYPlot xyPlot = (XYPlot) plot; // // int x = (int) (ev.getX() / this.scaleX); // // int y = (int) (ev.getY() / this.scaleY); // // PlotRenderingInfo plotInfo = info.getPlotInfo(); // // RectShape dataArea = plotInfo.getDataArea(); // // if (dataArea.contains(x, y)) { // // ValueAxis xaxis = xyPlot.getDomainAxis(); // // if (xaxis != null) { // // xValue = xaxis.java2DToValue(x, plotInfo.getDataArea(), xyPlot.getDomainAxisEdge()); // // } // // ValueAxis yaxis = xyPlot.getRangeAxis(); // // if (yaxis != null) { // // yValue = yaxis.java2DToValue(y, plotInfo.getDataArea(), xyPlot.getRangeAxisEdge()); // // } // // } // // final double fxValue = xValue; // // final double fyValue = yValue; // // new AsyncTask<String, Void, String>(){ // // protected String doInBackground( String... params ) { // // return ""; // // } // // @SuppressWarnings("nls") // // protected void onPostExecute( String response ) { // on UI thread! // // Log.i("TIMESERIDEMO", fxValue + "/" + fyValue); // // Toast.makeText(getContext(), fxValue + "/" + fyValue, Toast.LENGTH_LONG); // // } // // }.execute((String) null); // // } // // break; // // default: // // break; // // } // // return true; // // } //}