intento 3
This commit is contained in:
parent
fab7a4ac95
commit
b15b7093b1
@ -8,10 +8,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: move;
|
cursor: move; /* Indica que es arrastrable */
|
||||||
user-select: none;
|
user-select: none; /* Evita selección de texto al arrastrar */
|
||||||
z-index: 1;
|
z-index: 1000; /* Asegura que esté por encima de otros elementos */
|
||||||
/* z-index: 1000; */
|
|
||||||
transition:
|
transition:
|
||||||
background-color 0.3s,
|
background-color 0.3s,
|
||||||
left 0.3s ease,
|
left 0.3s ease,
|
||||||
@ -20,11 +19,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.floating-btn:active {
|
.floating-btn:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing; /* Cambia el cursor mientras se arrastra */
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<div class="floating-btn border border-light shadow-lg" id="floatingBtn">
|
<div class="floating-btn border border-light shadow-lg" id="floatingBtn">
|
||||||
<a id="floatingBtnLink" target="_blank" href="https://chatgpt.com/g/g-6828126fba608191a2803ac89f54f504-formha-rh-para-pymes">
|
<a id="floatingBtnLink" target="_blank" href="https://chatgpt.com/g/g-6828126fba608191a2803ac89f54f504-formha-rh-para-pymes">
|
||||||
<img src="{{ url_for('static', filename='y_img/logos/chat_ia_formha.svg') }}"
|
<img src="{{ url_for('static', filename='y_img/logos/chat_ia_formha.svg') }}"
|
||||||
@ -34,174 +33,154 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<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;
|
let offsetX, offsetY; // Desplazamiento del puntero/dedo dentro del botón
|
||||||
let isDragging = false;
|
let isDragging = false; // Estado de arrastre
|
||||||
let hasMoved = false;
|
let hasMoved = false; // Indica si el botón se ha movido lo suficiente para ser considerado arrastre
|
||||||
let touchStartTimer;
|
let startClientX, startClientY; // Coordenadas iniciales del toque/clic
|
||||||
const tapThreshold = 200; // Tiempo en milisegundos para considerar un "tap"
|
const moveThreshold = 5; // Distancia en píxeles para considerar un "move"
|
||||||
const moveThreshold = 10; // Distancia en píxeles para considerar un "move"
|
|
||||||
let initialTouchX, initialTouchY;
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- Cargar y aplicar la 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;
|
||||||
setTimeout(() => stickToNearestSide(parseInt(x), parseInt(y)), 10);
|
// Usamos requestAnimationFrame para asegurar que la posición se aplique después del renderizado.
|
||||||
|
// Esto evita posibles glitches al inicio.
|
||||||
|
requestAnimationFrame(() => stickToNearestSide(parseInt(x), parseInt(y)));
|
||||||
} else {
|
} else {
|
||||||
|
// Posición inicial por defecto si no hay nada guardado
|
||||||
btn.style.right = '20px';
|
btn.style.right = '20px';
|
||||||
btn.style.top = '20px';
|
btn.style.top = '20px';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eventos para mouse
|
// --- Eventos para mouse (click y arrastre) ---
|
||||||
btn.addEventListener('mousedown', startDrag);
|
btn.addEventListener('mousedown', startInteraction);
|
||||||
document.addEventListener('mousemove', drag);
|
document.addEventListener('mousemove', moveInteraction);
|
||||||
document.addEventListener('mouseup', stopDrag);
|
document.addEventListener('mouseup', endInteraction);
|
||||||
|
|
||||||
|
// --- Eventos para touch (tap y arrastre) ---
|
||||||
|
// passive: false es CRUCIAL para poder usar e.preventDefault() en touchmove y evitar el scroll no deseado.
|
||||||
|
btn.addEventListener('touchstart', startInteraction, { passive: false });
|
||||||
|
document.addEventListener('touchmove', moveInteraction, { passive: false });
|
||||||
|
document.addEventListener('touchend', endInteraction);
|
||||||
|
|
||||||
// Eventos para touch
|
// --- Evitar que el enlace se abra si se ha arrastrado el botón ---
|
||||||
btn.addEventListener('touchstart', startTouch, { passive: false });
|
|
||||||
btn.addEventListener('touchmove', moveTouch, { passive: false });
|
|
||||||
btn.addEventListener('touchend', endTouch);
|
|
||||||
|
|
||||||
link.addEventListener('click', function (e) {
|
link.addEventListener('click', function (e) {
|
||||||
if (hasMoved) {
|
if (hasMoved) {
|
||||||
e.preventDefault();
|
e.preventDefault(); // Si se movió, previene el click
|
||||||
hasMoved = false;
|
|
||||||
}
|
}
|
||||||
|
hasMoved = false; // Resetear para la siguiente interacción
|
||||||
});
|
});
|
||||||
|
|
||||||
function startDrag(e) {
|
// --- Función para iniciar la interacción (mousedown o touchstart) ---
|
||||||
isDragging = true;
|
function startInteraction(e) {
|
||||||
hasMoved = false;
|
// Prevenir el comportamiento por defecto del navegador (ej. arrastrar imágenes)
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
isDragging = false; // Resetear estado de arrastre
|
||||||
|
hasMoved = false; // Resetear estado de movimiento
|
||||||
|
|
||||||
|
// Obtener las coordenadas iniciales del evento (mouse o touch)
|
||||||
|
const clientX = e.clientX || e.touches[0].clientX;
|
||||||
|
const clientY = e.clientY || e.touches[0].clientY;
|
||||||
|
|
||||||
|
startClientX = clientX;
|
||||||
|
startClientY = clientY;
|
||||||
|
|
||||||
|
// Calcular el desplazamiento dentro del botón
|
||||||
const rect = btn.getBoundingClientRect();
|
const rect = btn.getBoundingClientRect();
|
||||||
offsetX = e.clientX - rect.left;
|
offsetX = clientX - rect.left;
|
||||||
offsetY = e.clientY - rect.top;
|
offsetY = clientY - rect.top;
|
||||||
|
|
||||||
btn.style.cursor = 'grabbing';
|
// Asegurar que la posición del botón se base en left/top para el arrastre
|
||||||
btn.style.left = `${rect.left}px`;
|
btn.style.left = `${rect.left}px`;
|
||||||
btn.style.top = `${rect.top}px`;
|
btn.style.top = `${rect.top}px`;
|
||||||
btn.style.right = 'auto';
|
btn.style.right = 'auto'; // Desactivar 'right' para evitar conflictos
|
||||||
|
btn.style.bottom = 'auto'; // Desactivar 'bottom' si estuviera activo
|
||||||
|
|
||||||
e.preventDefault();
|
btn.style.cursor = 'grabbing'; // Cambiar cursor mientras se "agarra"
|
||||||
}
|
}
|
||||||
|
|
||||||
function drag(e) {
|
// --- Función para mover (mousemove o touchmove) ---
|
||||||
if (!isDragging) return;
|
function moveInteraction(e) {
|
||||||
|
if (!startClientX) return; // Si no hay inicio de interacción, salimos
|
||||||
|
|
||||||
const x = e.clientX - offsetX;
|
const clientX = e.clientX || e.touches[0].clientX;
|
||||||
const y = e.clientY - offsetY;
|
const clientY = e.clientY || e.touches[0].clientY;
|
||||||
|
|
||||||
btn.style.left = `${x}px`;
|
const currentX = clientX - offsetX;
|
||||||
btn.style.top = `${y}px`;
|
const currentY = clientY - offsetY;
|
||||||
|
|
||||||
hasMoved = true;
|
// Detectar si el movimiento supera el umbral
|
||||||
}
|
const deltaX = Math.abs(clientX - startClientX);
|
||||||
|
const deltaY = Math.abs(clientY - startClientY);
|
||||||
|
|
||||||
function stopDrag() {
|
if (deltaX > moveThreshold || deltaY > moveThreshold) {
|
||||||
if (!isDragging) return;
|
isDragging = true; // Confirmamos que es un arrastre
|
||||||
|
hasMoved = true; // Se ha movido significativamente
|
||||||
|
}
|
||||||
|
|
||||||
isDragging = false;
|
if (isDragging) {
|
||||||
btn.style.cursor = 'move';
|
// Mover el botón
|
||||||
|
btn.style.left = `${currentX}px`;
|
||||||
const rect = btn.getBoundingClientRect();
|
btn.style.top = `${currentY}px`;
|
||||||
const x = rect.left;
|
// Prevenir el scroll de la página solo si estamos arrastrando
|
||||||
const y = rect.top;
|
|
||||||
|
|
||||||
stickToNearestSide(x, y);
|
|
||||||
savePosition(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function startTouch(e) {
|
|
||||||
if (e.touches.length !== 1) return;
|
|
||||||
|
|
||||||
e.preventDefault(); // Prevenir comportamiento por defecto
|
|
||||||
const touch = e.touches[0];
|
|
||||||
initialTouchX = touch.clientX;
|
|
||||||
initialTouchY = touch.clientY;
|
|
||||||
|
|
||||||
const rect = btn.getBoundingClientRect();
|
|
||||||
offsetX = initialTouchX - rect.left;
|
|
||||||
offsetY = initialTouchY - rect.top;
|
|
||||||
|
|
||||||
hasMoved = false;
|
|
||||||
touchStartTimer = setTimeout(() => {
|
|
||||||
if (!isDragging) {
|
|
||||||
link.click();
|
|
||||||
}
|
|
||||||
}, tapThreshold);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function moveTouch(e) {
|
|
||||||
if (!touchStartTimer || e.touches.length !== 1 || !initialTouchX) return;
|
|
||||||
|
|
||||||
const touch = e.touches[0];
|
|
||||||
const currentX = touch.clientX;
|
|
||||||
const currentY = touch.clientY;
|
|
||||||
|
|
||||||
// Verificar si el movimiento supera el umbral
|
|
||||||
if (Math.abs(currentX - initialTouchX) > moveThreshold ||
|
|
||||||
Math.abs(currentY - initialTouchY) > moveThreshold) {
|
|
||||||
clearTimeout(touchStartTimer);
|
|
||||||
isDragging = true;
|
|
||||||
hasMoved = true;
|
|
||||||
|
|
||||||
btn.style.cursor = 'grabbing';
|
|
||||||
btn.style.left = `${currentX - offsetX}px`;
|
|
||||||
btn.style.top = `${currentY - offsetY}px`;
|
|
||||||
btn.style.right = 'auto';
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Función para finalizar la interacción (mouseup o touchend) ---
|
||||||
|
function endInteraction() {
|
||||||
|
// Resetear las coordenadas iniciales del toque
|
||||||
|
startClientX = null;
|
||||||
|
startClientY = null;
|
||||||
|
|
||||||
|
|
||||||
function endTouch(e) {
|
|
||||||
clearTimeout(touchStartTimer);
|
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
isDragging = false;
|
isDragging = false; // Finalizar el estado de arrastre
|
||||||
btn.style.cursor = 'move';
|
btn.style.cursor = 'move'; // Restaurar cursor
|
||||||
|
|
||||||
const rect = btn.getBoundingClientRect();
|
const rect = btn.getBoundingClientRect();
|
||||||
stickToNearestSide(rect.left, rect.top);
|
stickToNearestSide(rect.left, rect.top); // Anclar a la posición final
|
||||||
savePosition(rect.left, rect.top);
|
savePosition(rect.left, rect.top); // Guardar la posición
|
||||||
}
|
}
|
||||||
initialTouchX = null;
|
// hasMoved se reseteará en el evento 'click' del enlace o en la siguiente 'startInteraction'
|
||||||
initialTouchY = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 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 btnWidth = btn.offsetWidth;
|
const btnWidth = btn.offsetWidth;
|
||||||
|
const btnHeight = btn.offsetHeight;
|
||||||
|
const padding = 10; // Espacio de separación de los bordes
|
||||||
|
|
||||||
if (x < windowWidth / 2) {
|
// Anclar al lado izquierdo o derecho
|
||||||
btn.style.left = '10px';
|
if (x < windowWidth / 2 - btnWidth / 2) { // Considera el centro del botón
|
||||||
|
btn.style.left = `${padding}px`;
|
||||||
btn.style.right = 'auto';
|
btn.style.right = 'auto';
|
||||||
} else {
|
} else {
|
||||||
btn.style.left = 'auto';
|
btn.style.left = 'auto';
|
||||||
btn.style.right = '10px';
|
btn.style.right = `${padding}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const windowHeight = window.innerHeight;
|
// Asegurarse de que el botón no salga por arriba o por abajo
|
||||||
const btnHeight = btn.offsetHeight;
|
let newY = y;
|
||||||
|
if (y < padding) {
|
||||||
if (y < 0) {
|
newY = padding;
|
||||||
btn.style.top = '10px';
|
} else if (y + btnHeight > windowHeight - padding) {
|
||||||
} else if (y + btnHeight > windowHeight) {
|
newY = windowHeight - btnHeight - padding;
|
||||||
btn.style.top = `${windowHeight - btnHeight - 10}px`;
|
|
||||||
} else {
|
|
||||||
btn.style.top = `${y}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,
|
||||||
@ -209,11 +188,16 @@
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Ajustar posición al redimensionar la ventana ---
|
||||||
window.addEventListener('resize', function () {
|
window.addEventListener('resize', function () {
|
||||||
const savedPosition = localStorage.getItem('floatingBtnPosition');
|
const saved = localStorage.getItem('floatingBtnPosition');
|
||||||
if (savedPosition) {
|
if (saved) {
|
||||||
const { x, y } = JSON.parse(savedPosition);
|
const { x, y } = JSON.parse(saved);
|
||||||
|
// Volver a anclar el botón a su lado más cercano según la nueva ventana
|
||||||
stickToNearestSide(parseInt(x), parseInt(y));
|
stickToNearestSide(parseInt(x), parseInt(y));
|
||||||
|
} else {
|
||||||
|
// Si no hay posición guardada, anclar a la posición por defecto
|
||||||
|
stickToNearestSide(btn.getBoundingClientRect().left, btn.getBoundingClientRect().top);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user