Home | History | Annotate | Download | only in demos
      1 /*
      2  * Copyright 2012 AndroidPlot.com
      3  *
      4  *    Licensed under the Apache License, Version 2.0 (the "License");
      5  *    you may not use this file except in compliance with the License.
      6  *    You may obtain a copy of the License at
      7  *
      8  *        http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  *    Unless required by applicable law or agreed to in writing, software
     11  *    distributed under the License is distributed on an "AS IS" BASIS,
     12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  *    See the License for the specific language governing permissions and
     14  *    limitations under the License.
     15  */
     16 
     17 package com.androidplot.demos;
     18 
     19 import java.text.DecimalFormat;
     20 import java.util.Random;
     21 
     22 import android.app.Activity;
     23 import android.graphics.Color;
     24 import android.graphics.Paint;
     25 import android.graphics.PointF;
     26 import android.os.Bundle;
     27 import android.view.MotionEvent;
     28 import android.view.View;
     29 import android.view.View.OnTouchListener;
     30 import android.widget.Button;
     31 
     32 import com.androidplot.Plot;
     33 import com.androidplot.xy.BoundaryMode;
     34 import com.androidplot.xy.LineAndPointFormatter;
     35 import com.androidplot.xy.SimpleXYSeries;
     36 import com.androidplot.xy.XYPlot;
     37 
     38 /***********************************
     39  * @author David Buezas (david.buezas at gmail.com)
     40  * Feel free to copy, modify and use the source as it fits you.
     41  * 09/27/2012 nfellows - updated for 0.5.1 and made a few simplifications
     42  */
     43 public class TouchZoomExampleActivity extends Activity implements OnTouchListener {
     44     private static final int SERIES_SIZE = 200;
     45     private XYPlot mySimpleXYPlot;
     46     private Button resetButton;
     47     private SimpleXYSeries[] series = null;
     48     private PointF minXY;
     49     private PointF maxXY;
     50 
     51     public void onCreate(Bundle savedInstanceState) {
     52         super.onCreate(savedInstanceState);
     53         setContentView(R.layout.touch_zoom_example);
     54         resetButton = (Button) findViewById(R.id.resetButton);
     55         resetButton.setOnClickListener(new View.OnClickListener() {
     56             @Override
     57             public void onClick(View view) {
     58                 minXY.x = series[0].getX(0).floatValue();
     59                 maxXY.x = series[3].getX(series[3].size() - 1).floatValue();
     60                 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.FIXED);
     61 
     62                 // pre 0.5.1 users should use postRedraw() instead.
     63                 mySimpleXYPlot.redraw();
     64             }
     65         });
     66         mySimpleXYPlot = (XYPlot) findViewById(R.id.mySimpleXYPlot);
     67         mySimpleXYPlot.setOnTouchListener(this);
     68         mySimpleXYPlot.getGraphWidget().setTicksPerRangeLabel(2);
     69         mySimpleXYPlot.getGraphWidget().setTicksPerDomainLabel(2);
     70         mySimpleXYPlot.getGraphWidget().getBackgroundPaint().setColor(Color.TRANSPARENT);
     71         mySimpleXYPlot.getGraphWidget().setRangeValueFormat(
     72                 new DecimalFormat("#####"));
     73         mySimpleXYPlot.getGraphWidget().setDomainValueFormat(
     74                 new DecimalFormat("#####.#"));
     75         mySimpleXYPlot.getGraphWidget().setRangeLabelWidth(25);
     76         mySimpleXYPlot.setRangeLabel("");
     77         mySimpleXYPlot.setDomainLabel("");
     78 
     79         mySimpleXYPlot.setBorderStyle(Plot.BorderStyle.NONE, null, null);
     80         //mySimpleXYPlot.disableAllMarkup();
     81         series = new SimpleXYSeries[4];
     82         int scale = 1;
     83         for (int i = 0; i < 4; i++, scale *= 5) {
     84             series[i] = new SimpleXYSeries("S" + i);
     85             populateSeries(series[i], scale);
     86         }
     87         mySimpleXYPlot.addSeries(series[3],
     88                 new LineAndPointFormatter(Color.rgb(50, 0, 0), null,
     89                         Color.rgb(100, 0, 0), null));
     90         mySimpleXYPlot.addSeries(series[2],
     91                 new LineAndPointFormatter(Color.rgb(50, 50, 0), null,
     92                         Color.rgb(100, 100, 0), null));
     93         mySimpleXYPlot.addSeries(series[1],
     94                 new LineAndPointFormatter(Color.rgb(0, 50, 0), null,
     95                         Color.rgb(0, 100, 0), null));
     96         mySimpleXYPlot.addSeries(series[0],
     97                 new LineAndPointFormatter(Color.rgb(0, 0, 0), null,
     98                         Color.rgb(0, 0, 150), null));
     99         mySimpleXYPlot.redraw();
    100         mySimpleXYPlot.calculateMinMaxVals();
    101         minXY = new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),
    102                 mySimpleXYPlot.getCalculatedMinY().floatValue());
    103         maxXY = new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),
    104                 mySimpleXYPlot.getCalculatedMaxY().floatValue());
    105     }
    106 
    107     private void populateSeries(SimpleXYSeries series, int max) {
    108         Random r = new Random();
    109         for(int i = 0; i < SERIES_SIZE; i++) {
    110             series.addLast(i, r.nextInt(max));
    111         }
    112     }
    113 
    114     // Definition of the touch states
    115     static final int NONE = 0;
    116     static final int ONE_FINGER_DRAG = 1;
    117     static final int TWO_FINGERS_DRAG = 2;
    118     int mode = NONE;
    119 
    120     PointF firstFinger;
    121     float distBetweenFingers;
    122     boolean stopThread = false;
    123 
    124     @Override
    125     public boolean onTouch(View arg0, MotionEvent event) {
    126         switch (event.getAction() & MotionEvent.ACTION_MASK) {
    127             case MotionEvent.ACTION_DOWN: // Start gesture
    128                 firstFinger = new PointF(event.getX(), event.getY());
    129                 mode = ONE_FINGER_DRAG;
    130                 stopThread = true;
    131                 break;
    132             case MotionEvent.ACTION_UP:
    133             case MotionEvent.ACTION_POINTER_UP:
    134                 mode = NONE;
    135                 break;
    136             case MotionEvent.ACTION_POINTER_DOWN: // second finger
    137                 distBetweenFingers = spacing(event);
    138                 // the distance check is done to avoid false alarms
    139                 if (distBetweenFingers > 5f) {
    140                     mode = TWO_FINGERS_DRAG;
    141                 }
    142                 break;
    143             case MotionEvent.ACTION_MOVE:
    144                 if (mode == ONE_FINGER_DRAG) {
    145                     PointF oldFirstFinger = firstFinger;
    146                     firstFinger = new PointF(event.getX(), event.getY());
    147                     scroll(oldFirstFinger.x - firstFinger.x);
    148                     mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x,
    149                             BoundaryMode.FIXED);
    150                     mySimpleXYPlot.redraw();
    151 
    152                 } else if (mode == TWO_FINGERS_DRAG) {
    153                     float oldDist = distBetweenFingers;
    154                     distBetweenFingers = spacing(event);
    155                     zoom(oldDist / distBetweenFingers);
    156                     mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x,
    157                             BoundaryMode.FIXED);
    158                     mySimpleXYPlot.redraw();
    159                 }
    160                 break;
    161         }
    162         return true;
    163     }
    164 
    165     private void zoom(float scale) {
    166         float domainSpan = maxXY.x - minXY.x;
    167         float domainMidPoint = maxXY.x - domainSpan / 2.0f;
    168         float offset = domainSpan * scale / 2.0f;
    169 
    170         minXY.x = domainMidPoint - offset;
    171         maxXY.x = domainMidPoint + offset;
    172 
    173         minXY.x = Math.min(minXY.x, series[3].getX(series[3].size() - 3)
    174                 .floatValue());
    175         maxXY.x = Math.max(maxXY.x, series[0].getX(1).floatValue());
    176         clampToDomainBounds(domainSpan);
    177     }
    178 
    179     private void scroll(float pan) {
    180         float domainSpan = maxXY.x - minXY.x;
    181         float step = domainSpan / mySimpleXYPlot.getWidth();
    182         float offset = pan * step;
    183         minXY.x = minXY.x + offset;
    184         maxXY.x = maxXY.x + offset;
    185         clampToDomainBounds(domainSpan);
    186     }
    187 
    188     private void clampToDomainBounds(float domainSpan) {
    189         float leftBoundary = series[0].getX(0).floatValue();
    190         float rightBoundary = series[3].getX(series[3].size() - 1).floatValue();
    191         // enforce left scroll boundary:
    192         if (minXY.x < leftBoundary) {
    193             minXY.x = leftBoundary;
    194             maxXY.x = leftBoundary + domainSpan;
    195         } else if (maxXY.x > series[3].getX(series[3].size() - 1).floatValue()) {
    196             maxXY.x = rightBoundary;
    197             minXY.x = rightBoundary - domainSpan;
    198         }
    199     }
    200 
    201     private float spacing(MotionEvent event) {
    202         float x = event.getX(0) - event.getX(1);
    203         float y = event.getY(0) - event.getY(1);
    204         return (float) Math.hypot(x, y);
    205     }
    206 }
    207 
    208