1 | /* |
2 | Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/ |
3 | |
4 | This program is free software; |
5 | you can redistribute it and/or modify it under the terms of the |
6 | GNU General Public License as published by the Free Software Foundation; |
7 | either version 3 of the License, or any later version. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | /* |
19 | Changes: |
20 | - v4.0.0: |
21 | - created from v3.6.0 |
22 | Doc reviewed 202208 |
23 | */ |
24 | |
25 | import theGeometry from '../../core/lib/Geometry.js'; |
26 | import theConfig from '../../data/Config.js'; |
27 | import theTravelNotesData from '../../data/TravelNotesData.js'; |
28 | import { ZERO, ONE, TWO } from '../../main/Constants.js'; |
29 | |
30 | import { LeafletPoint } from '../../leaflet/LeafletImports.js'; |
31 | |
32 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
33 | /** |
34 | touch event listener on the background |
35 | */ |
36 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
37 | |
38 | class BackgroundTouchEL { |
39 | |
40 | /** |
41 | A reference to the dialog |
42 | @type {BaseDialog} |
43 | */ |
44 | |
45 | #baseDialog; |
46 | |
47 | /** |
48 | A flag set to true when a pan is ongoing |
49 | @type {Boolean} |
50 | */ |
51 | |
52 | #panOngoing = false; |
53 | |
54 | /** |
55 | A flag set to true when a zoom is ongoing |
56 | @type {Boolean} |
57 | */ |
58 | |
59 | #zoomOngoing = false; |
60 | |
61 | /** |
62 | The X screen coordinate of the beginning of the pan |
63 | @type {Number} |
64 | */ |
65 | |
66 | #startPanX = ZERO; |
67 | |
68 | /** |
69 | The Y screen coordinate of the beginning of the pan |
70 | @type {Number} |
71 | */ |
72 | |
73 | #startPanY = ZERO; |
74 | |
75 | /** |
76 | A leaflet LatLng object with the center of the map |
77 | @type {LeafletObject} |
78 | */ |
79 | |
80 | #mapCenter; |
81 | |
82 | /** |
83 | The zoom when the touchstart event is trigered |
84 | @type {Number} |
85 | */ |
86 | |
87 | #initialZoom; |
88 | |
89 | /** |
90 | The distance in pixel betwwen the touches when the touchstart event is trigered |
91 | @type {Number} |
92 | */ |
93 | |
94 | #initialZoomDistance; |
95 | |
96 | /** |
97 | the point on the screen around witch thz zoom is performed |
98 | @type {LeafletObject} |
99 | */ |
100 | |
101 | #aroundPoint; |
102 | |
103 | /** |
104 | Execute the pan when a touchmove or toucheend event occurs after a touchestart event |
105 | @param {Touch} touch The touch object to process |
106 | */ |
107 | |
108 | #processPan ( touch ) { |
109 | if ( |
110 | this.#panOngoing |
111 | && |
112 | ( this.#startPanX !== touch.screenX || this.#startPanY !== touch.screenY ) |
113 | ) { |
114 | if ( |
115 | theConfig.baseDialog.cancelTouchY > this.#startPanY |
116 | && |
117 | touch.screenY < this.#startPanY |
118 | && |
119 | theConfig.baseDialog.cancelTouchX > this.#startPanX ) { |
120 | this.#baseDialog.onCancel ( ); |
121 | } |
122 | const latLngAtStart = theGeometry.screenCoordToLatLng ( this.#startPanX, this.#startPanY ); |
123 | const latLngAtEnd = theGeometry.screenCoordToLatLng ( touch.screenX, touch.screenY ); |
124 | theTravelNotesData.map.panTo ( |
125 | [ |
126 | this.#mapCenter.lat + |
127 | latLngAtStart [ ZERO ] - |
128 | latLngAtEnd [ ZERO ], |
129 | this.#mapCenter.lng + |
130 | latLngAtStart [ ONE ] - |
131 | latLngAtEnd [ ONE ] |
132 | ] |
133 | ); |
134 | } |
135 | } |
136 | |
137 | /** |
138 | Execute the zoom when a touchmove or toucheend event occurs after a touchestart event |
139 | @param {TouchList} targetTouches The touch objects to process |
140 | */ |
141 | |
142 | #processZoom ( targetTouches ) { |
143 | let zoomDistance = Math.sqrt ( |
144 | ( ( targetTouches.item ( ZERO ).clientX - targetTouches.item ( ONE ).clientX ) ** TWO ) |
145 | + |
146 | ( ( targetTouches.item ( ZERO ).clientY - targetTouches.item ( ONE ).clientY ) ** TWO ) |
147 | ); |
148 | let zoom = this.#initialZoom; |
149 | let deltaZoom = zoomDistance - this.#initialZoomDistance; |
150 | if ( theConfig.baseDialog.deltaZoomDistance < deltaZoom ) { |
151 | zoom ++; |
152 | } |
153 | else if ( -theConfig.baseDialog.deltaZoomDistance > deltaZoom ) { |
154 | zoom --; |
155 | } |
156 | |
157 | zoom = Math.min ( theTravelNotesData.map.getMaxZoom ( ), zoom ); |
158 | zoom = Math.max ( theTravelNotesData.map.getMinZoom ( ), zoom ); |
159 | if ( zoom !== this.#initialZoom ) { |
160 | theTravelNotesData.map.setZoomAround ( this.#aroundPoint, zoom ); |
161 | this.#initialZoom = zoom; |
162 | this.#initialZoomDistance = zoomDistance; |
163 | } |
164 | } |
165 | |
166 | /** |
167 | Handle the touchend event |
168 | @param {Event} touchEvent The event to handle |
169 | */ |
170 | |
171 | #handleEndEvent ( touchEvent ) { |
172 | if ( this.#panOngoing && ONE === touchEvent.changedTouches.length ) { |
173 | this.#processPan ( touchEvent.changedTouches.item ( ZERO ) ); |
174 | this.#panOngoing = false; |
175 | } |
176 | } |
177 | |
178 | /** |
179 | Handle the touchmove event |
180 | @param {Event} touchEvent The event to handle |
181 | */ |
182 | |
183 | #handleMoveEvent ( touchEvent ) { |
184 | if ( this.#panOngoing && ONE === touchEvent.changedTouches.length ) { |
185 | this.#processPan ( touchEvent.changedTouches.item ( ZERO ) ); |
186 | } |
187 | else if ( this.#zoomOngoing && TWO === touchEvent.targetTouches.length ) { |
188 | this.#processZoom ( touchEvent.targetTouches ); |
189 | } |
190 | } |
191 | |
192 | /** |
193 | Handle the touchstart event |
194 | @param {Event} touchEvent The event to handle |
195 | */ |
196 | |
197 | #handleStartEvent ( touchEvent ) { |
198 | if ( ONE === touchEvent.targetTouches.length ) { |
199 | const touch = touchEvent.changedTouches.item ( ZERO ); |
200 | this.#startPanX = touch.screenX; |
201 | this.#startPanY = touch.screenY; |
202 | this.#mapCenter = theTravelNotesData.map.getCenter ( ); |
203 | this.#panOngoing = true; |
204 | this.#zoomOngoing = false; |
205 | } |
206 | if ( TWO === touchEvent.targetTouches.length ) { |
207 | this.#initialZoom = theTravelNotesData.map.getZoom ( ); |
208 | this.#aroundPoint = new LeafletPoint ( |
209 | ( touchEvent.targetTouches.item ( ZERO ).clientX + touchEvent.targetTouches.item ( ONE ).clientX ) / TWO, |
210 | ( touchEvent.targetTouches.item ( ZERO ).clientY + touchEvent.targetTouches.item ( ONE ).clientY ) / TWO |
211 | ); |
212 | this.#initialZoomDistance = Math.sqrt ( |
213 | ( ( touchEvent.targetTouches.item ( ZERO ).clientX - touchEvent.targetTouches.item ( ONE ).clientX ) ** TWO ) |
214 | + |
215 | ( ( touchEvent.targetTouches.item ( ZERO ).clientY - touchEvent.targetTouches.item ( ONE ).clientY ) ** TWO ) |
216 | ); |
217 | this.#panOngoing = false; |
218 | this.#zoomOngoing = true; |
219 | } |
220 | } |
221 | |
222 | /** |
223 | The constructor |
224 | @param {BaseDialog} baseDialog A reference to the dialog |
225 | */ |
226 | |
227 | constructor ( baseDialog ) { |
228 | Object.freeze ( this ); |
229 | this.#baseDialog = baseDialog; |
230 | } |
231 | |
232 | /** |
233 | Event listener method |
234 | @param {Event} touchEvent The event to handle |
235 | */ |
236 | |
237 | handleEvent ( touchEvent ) { |
238 | |
239 | if ( touchEvent.currentTarget === touchEvent.target ) { |
240 | touchEvent.preventDefault ( ); |
241 | } |
242 | switch ( touchEvent.type ) { |
243 | case 'touchstart' : |
244 | if ( touchEvent.currentTarget === touchEvent.target ) { |
245 | this.#handleStartEvent ( touchEvent ); |
246 | } |
247 | break; |
248 | case 'touchmove' : |
249 | this.#handleMoveEvent ( touchEvent ); |
250 | break; |
251 | case 'touchend' : |
252 | this.#handleEndEvent ( touchEvent ); |
253 | break; |
254 | default : |
255 | break; |
256 | } |
257 | |
258 | } |
259 | } |
260 | |
261 | export default BackgroundTouchEL; |
262 | |
263 | /* --- End of file --------------------------------------------------------------------------------------------------------- */ |
264 |