javascript - 模拟时钟的时间调整气泡偏差问题

标签 javascript html jquery css

我遇到了模拟时钟组件的问题。当我反复单击时间调整气泡并同时修改光标位置时,它会远离其初始位置,该位置应位于橙色圆圈和时钟内容(白色部分)之间。

我尝试通过调整 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';
});

https://codepen.io/Mohamed-Mojtobai/pen/dywMymP

最佳答案

我已经调整了您的代码以使其正常工作。主要思想是,可拖动对象与时钟中心的距离固定,并且可拖动对象的位置应仅取决于 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/

相关文章:

javascript - 保存上传到 asp 的文件时可以阻止 window.onbeforeunload :fileupload

jquery button() 单击后退按钮时会导致白屏

javascript - 使用 Jest 假计时器进行所有测试

javascript - Canvas 仅在使用 fabric.js 的单击事件上呈现自定义 webfont

javascript - Modernizr.load 在 IE8 中无法正常工作

javascript - JavaScript 中的占位符未运行

.net - 如何编写浏览器特定的 css 属性?

javascript - 是否可以在客户端和服务器端设置 td 的宽度?

html - 子菜单文本颜色无法在 Wordpress 站点中更改

javascript - jQuery 中的 getJSON 长度