При перетаскивании поверните стрелку часов на правильный угол - Ваниль JS - PullRequest
0 голосов
/ 14 января 2020

Я реализовал аналоговые часы с минутной стрелкой и часовой стрелкой. Цель этого упражнения - при перетаскивании повернуть стрелки часов на соответствующий угол метки часа; то есть, когда мышь двигается вокруг.

Некоторые примеры, которые я нашел, используют JQuery и другие библиотеки. Я пытаюсь сделать это только с ванилью js. Я посмотрел некоторые примеры, расположенные здесь, в stackoverflow, а также в других местах и ​​изучая логи c и пытаясь понять документацию atan2 , это насколько я смог получить:

//rotate handler
const rotateHand = (event)=>{
    const elem = event.target;
    elem.style.cursor = "grabbing";
    let rotating = true;
    const clock = document.querySelector(".gamut__timePicker__clock");
    const radius = 252 / 2;
    const rotateHandler = (e)=>{
        const radians = Math.atan2(e.pageX - radius, e.pageY - radius);
        let rotateDegrees = (radians * (180 / Math.PI) * -1) -180;
        if (rotating) {
            elem.style.transform = `rotate(${rotateDegrees}deg)`;
        }
    };
    document.addEventListener("mousemove", rotateHandler);
    const cancelRotate = (event)=>{
        elem.style.cursor = "grab";
        rotating = !rotating;
        document.removeEventListener("mousemove", rotateHandler);
        document.removeEventListener("mouseup", cancelRotate);

    };
    document.addEventListener("mouseup", cancelRotate);
};

document.querySelector(".gamut__timePicker__minHand").addEventListener("mousedown", rotateHand);
document.querySelector(".gamut__timePicker__hrHand").addEventListener("mousedown", rotateHand);
@import url("https://fonts.googleapis.com/css?family=Roboto&display=swap");
.gamut__timePicker {
  border: 1px solid gray;
  width: 300px;
  height: 335px;
  display: -webkit-box;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
          flex-direction: column;
  font-family: 'Roboto', sans-serif;
}

.gamut__timePicker__meridiamSelector {
  height: 20px;
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: justify;
          justify-content: space-between;
}

.gamut__timePicker__meridiamSelector--meridiam {
  text-align: center;
  -webkit-box-flex: 1;
          flex-grow: 1;
  border: 1px solid gray;
  font-size: 0.875rem;
  line-height: 20px;
  cursor: pointer;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}

.gamut__timePicker__meridiamSelector--meridiam:hover {
  background: #efefef;
}

.gamut__timePicker__meridiamSelector--selected {
  background: #607d8b !important;
  color: white;
}

.gamut__timePicker__clockWrapper {
  -webkit-box-flex: 1;
          flex-grow: 1;
  align-self: stretch;
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: center;
          justify-content: center;
  -webkit-box-align: center;
          align-items: center;
  position: relative;
}

.gamut__timePicker__clock {
  border-radius: 50%;
  width: 250px;
  height: 250px;
  border: 1px solid gray;
  margin: 0 auto;
  position: relative;
}

.gamut__timePicker__clock--minPointer {
  width: 1px;
  height: 10px;
  background-color: #424242;
  position: absolute;
  -webkit-transform-origin: 0% 0%;
          transform-origin: 0% 0%;
}

.gamut__timePicker__clock--hrPointer {
  position: absolute;
  -webkit-transform-origin: 0% 0%;
          transform-origin: 0% 0%;
}

.gamut__timePicker__clock--hrPointer::before {
  top: -4px;
  left: -7px;
  content: "\25BC";
  position: absolute;
}

.gamut__timePicker__labels {
  border-radius: 50%;
  width: 210px;
  height: 210px;
  margin: 0 auto;
  position: absolute;
  pointer-events: none;
}

.gamut__timePicker__labels--hourLabel {
  position: absolute;
  -webkit-transform: translate(-50%, -45%);
          transform: translate(-50%, -45%);
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}

