I am facing an issue with an analog clock component. When I repeatedly click on the time adjustment bubble and simultaneously modify the cursor position, it moves away from its initial position, which should be between an orange circle and the clock’s content (the white part).
I attempted to resolve this problem by adjusting the marginLeft and marginTop properties, but this made the situation even worse.
let isDragging = false;
let offsetX, offsetY;
const draggable = document.querySelector('.clock div:nth-child(3)');
const clock = document.querySelector('.clock');
const clockRadius = clock.offsetWidth / 2;
const draggableRadius = draggable.offsetWidth / 2;
const hourDisplay = document.querySelector('.clock div p');
draggable.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - draggable.getBoundingClientRect().left;
offsetY = e.clientY - draggable.getBoundingClientRect().top;
draggable.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const angle = Math.atan2(e.clientY - (clock.offsetTop + clockRadius), e.clientX - (clock.offsetLeft + clockRadius));
let hours = Math.floor((angle + Math.PI / 2) / (Math.PI / 6));
hours = (hours + 12) % 12; // Adjust for 0-11 instead of 1-12
const minuteSegment = ((angle + Math.PI / 2) / (Math.PI / 6 / 60)) % 60;
const minutes = Math.floor(minuteSegment);
// Calculate and display the hour and minutes based on the angle
const formattedHour = hours < 10 ? `0${hours}` : `${hours}`;
const formattedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
hourDisplay.textContent = `${formattedHour}:${formattedMinutes}`;
const x = Math.cos(angle) * (clockRadius - draggableRadius) + clockRadius - draggableRadius;
const y = Math.sin(angle) * (clockRadius - draggableRadius) + clockRadius - draggableRadius;
draggable.style.left = x - offsetX + 'px';
draggable.style.top = y - offsetY + 'px';
});
document.addEventListener('mouseup', () => {
isDragging = false;
draggable.style.cursor = 'grab';
});
2
Answers
Try the updated code below:
I have adapted your code to make it work. The main idea is that the draggable is at a fixed distance from the center of the clock and the position of the draggable should only depend on the angle and not on the position of the mouse click (please look at the comments in the code).
The position of the mouse click
(e.clientX, e.clientY)
is only used to compute the angle:Demo: