|
@@ -8,6 +8,7 @@ const MapView = (() => {
|
|
|
const COLORS = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#34495e'];
|
|
const COLORS = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#34495e'];
|
|
|
const HOVER_TOLERANCE_PX = 20;
|
|
const HOVER_TOLERANCE_PX = 20;
|
|
|
let colorIndex = 0;
|
|
let colorIndex = 0;
|
|
|
|
|
+ let userMovedMap = false; // true after manual pan/zoom; suppresses auto-fit
|
|
|
|
|
|
|
|
// ===== Haversine / point helpers =====
|
|
// ===== Haversine / point helpers =====
|
|
|
|
|
|
|
@@ -78,6 +79,12 @@ const MapView = (() => {
|
|
|
map.on('mouseout', onMapMouseOut);
|
|
map.on('mouseout', onMapMouseOut);
|
|
|
map.on('click', onMapClick);
|
|
map.on('click', onMapClick);
|
|
|
|
|
|
|
|
|
|
+ // Detect manual pan/zoom: Leaflet sets originalEvent only for user gestures,
|
|
|
|
|
+ // not for programmatic fitBounds/setView calls.
|
|
|
|
|
+ map.on('movestart zoomstart', (e) => {
|
|
|
|
|
+ if (e.originalEvent) userMovedMap = true;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
restoreFromHash();
|
|
restoreFromHash();
|
|
|
map.on('moveend zoomend', saveToHash);
|
|
map.on('moveend zoomend', saveToHash);
|
|
|
|
|
|
|
@@ -134,6 +141,7 @@ const MapView = (() => {
|
|
|
layer.addTo(map);
|
|
layer.addTo(map);
|
|
|
layer.on('dblclick', (e) => {
|
|
layer.on('dblclick', (e) => {
|
|
|
L.DomEvent.stopPropagation(e);
|
|
L.DomEvent.stopPropagation(e);
|
|
|
|
|
+ userMovedMap = false; // explicit user request — override the guard
|
|
|
fitTrack(trackId);
|
|
fitTrack(trackId);
|
|
|
});
|
|
});
|
|
|
trackLayers[trackId] = {
|
|
trackLayers[trackId] = {
|
|
@@ -161,6 +169,7 @@ const MapView = (() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function fitTrack(trackId) {
|
|
function fitTrack(trackId) {
|
|
|
|
|
+ if (userMovedMap) return;
|
|
|
if (!trackLayers[trackId]) return;
|
|
if (!trackLayers[trackId]) return;
|
|
|
try {
|
|
try {
|
|
|
const bounds = trackLayers[trackId].layer.getBounds();
|
|
const bounds = trackLayers[trackId].layer.getBounds();
|
|
@@ -171,6 +180,7 @@ const MapView = (() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function fitAll() {
|
|
function fitAll() {
|
|
|
|
|
+ if (userMovedMap) return;
|
|
|
const layers = Object.values(trackLayers).map(t => t.layer);
|
|
const layers = Object.values(trackLayers).map(t => t.layer);
|
|
|
if (layers.length === 0) return;
|
|
if (layers.length === 0) return;
|
|
|
try {
|
|
try {
|