otro intento btn flotante

This commit is contained in:
David Itehua Xalamihua 2025-05-24 13:21:18 -06:00
parent b15b7093b1
commit 1e2631d32e

View File

@ -37,49 +37,112 @@
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const btn = document.getElementById('floatingBtn'); const btn = document.getElementById('floatingBtn');
const link = document.getElementById('floatingBtnLink'); const link = document.getElementById('floatingBtnLink');
let offsetX, offsetY; // Desplazamiento del puntero/dedo dentro del botón let offsetX, offsetY;
let isDragging = false; // Estado de arrastre let isDragging = false;
let hasMoved = false; // Indica si el botón se ha movido lo suficiente para ser considerado arrastre let hasMoved = false;
let startClientX, startClientY; // Coordenadas iniciales del toque/clic let startClientX, startClientY;
const moveThreshold = 5; // Distancia en píxeles para considerar un "move" const moveThreshold = 10; // Aumenté el umbral para mejor experiencia táctil
let tapTimer;
// --- Cargar y aplicar la posición guardada --- // Cargar posición guardada
const savedPosition = localStorage.getItem('floatingBtnPosition'); const savedPosition = localStorage.getItem('floatingBtnPosition');
if (savedPosition) { if (savedPosition) {
const { x, y } = JSON.parse(savedPosition); const { x, y } = JSON.parse(savedPosition);
btn.style.left = x; btn.style.left = x;
btn.style.top = y; btn.style.top = y;
// Usamos requestAnimationFrame para asegurar que la posición se aplique después del renderizado. requestAnimationFrame(() => stickToNearestSide(parseInt(x), parseInt(y)));
// Esto evita posibles glitches al inicio. } else {
requestAnimationFrame(() => stickToNearestSide(parseInt(x), parseInt(y))); btn.style.right = '20px';
} else { btn.style.top = '20px';
// Posición inicial por defecto si no hay nada guardado }
btn.style.right = '20px';
btn.style.top = '20px';
}
// --- Eventos para mouse (click y arrastre) --- // Eventos para mouse
btn.addEventListener('mousedown', startInteraction); btn.addEventListener('mousedown', startInteraction);
document.addEventListener('mousemove', moveInteraction); document.addEventListener('mousemove', moveInteraction);
document.addEventListener('mouseup', endInteraction); document.addEventListener('mouseup', endInteraction);
// --- Eventos para touch (tap y arrastre) --- // Eventos para touch
// passive: false es CRUCIAL para poder usar e.preventDefault() en touchmove y evitar el scroll no deseado. btn.addEventListener('touchstart', handleTouchStart, { passive: false });
btn.addEventListener('touchstart', startInteraction, { passive: false }); btn.addEventListener('touchend', handleTouchEnd, { passive: false });
document.addEventListener('touchmove', moveInteraction, { passive: false }); document.addEventListener('touchmove', handleTouchMove, { passive: false });
document.addEventListener('touchend', endInteraction);
// --- Evitar que el enlace se abra si se ha arrastrado el botón --- // Manejar el clic/enlace
link.addEventListener('click', function (e) { link.addEventListener('click', handleLinkClick);
if (hasMoved) {
e.preventDefault(); // Si se movió, previene el click function handleTouchStart(e) {
e.preventDefault();
const touch = e.touches[0];
startClientX = touch.clientX;
startClientY = touch.clientY;
const rect = btn.getBoundingClientRect();
offsetX = startClientX - rect.left;
offsetY = startClientY - rect.top;
isDragging = false;
hasMoved = false;
// Iniciar temporizador para el tap
tapTimer = setTimeout(() => {
if (!isDragging) {
simulateClick(link);
} }
hasMoved = false; // Resetear para la siguiente interacción }, 300); // 300ms es el tiempo típico para considerar un tap
}); }
// --- Función para iniciar la interacción (mousedown o touchstart) --- function handleTouchMove(e) {
if (!startClientX) return;
const touch = e.touches[0];
const currentX = touch.clientX;
const currentY = touch.clientY;
const deltaX = Math.abs(currentX - startClientX);
const deltaY = Math.abs(currentY - startClientY);
if (deltaX > moveThreshold || deltaY > moveThreshold) {
clearTimeout(tapTimer);
isDragging = true;
hasMoved = true;
btn.style.left = `${currentX - offsetX}px`;
btn.style.top = `${currentY - offsetY}px`;
btn.style.right = 'auto';
e.preventDefault();
}
}
function handleTouchEnd(e) {
clearTimeout(tapTimer);
if (isDragging) {
isDragging = false;
const rect = btn.getBoundingClientRect();
stickToNearestSide(rect.left, rect.top);
savePosition(rect.left, rect.top);
}
startClientX = null;
startClientY = null;
}
function simulateClick(element) {
const clickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
element.dispatchEvent(clickEvent);
}
function handleLinkClick(e) {
if (hasMoved) {
e.preventDefault();
}
hasMoved = false;
}
// Funciones restantes igual que antes...
function startInteraction(e) { function startInteraction(e) {
// Prevenir el comportamiento por defecto del navegador (ej. arrastrar imágenes) // Prevenir el comportamiento por defecto del navegador (ej. arrastrar imágenes)
e.preventDefault(); e.preventDefault();
@ -108,7 +171,6 @@
btn.style.cursor = 'grabbing'; // Cambiar cursor mientras se "agarra" btn.style.cursor = 'grabbing'; // Cambiar cursor mientras se "agarra"
} }
// --- Función para mover (mousemove o touchmove) ---
function moveInteraction(e) { function moveInteraction(e) {
if (!startClientX) return; // Si no hay inicio de interacción, salimos if (!startClientX) return; // Si no hay inicio de interacción, salimos
@ -136,7 +198,6 @@
} }
} }
// --- Función para finalizar la interacción (mouseup o touchend) ---
function endInteraction() { function endInteraction() {
// Resetear las coordenadas iniciales del toque // Resetear las coordenadas iniciales del toque
startClientX = null; startClientX = null;
@ -153,7 +214,7 @@
// hasMoved se reseteará en el evento 'click' del enlace o en la siguiente 'startInteraction' // hasMoved se reseteará en el evento 'click' del enlace o en la siguiente 'startInteraction'
} }
// --- Función para anclar el botón al lado más cercano ---
function stickToNearestSide(x, y) { function stickToNearestSide(x, y) {
const windowWidth = window.innerWidth; const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
@ -180,7 +241,6 @@
btn.style.top = `${newY}px`; btn.style.top = `${newY}px`;
} }
// --- Función para guardar la posición en localStorage ---
function savePosition(x, y) { function savePosition(x, y) {
localStorage.setItem('floatingBtnPosition', JSON.stringify({ localStorage.setItem('floatingBtnPosition', JSON.stringify({
x: btn.style.left, x: btn.style.left,
@ -188,8 +248,7 @@
})); }));
} }
// --- Ajustar posición al redimensionar la ventana --- window.addEventListener('resize', function () {
window.addEventListener('resize', function () {
const saved = localStorage.getItem('floatingBtnPosition'); const saved = localStorage.getItem('floatingBtnPosition');
if (saved) { if (saved) {
const { x, y } = JSON.parse(saved); const { x, y } = JSON.parse(saved);
@ -200,5 +259,6 @@
stickToNearestSide(btn.getBoundingClientRect().left, btn.getBoundingClientRect().top); stickToNearestSide(btn.getBoundingClientRect().left, btn.getBoundingClientRect().top);
} }
}); });
});
});
</script> </script>