I'm considered a newbie in android programming, this is only my second application and i'm learning things as they come. So if there are obvious oversights, bear with me.
As a part of a larger application I'm trying to implement a graph page using AndroidPlot. For now I'm using manually input values for the graph as i'm only testing. I used the tutorial on the AndroidPlot website in order to implements zoom and pan in my graph page. However anytime a touch event occurs, on the emulator and on the actual phone.
Here is the code for the graph page:
public class Graph extends Activity implements OnTouchListener{
Campaign_Db myCamp = new Campaign_Db(this);
private XYPlot myXY;
private PointF minXY;
private PointF maxXY;
ArrayList<String> array_date;
ArrayList<Integer> array_cap;
Array arr_date;
Integer[] arr_cap;
float x,y;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.graph);
myXY = (XYPlot) findViewById(R.id.myXYplot);
myXY.setOnTouchListener(this);
getdata();
// Create a couple arrays of y-values to plot:
Number[] series1Numbers = {978307200, // 2001
1009843200, // 2002
1041379200, // 2003
1072915200, // 2004
1104537600 // 2005
};
Number[] series2 = {1,2,3,4,5};
// Turn the above arrays into XYSeries':
XYSeries series1 = new SimpleXYSeries(
Arrays.asList(series1Numbers),
Arrays.asList(series2),
"cups of water");
// Create a formatter to use for drawing a series using LineAndPointRenderer:
@SuppressWarnings("deprecation")
LineAndPointFormatter series1Format = new LineAndPointFormatter(
Color.rgb(0, 200, 0), // line color
Color.rgb(0, 100, 0), // point color
null); // fill color (none)
// add a new series' to the xyplot:
myXY.addSeries(series1, series1Format);
// reduce the number of range labels
myXY.setTicksPerRangeLabel(1);
myXY.setTicksPerDomainLabel(2);
// get rid of decimal points in our range labels:
myXY.setRangeValueFormat(new DecimalFormat("0"));
// customize our domain/range labels
myXY.setDomainLabel("Date");
myXY.setRangeLabel("# of cups");
myXY.setDomainValueFormat(new Format() {
/**
*
*/
private static final long serialVersionUID = 1L;
// create a simple date format that draws on the year portion of our timestamp.
// see http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
// for a full description of SimpleDateFormat.
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");
@Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
// because our timestamps are in seconds and SimpleDateFormat expects milliseconds
// we multiply our timestamp by 1000:
long timestamp = ((Number) obj).longValue() * 1000;
Date date = new Date(timestamp);
return dateFormat.format(date, toAppendTo, pos);
}
@Override
public Object parseObject(String string, ParsePosition position) {
// TODO Auto-generated method stub
return null;
}
});
// by default, AndroidPlot displays developer guides to aid in laying out your plot.
// To get rid of them call disableAllMarkup():
myXY.disableAllMarkup();
myXY.redraw();
//Set of internal variables for keeping track of the boundaries
myXY.calculateMinMaxVals();
minXY=new PointF(myXY.getCalculatedMinX().floatValue(),myXY.getCalculatedMinY().floatValue());
maxXY=new PointF(myXY.getCalculatedMaxX().floatValue(),myXY.getCalculatedMaxY().floatValue());
}
// Definition of the touch states
static final int NONE = 0;
static final int ONE_FINGER_DRAG = 1;
static final int TWO_FINGERS_DRAG = 2;
int mode = NONE;
PointF firstFinger;
float lastScrolling;
float distBetweenFingers;
float lastZooming;
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: // Start gesture
firstFinger = new PointF(event.getX(), event.getY());
mode = ONE_FINGER_DRAG;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
//When the gesture ends, a thread is created to give inertia to the scrolling and zoom
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
while(Math.abs(lastScrolling)>1f || Math.abs(lastZooming-1)<1.01){
lastScrolling*=.8;
scroll(lastScrolling);
lastZooming+=(1-lastZooming)*.2;
zoom(lastZooming);
myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
myXY.redraw();
}
}
}, 0);
case MotionEvent.ACTION_POINTER_DOWN: // second finger
distBetweenFingers = spacing(event);
// the distance check is done to avoid false alarms
if (distBetweenFingers > 5f) {
mode = TWO_FINGERS_DRAG;
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == ONE_FINGER_DRAG) {
PointF oldFirstFinger=firstFinger;
firstFinger=new PointF(event.getX(), event.getY());
lastScrolling=oldFirstFinger.x-firstFinger.x;
scroll(lastScrolling);
lastZooming=(firstFinger.y-oldFirstFinger.y)/myXY.getHeight();
if (lastZooming<0)
lastZooming=1/(1-lastZooming);
else
lastZooming+=1;
zoom(lastZooming);
myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
myXY.redraw();
} else if (mode == TWO_FINGERS_DRAG) {
float oldDist =distBetweenFingers;
distBetweenFingers=spacing(event);
lastZooming=oldDist/distBetweenFingers;
zoom(lastZooming);
myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
myXY.redraw();
}
break;
}
return true;
}
private void zoom(float scale) {
float domainSpan = maxXY.x - minXY.x;
float domainMidPoint = maxXY.x - domainSpan / 2.0f;
float offset = domainSpan * scale / 2.0f;
minXY.x=domainMidPoint- offset;
maxXY.x=domainMidPoint+offset;
}
private void scroll(float pan) {
float domainSpan = maxXY.x - minXY.x;
float step = domainSpan / myXY.getWidth();
float offset = pan * step;
minXY.x+= offset;
maxXY.x+= offset;
}
private float spacing(MotionEvent event) {
x = event.getX(0) - event.getX(1);
y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
return false;
}
}
}
And here is the logcat for the error
06-11 14:59:31.764: E/AndroidRuntime(2203): FATAL EXCEPTION: main
06-11 14:59:31.764: E/AndroidRuntime(2203): java.lang.IllegalArgumentException: pointerIndex out of range
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.MotionEvent.nativeGetAxisValue(Native Method)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.MotionEvent.getX(MotionEvent.java:1974)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.example.damavand.Graph.spacing(Graph.java:231)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.example.damavand.Graph.onTouch(Graph.java:176)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.View.dispatchTouchEvent(View.java:5559)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1931)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1390)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.app.Activity.dispatchTouchEvent(Activity.java:2364)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1879)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.View.dispatchPointerEvent(View.java:5766)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:2890)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2466)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:845)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2475)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.os.Handler.dispatchMessage(Handler.java:99)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.os.Looper.loop(Looper.java:137)
06-11 14:59:31.764: E/AndroidRuntime(2203): at android.app.ActivityThread.main(ActivityThread.java:4441)
06-11 14:59:31.764: E/AndroidRuntime(2203): at java.lang.reflect.Method.invokeNative(Native Method)
06-11 14:59:31.764: E/AndroidRuntime(2203): at java.lang.reflect.Method.invoke(Method.java:511)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
06-11 14:59:31.764: E/AndroidRuntime(2203): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
06-11 14:59:31.764: E/AndroidRuntime(2203): at dalvik.system.NativeStart.main(Native Method)
I have been reading around and nothing have been helpful. This might be because I am horrible when it comes to motion events and because of that I might have missed on probable solutions. Thanks in advance for any help or guidance.
Alright I decided to go about this another way and use a custom-built zoom and pan function made by Marcin Lepicki who had been kind enough to share his work. His way of approching the zoom function is much easier to follow and also tidier as long as coding is considering.
Here is the link to his code for anyone else who might be facing the same issue or looking to work with AndroidPlot
AndroidPlot multitouch zoom & scroll
Hope this has been helpful.