• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
onCreate(Bundle savedInstanceState)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 
populateSeries(SimpleXYSeries series, int max)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
onTouch(View arg0, MotionEvent event)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 
zoom(float scale)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 
scroll(float pan)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 
clampToDomainBounds(float domainSpan)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 
spacing(MotionEvent event)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