create changelog entry
[debian/openrocket] / android-libraries / achartengine / src / org / achartengine / TouchHandler.java
1 /**\r
2  * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
3  *  \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *  \r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *  \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 package org.achartengine;\r
17 \r
18 import org.achartengine.chart.AbstractChart;\r
19 import org.achartengine.chart.RoundChart;\r
20 import org.achartengine.chart.XYChart;\r
21 import org.achartengine.renderer.DefaultRenderer;\r
22 import org.achartengine.tools.Pan;\r
23 import org.achartengine.tools.PanListener;\r
24 import org.achartengine.tools.Zoom;\r
25 import org.achartengine.tools.ZoomListener;\r
26 \r
27 import android.graphics.RectF;\r
28 import android.view.MotionEvent;\r
29 \r
30 /**\r
31  * The main handler of the touch events.\r
32  */\r
33 public class TouchHandler implements ITouchHandler {\r
34   /** The chart renderer. */\r
35   private DefaultRenderer mRenderer;\r
36   /** The old x coordinate. */\r
37   private float oldX;\r
38   /** The old y coordinate. */\r
39   private float oldY;\r
40   /** The old x2 coordinate. */\r
41   private float oldX2;\r
42   /** The old y2 coordinate. */\r
43   private float oldY2;\r
44   /** The zoom buttons rectangle. */\r
45   private RectF zoomR = new RectF();\r
46   /** The pan tool. */\r
47   private Pan mPan;\r
48   /** The zoom for the pinch gesture. */\r
49   private Zoom mPinchZoom;\r
50   /** The graphical view. */\r
51   private GraphicalView graphicalView;\r
52 \r
53   /**\r
54    * Creates a new graphical view.\r
55    * \r
56    * @param view the graphical view\r
57    * @param chart the chart to be drawn\r
58    */\r
59   public TouchHandler(GraphicalView view, AbstractChart chart) {\r
60     graphicalView = view;\r
61     zoomR = graphicalView.getZoomRectangle();\r
62     if (chart instanceof XYChart) {\r
63       mRenderer = ((XYChart) chart).getRenderer();\r
64     } else {\r
65       mRenderer = ((RoundChart) chart).getRenderer();\r
66     }\r
67     if (mRenderer.isPanEnabled()) {\r
68       mPan = new Pan(chart);\r
69     }\r
70     if (mRenderer.isZoomEnabled()) {\r
71       mPinchZoom = new Zoom(chart, true, 1);\r
72     }\r
73   }\r
74 \r
75   /**\r
76    * Handles the touch event.\r
77    * \r
78    * @param event the touch event\r
79    */\r
80   public boolean handleTouch(MotionEvent event) {\r
81     int action = event.getAction();\r
82     if (mRenderer != null && action == MotionEvent.ACTION_MOVE) {\r
83       if (oldX >= 0 || oldY >= 0) {\r
84         float newX = event.getX(0);\r
85         float newY = event.getY(0);\r
86         if (event.getPointerCount() > 1 && (oldX2 >= 0 || oldY2 >= 0) && mRenderer.isZoomEnabled()) {\r
87           float newX2 = event.getX(1);\r
88           float newY2 = event.getY(1);\r
89           float newDeltaX = Math.abs(newX - newX2);\r
90           float newDeltaY = Math.abs(newY - newY2);\r
91           float oldDeltaX = Math.abs(oldX - oldX2);\r
92           float oldDeltaY = Math.abs(oldY - oldY2);\r
93           float zoomRate = 1;\r
94 \r
95           float tan1 = Math.abs(newY - oldY) / Math.abs(newX - oldX);\r
96           float tan2 = Math.abs(newY2 - oldY2) / Math.abs(newX2 - oldX2);\r
97           if ( tan1 <= 0.577 && tan2 <= 0.577) {\r
98             // horizontal pinch zoom, |deltaY| / |deltaX| is [0 ~ 0.577], 0.577 is the approximate value of tan(Pi/6)\r
99             zoomRate = newDeltaX / oldDeltaX;\r
100             if (zoomRate > 0.909 && zoomRate < 1.1) {\r
101               mPinchZoom.setZoomRate(zoomRate);\r
102               mPinchZoom.apply(Zoom.ZOOM_AXIS_X);\r
103             }\r
104           } else if ( tan1 >= 1.732 && tan2 >= 1.732 ) {\r
105             // pinch zoom vertically, |deltaY| / |deltaX| is [1.732 ~ infinity], 1.732 is the approximate value of tan(Pi/3)\r
106             zoomRate = newDeltaY / oldDeltaY;\r
107             if (zoomRate > 0.909 && zoomRate < 1.1) {\r
108               mPinchZoom.setZoomRate(zoomRate);\r
109               mPinchZoom.apply(Zoom.ZOOM_AXIS_Y);\r
110             }\r
111           } else if ( (tan1 > 0.577 && tan1 < 1.732) && (tan2 > 0.577 && tan2 < 1.732) ){\r
112             // pinch zoom diagonally\r
113             if (Math.abs(newX - oldX) >= Math.abs(newY - oldY)) {\r
114               zoomRate = newDeltaX / oldDeltaX;\r
115             } else {\r
116               zoomRate = newDeltaY / oldDeltaY;\r
117             }\r
118             if (zoomRate > 0.909 && zoomRate < 1.1) {\r
119               mPinchZoom.setZoomRate(zoomRate);\r
120               mPinchZoom.apply(Zoom.ZOOM_AXIS_XY);\r
121             }\r
122           }\r
123           oldX2 = newX2;\r
124           oldY2 = newY2;\r
125         } else if (mRenderer.isPanEnabled()) {\r
126           mPan.apply(oldX, oldY, newX, newY);\r
127           oldX2 = 0;\r
128           oldY2 = 0;\r
129         }\r
130         oldX = newX;\r
131         oldY = newY;\r
132         graphicalView.repaint();\r
133         return true;\r
134       }\r
135     } else if (action == MotionEvent.ACTION_DOWN) {\r
136       oldX = event.getX(0);\r
137       oldY = event.getY(0);\r
138       if (mRenderer != null && mRenderer.isZoomEnabled() && zoomR.contains(oldX, oldY)) {\r
139         if (oldX < zoomR.left + zoomR.width() / 3) {\r
140           graphicalView.zoomIn();\r
141         } else if (oldX < zoomR.left + zoomR.width() * 2 / 3) {\r
142           graphicalView.zoomOut();\r
143         } else {\r
144           graphicalView.zoomReset();\r
145         }\r
146         return true;\r
147       }\r
148     } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {\r
149       oldX = 0;\r
150       oldY = 0;\r
151       oldX2 = 0;\r
152       oldY2 = 0;\r
153       if (action == MotionEvent.ACTION_POINTER_UP) {\r
154         oldX = -1;\r
155         oldY = -1;\r
156       }\r
157     }\r
158     return !mRenderer.isClickEnabled();\r
159   }\r
160 \r
161   /**\r
162    * Adds a new zoom listener.\r
163    * \r
164    * @param listener zoom listener\r
165    */\r
166   public void addZoomListener(ZoomListener listener) {\r
167     if (mPinchZoom != null) {\r
168       mPinchZoom.addZoomListener(listener);\r
169     }\r
170   }\r
171 \r
172   /**\r
173    * Removes a zoom listener.\r
174    * \r
175    * @param listener zoom listener\r
176    */\r
177   public void removeZoomListener(ZoomListener listener) {\r
178     if (mPinchZoom != null) {\r
179       mPinchZoom.removeZoomListener(listener);\r
180     }\r
181   }\r
182 \r
183   /**\r
184    * Adds a new pan listener.\r
185    * \r
186    * @param listener pan listener\r
187    */\r
188   public void addPanListener(PanListener listener) {\r
189     if (mPan != null) {\r
190       mPan.addPanListener(listener);\r
191     }\r
192   }\r
193 \r
194   /**\r
195    * Removes a pan listener.\r
196    * \r
197    * @param listener pan listener\r
198    */\r
199   public void removePanListener(PanListener listener) {\r
200     if (mPan != null) {\r
201       mPan.removePanListener(listener);\r
202     }\r
203   }\r
204 }