Skip to content

Commit 6ca9207

Browse files
authored
Feat/location btn behavior (#130)
1 parent 7f6f051 commit 6ca9207

File tree

3 files changed

+158
-42
lines changed

3 files changed

+158
-42
lines changed

src/js/map-buttons-listeners.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ const addListeners = () => {
3333
// Rotation de la boussole
3434
DOM.$compassBtn.addEventListener("click", () => {
3535
const map = Globals.map;
36-
if (Location.isTrackingActive()){
37-
// De tracking a simple suivi de position
38-
Location.disableTracking();
39-
}
40-
if (map.getBearing() === 0) {
41-
DOM.$compassBtn.classList.add("d-none");
36+
if (Location.isNavigationActive()){
37+
// De nivigation a simple suivi de position
38+
Location.disableNavigation(0);
39+
} else {
40+
if (map.getBearing() === 0) {
41+
DOM.$compassBtn.classList.add("d-none");
42+
}
43+
map.rotateTo(0);
4244
}
43-
map.rotateTo(0);
4445
});
4546

4647
// Bouton Comparaison de carte

src/js/map-listeners.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,9 @@ const addListeners = () => {
2626
}
2727
});
2828

29-
let lastMapCenter = null;
3029
// Désactivation du tracking au déplacement non programmatique de la carte
3130
map.on("dragstart", () => {
32-
if (Location.isTrackingActive()){
33-
lastMapCenter = map.getCenter();
34-
}
35-
});
36-
map.on("dragend", () => {
37-
if (Location.isTrackingActive() && lastMapCenter){
38-
if (lastMapCenter.distanceTo(map.getCenter()) > 100) {
39-
// De tracking a simple suivi de position
40-
Location.disableTracking();
41-
}
42-
}
43-
lastMapCenter = null;
31+
Location.disableTracking();
4432
});
4533

4634
// l'event contextmenu n'est pas enclenché par clic long sur la carte... https://github.com/maplibre/maplibre-gl-js/issues/373

src/js/services/location.js

Lines changed: 149 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ let location_active = false;
7575

7676
// Suivi de la carte
7777
let tracking_active = false;
78+
79+
// Suivi de la carte avec boussole
80+
let navigation_active = false;
81+
7882
let watch_id;
7983
let currentPosition = null;
8084

@@ -97,6 +101,13 @@ let firstLocation;
97101
// Est-ce que le marqueur de "Ma Position" a un écouteur d'évènement ?
98102
let hasEventListener = false;
99103

104+
// Varaibles pour la gestion d'évènements touch et zoom spécifiques à la localisation activée
105+
let startDist = 0;
106+
let startZoom = 0;
107+
let startBearing =0;
108+
let startAngle = 0;
109+
let rotationEnabled = false;
110+
100111
/**
101112
* Interface pour les evenements
102113
* @example
@@ -186,6 +197,7 @@ const moveTo = (coords, zoom = Globals.map.getZoom(), panTo = true, gps = true)
186197
Globals.myPositionMarker = new maplibregl.Marker({
187198
element: (gps) ? positionIcon : Globals.searchResultIcon,
188199
anchor: (gps) ? "center" : "bottom",
200+
pitchAlignment: "map",
189201
})
190202
.setLngLat([coords.lon, coords.lat])
191203
.addTo(Globals.map);
@@ -216,11 +228,30 @@ const moveTo = (coords, zoom = Globals.map.getZoom(), panTo = true, gps = true)
216228

217229
if (panTo) {
218230
if (tracking_active) {
231+
let bearing = Globals.map.getBearing();
232+
let pitch = 0;
233+
let padding = 0;
234+
if (navigation_active) {
235+
bearing = -mapBearing;
236+
pitch = 45;
237+
padding = {top: DOM.$map.clientHeight * 0.5};
238+
}
219239
isMapPanning = true;
220-
Globals.map.flyTo({center: [coords.lon, coords.lat], zoom: zoom, bearing: -mapBearing, duration: 500});
240+
Globals.map.easeTo({
241+
center: [coords.lon, coords.lat],
242+
zoom: zoom,
243+
bearing: bearing,
244+
pitch: pitch,
245+
duration: 500,
246+
padding: padding,
247+
});
221248
Globals.map.once("moveend", () => {isMapPanning = false;});
222249
} else {
223-
Globals.map.flyTo({center: [coords.lon, coords.lat], zoom: zoom});
250+
Globals.map.flyTo({
251+
center: [coords.lon, coords.lat],
252+
zoom: zoom,
253+
pitch: 0
254+
});
224255
}
225256
}
226257
};
@@ -249,8 +280,8 @@ const watchPositionCallback = (position) => {
249280
currentPosition = position;
250281
localStorage.setItem("lastKnownPosition", JSON.stringify({lat: currentPosition.coords.latitude, lng: currentPosition.coords.longitude}));
251282
var zoom = Globals.map.getZoom();
252-
if (firstLocation || tracking_active) {
253-
zoom = Math.max(Globals.map.getZoom(), 16);
283+
if (firstLocation) {
284+
zoom = Math.max(Globals.map.getZoom(), 16.5);
254285
}
255286
moveTo({
256287
lat: position.coords.latitude,
@@ -262,11 +293,9 @@ const watchPositionCallback = (position) => {
262293
var padding;
263294
// gestion du mode paysage / écran large
264295
if (window.matchMedia("screen and (min-aspect-ratio: 1/1) and (min-width:400px)").matches) {
265-
var paddingLeft = parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--safe-area-inset-left").slice(0, -2)) +
266-
Math.min(window.innerHeight, window.innerWidth/2) + 42;
267-
padding = {top: 20, right: 20, bottom: 20, left: paddingLeft};
296+
padding = {top: 20, right: 20, bottom: 20, left: 20};
268297
} else {
269-
padding = {top: 80, right: 20, bottom: 120, left: 20};
298+
padding = {top: 80, right: 20, bottom: 40, left: 20};
270299
}
271300
Globals.map.fitBounds(bbox, {
272301
padding: padding
@@ -360,6 +389,7 @@ const enablePosition = async() => {
360389
return;
361390
}
362391
location_active = true;
392+
tracking_active = true;
363393
if (!currentPosition && localStorage.getItem("lastKnownPosition")) {
364394
const lastPosition = JSON.parse(localStorage.getItem("lastKnownPosition"));
365395
moveTo({
@@ -382,11 +412,32 @@ const locationOnOff = async () => {
382412
if (currentPosition === null) {
383413
return;
384414
}
385-
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationFollowImg + "\")";
415+
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationFixeImg + "\")";
386416
tracking_active = true;
417+
Globals.map.setPadding({top: 0, right: 0, bottom: 0, left: 0});
387418
Globals.map.setCenter([currentPosition.coords.longitude, currentPosition.coords.latitude]);
388-
Globals.map.setZoom(16);
389-
Globals.map.setBearing(-mapBearing);
419+
Globals.map.touchZoomRotate.disable();
420+
Globals.map.getCanvasContainer().addEventListener("touchstart", locationOnTouchStartHandler);
421+
Globals.map.getCanvasContainer().addEventListener("touchmove", locationOnTouchMoveHandler);
422+
Toast.show({
423+
text: "Suivi de position activé",
424+
duration: "short",
425+
position: "bottom"
426+
});
427+
} else if (!navigation_active) {
428+
if (currentPosition === null) {
429+
return;
430+
}
431+
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationFollowImg + "\")";
432+
navigation_active = true;
433+
Globals.map.setMaxPitch(45);
434+
const padding = {top: DOM.$map.clientHeight * 0.5};
435+
Globals.map.easeTo({
436+
center: [currentPosition.coords.longitude, currentPosition.coords.latitude],
437+
bearing: -mapBearing,
438+
pitch: 45,
439+
padding: padding,
440+
});
390441
DOM.$compassBtn.classList.remove("d-none");
391442
DOM.$compassBtn.style.transform = "rotate(" + mapBearing + "deg)";
392443
Toast.show({
@@ -395,14 +446,19 @@ const locationOnOff = async () => {
395446
position: "bottom"
396447
});
397448
} else {
449+
Globals.map.flyTo({
450+
pitch: 0,
451+
duration: 500,
452+
});
453+
setTimeout( () => {Globals.map.setMaxPitch(0);}, 500);
398454
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationImg + "\")";
399-
Geolocation.clearWatch({id: watch_id});
400-
clean();
401-
currentPosition = null;
402-
location_active = false;
403455
tracking_active = false;
456+
navigation_active = false;
457+
Globals.map.touchZoomRotate.enable();
458+
Globals.map.getCanvasContainer().removeEventListener("touchstart", locationOnTouchStartHandler);
459+
Globals.map.getCanvasContainer().removeEventListener("touchmove", locationOnTouchMoveHandler);
404460
Toast.show({
405-
text: "Navigation et suivi de position désactivés",
461+
text: "Navigation désactivée",
406462
duration: "short",
407463
position: "bottom"
408464
});
@@ -434,7 +490,7 @@ const getOrientation = async (event) => {
434490
tempMapBearing -= 90;
435491
}
436492
mapBearing = tempMapBearing;
437-
if (tracking_active) {
493+
if (navigation_active) {
438494
if (!isMapPanning) {
439495
Globals.map.easeTo({bearing: -mapBearing, duration: 100});
440496
}
@@ -491,13 +547,29 @@ const getLocation = async () => {
491547
};
492548

493549
const disableTracking = () => {
494-
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationFixeImg + "\")";
550+
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationImg + "\")";
495551
tracking_active = false;
496-
Toast.show({
497-
text: "Suivi de position activé",
498-
duration: "short",
499-
position: "bottom"
552+
if (navigation_active) {
553+
Globals.map.setMaxPitch(0);
554+
navigation_active = false;
555+
}
556+
Globals.map.touchZoomRotate.enable();
557+
Globals.map.getCanvasContainer().removeEventListener("touchstart", locationOnTouchStartHandler);
558+
Globals.map.getCanvasContainer().removeEventListener("touchmove", locationOnTouchMoveHandler);
559+
};
560+
561+
const disableNavigation = (bearing = Globals.map.getBearing()) => {
562+
DOM.$geolocateBtn.style.backgroundImage = "url(\"" + LocationFixeImg + "\")";
563+
navigation_active = false;
564+
Globals.map.flyTo({
565+
pitch: 0,
566+
bearing: bearing,
567+
duration: 500,
500568
});
569+
setTimeout( () => {Globals.map.setMaxPitch(0);}, 500);
570+
if (bearing === 0) {
571+
DOM.$compassBtn.classList.add("d-none");
572+
}
501573
};
502574

503575
let listenResumeAfterLocation = false;
@@ -577,19 +649,74 @@ const isTrackingActive = () => {
577649
return tracking_active;
578650
};
579651

652+
const isNavigationActive = () => {
653+
return navigation_active;
654+
};
655+
580656
const getCurrentPosition = () => {
581657
return currentPosition;
582658
};
583659

660+
// Event handlers for rotation and zoom when tracking active
661+
const locationOnTouchStartHandler = (e) => {
662+
if (e.touches.length === 2) {
663+
startDist = getTouchDistance(e.touches);
664+
startZoom = Globals.map.getZoom();
665+
startBearing = Globals.map.getBearing();
666+
startAngle = getTouchAngle(e.touches);
667+
rotationEnabled = false;
668+
}
669+
};
670+
671+
const locationOnTouchMoveHandler = (e) => {
672+
if (e.touches.length === 2) {
673+
e.preventDefault();
674+
675+
const currentDist = getTouchDistance(e.touches);
676+
const scale = currentDist / startDist;
677+
const newZoom = startZoom + Math.log2(scale);
678+
679+
const currentAngle = getTouchAngle(e.touches);
680+
let angleDelta = currentAngle - startAngle;
681+
if (!rotationEnabled && Math.abs(angleDelta) > 8) {
682+
rotationEnabled = true;
683+
startAngle += angleDelta;
684+
angleDelta = 0;
685+
}
686+
const newBearing = startBearing + angleDelta;
687+
688+
Globals.map.setZoom(newZoom, { around: Globals.map.getCenter() });
689+
if (rotationEnabled) {
690+
Globals.map.setBearing(newBearing);
691+
}
692+
}
693+
};
694+
695+
function getTouchDistance(touches) {
696+
const [touch1, touch2] = touches;
697+
const dx = touch1.clientX - touch2.clientX;
698+
const dy = touch1.clientY - touch2.clientY;
699+
return Math.sqrt(dx * dx + dy * dy);
700+
}
701+
702+
function getTouchAngle(touches) {
703+
const [touch1, touch2] = touches;
704+
const dx = touch1.clientX - touch2.clientX;
705+
const dy = touch1.clientY - touch2.clientY;
706+
return Math.atan2(dy, dx) * (180 / Math.PI);
707+
}
708+
584709
export default {
585710
target,
586711
getCurrentPosition,
587712
isLocationActive,
588713
isTrackingActive,
714+
isNavigationActive,
589715
moveTo,
590716
enablePosition,
591717
locationOnOff,
592718
getOrientation,
593719
getLocation,
594720
disableTracking,
721+
disableNavigation,
595722
};

0 commit comments

Comments
 (0)