.gamut__timePicker__minHand {
  width: 20px;
  height: 100px;
  background-image: url(https://res.cloudinary.com/dvzwvxhev/image/upload/v1578025454/clock_min.svg);
  background-size: 100% 100%;
  position: absolute;
  -webkit-transform-origin: 49% 92%;
          transform-origin: 49% 92%;
  top: 15%;
  -webkit-transform: rotate(0deg);
          transform: rotate(0deg);
  cursor: -webkit-grab;
  cursor: grab;
}

.gamut__timePicker__hrHand {
  width: 40px;
  height: 70px;
  background-image: url(https://res.cloudinary.com/dvzwvxhev/image/upload/v1578274567/clock_hr.svg);
  background-size: 100% 100%;
  position: absolute;
  -webkit-transform-origin: 50% 93%;
          transform-origin: 50% 93%;
  top: 25%;
  -webkit-transform: rotate(0deg);
          transform: rotate(0deg);
  cursor: -webkit-grab;
  cursor: grab;
}

.gamut__timePicker__time {
  height: 34px;
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: center;
          justify-content: center;
}

.gamut__timePicker__time > input {
  width: 35px;
  border: none;
  border-bottom: 1px solid #ababab;
  text-align: center;
  font-size: 1.125rem;
  outline: none;
  height: 25px;
  padding: 0;
}

.gamut__timePicker__time > input:focus {
  border-bottom: 2px solid #607d8b;
}

.gamut__timePicker__time--separator {
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  font-size: 1.125rem;
  height: 25px;
}

.gamut__timePicker__done {
  background: #efefef;
  text-align: center;
  border-top: 1px solid gray;
  cursor: pointer;
}
<div class="gamut__timePicker" style="top: 31px; left: 8px; z-index: 9;"><div class="gamut__timePicker__meridiamSelector"><div data-meridiam-value="am" class="gamut__timePicker__meridiamSelector--meridiam gamut__timePicker__meridiamSelector--selected">AM</div><div data-meridiam-value="pm" class="gamut__timePicker__meridiamSelector--meridiam">PM</div></div><div class="gamut__timePicker__clockWrapper"><div class="gamut__timePicker__clock"><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(90deg); left: 100%; top: 50%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(96deg); left: 99.7261%; top: 55.2264%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(102deg); left: 98.9074%; top: 60.3956%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(108deg); left: 97.5528%; top: 65.4508%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(114deg); left: 95.6773%; top: 70.3368%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(120deg); left: 93.3013%; top: 75%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(126deg); left: 90.4508%; top: 79.3893%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(132deg); left: 87.1572%; top: 83.4565%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(138deg); left: 83.4565%; top: 87.1572%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(144deg); left: 79.3893%; top: 90.4508%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(150deg); left: 75%; top: 93.3013%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(156deg); left: 70.3368%; top: 95.6773%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(162deg); left: 65.4508%; top: 97.5528%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(168deg); left: 60.3956%; top: 98.9074%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(174deg); left: 55.2264%; top: 99.7261%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(180deg); left: 50%; top: 100%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(186deg); left: 44.7736%; top: 99.7261%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(192deg); left: 39.6044%; top: 98.9074%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(198deg); left: 34.5492%; top: 97.5528%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(204deg); left: 29.6632%; top: 95.6773%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(210deg); left: 25%; top: 93.3013%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(216deg); left: 20.6107%; top: 90.4508%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(222deg); left: 16.5435%; top: 87.1572%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(228deg); left: 12.8428%; top: 83.4565%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(234deg); left: 9.54915%; top: 79.3893%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(240deg); left: 6.69873%; top: 75%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(246deg); left: 4.32273%; top: 70.3368%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(252deg); left: 2.44717%; top: 65.4508%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(258deg); left: 1.09262%; top: 60.3956%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(264deg); left: 0.273905%; top: 55.2264%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(270deg); left: 0%; top: 50%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(276deg); left: 0.273905%; top: 44.7736%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(282deg); left: 1.09262%; top: 39.6044%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(288deg); left: 2.44717%; top: 34.5492%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(294deg); left: 4.32273%; top: 29.6632%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(300deg); left: 6.69873%; top: 25%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(306deg); left: 9.54915%; top: 20.6107%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(312deg); left: 12.8428%; top: 16.5435%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(318deg); left: 16.5435%; top: 12.8428%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(324deg); left: 20.6107%; top: 9.54915%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(330deg); left: 25%; top: 6.69873%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(336deg); left: 29.6632%; top: 4.32273%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(342deg); left: 34.5492%; top: 2.44717%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(348deg); left: 39.6044%; top: 1.09262%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(354deg); left: 44.7736%; top: 0.273905%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(360deg); left: 50%; top: 0%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(366deg); left: 55.2264%; top: 0.273905%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(372deg); left: 60.3956%; top: 1.09262%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(378deg); left: 65.4508%; top: 2.44717%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(384deg); left: 70.3368%; top: 4.32273%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(390deg); left: 75%; top: 6.69873%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(396deg); left: 79.3893%; top: 9.54915%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(402deg); left: 83.4565%; top: 12.8428%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(408deg); left: 87.1572%; top: 16.5435%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(414deg); left: 90.4508%; top: 20.6107%;"></div><div class="gamut__timePicker__clock--hrPointer" style="transform: rotate(420deg); left: 93.3013%; top: 25%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(426deg); left: 95.6773%; top: 29.6632%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(432deg); left: 97.5528%; top: 34.5492%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(438deg); left: 98.9074%; top: 39.6044%;"></div><div class="gamut__timePicker__clock--minPointer" style="transform: rotate(444deg); left: 99.7261%; top: 44.7736%;"></div></div><div class="gamut__timePicker__labels"><span class="gamut__timePicker__labels--hourLabel" style="left: 100%; top: 50%;">3</span><span class="gamut__timePicker__labels--hourLabel" style="left: 93.3013%; top: 75%;">4</span><span class="gamut__timePicker__labels--hourLabel" style="left: 75%; top: 93.3013%;">5</span><span class="gamut__timePicker__labels--hourLabel" style="left: 50%; top: 100%;">6</span><span class="gamut__timePicker__labels--hourLabel" style="left: 25%; top: 93.3013%;">7</span><span class="gamut__timePicker__labels--hourLabel" style="left: 6.69873%; top: 75%;">8</span><span class="gamut__timePicker__labels--hourLabel" style="left: 0%; top: 50%;">9</span><span class="gamut__timePicker__labels--hourLabel" style="left: 6.69873%; top: 25%;">10</span><span class="gamut__timePicker__labels--hourLabel" style="left: 25%; top: 6.69873%;">11</span><span class="gamut__timePicker__labels--hourLabel" style="left: 50%; top: 0%;">12</span><span class="gamut__timePicker__labels--hourLabel" style="left: 75%; top: 6.69873%;">1</span><span class="gamut__timePicker__labels--hourLabel" style="left: 93.3013%; top: 25%;">2</span></div><div class="gamut__timePicker__minHand" style="transform: rotate(0deg);"></div><div class="gamut__timePicker__hrHand" style="transform: rotate(240deg);"></div></div><div class="gamut__timePicker__time"><input type="text" data-time-param="hour"><span class="gamut__timePicker__time--separator">:</span><input type="text" data-time-param="minute"></div><div class="gamut__timePicker__done">DONE</div></div>

Как видно из приведенного фрагмента, стрелка часов вращается, но угол не точный, есть небольшое расхождение. Цель состоит в том, чтобы стрелка указывала на правильный час / минуту, когда указатель мыши находится под углом, который соответствует соответствующему часу.

...