我遇到了模拟时钟组件的问题。当我反复单击时间调整气泡并同时修改光标位置时,它会远离其初始位置,该位置应位于橙色圆圈和时钟内容(白色部分)之间。
我尝试通过调整 marginLeft 和 marginTop 属性来解决此问题,但这使情况变得更糟。
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';
});
最佳答案
我已经调整了您的代码以使其正常工作。主要思想是,可拖动对象与时钟中心的距离固定,并且可拖动对象的位置应仅取决于 Angular ,而不取决于鼠标单击的位置(请查看代码中的注释)。
鼠标点击的位置(e.clientX, e.clientY)
仅用于计算 Angular :
const angle = Math.atan2(e.clientY - clockcenterY, e.clientX - clockcenterX);
演示:
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;
// clock.getBoundingClientRect()
const box = clock.getBoundingClientRect();
const clockcenterX = (box.left + box.right) / 2;
const clockcenterY = (box.top + box.bottom) / 2;
const draggableRadius = draggable.offsetWidth / 2;
const hourDisplay = document.querySelector('.clock div p');
const radius = clockRadius - draggableRadius;
// compute clock border width
const clockBorderwidth = (clock.offsetWidth - clock.clientWidth) / 2;
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;
// use clockcenterX, clockcenterY
const angle = Math.atan2(e.clientY - clockcenterY, e.clientX - clockcenterX);
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) / (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}`;
// the position of the draggable should only depend on the angle
// (and not on the position of the mouse click)
const x = Math.cos(angle) * radius + radius - clockBorderwidth;
const y = Math.sin(angle) * radius + radius - clockBorderwidth;
draggable.style.left = x + 'px';
draggable.style.top = y + 'px';
});
document.addEventListener('mouseup', () => {
isDragging = false;
draggable.style.cursor = 'grab';
});
body {
font-family: 'Nunito Sans';
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.clock {
display: flex;
justify-content: center;
align-items: center;
width: 120px;
height: 120px;
border: 20px solid #f7ab57;
border-radius: 50%;
position: relative;
}
.clock div:nth-child(2) {
width: 110px;
height: 110px;
border: 5px solid #dcdfdd;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.clock div:nth-child(3) {
width: 20px;
height: 20px;
background-color: #4480c3;
border-radius: 50%;
position: absolute;
margin-bottom: 140px;
cursor: grab;
}
.clock div p {
color: #2e1414;
font-size: 48px;
}
<div class="clock">
<div></div>
<div></div>
<div></div>
<div>
<p>00:00</p>
</div>
</div>
关于javascript - 模拟时钟的时间调整气泡偏差问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76999788/