8
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScript 要素をマウスやタッチ操作で回転

Last updated at Posted at 2021-08-23

PC/タッチデバイス両対応の回転操作のサンプル

ss.jpg

動作デモ


<!DOCTYPE html>
<html lang='ja'>
<head>
<meta charset='utf-8'>
<title>要素の回転操作サンプル</title>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<style>
.wheel {
  position: absolute;
  border: 3px #fff double;
  border-radius: 50%;
  cursor: pointer;
  background-image: repeating-conic-gradient(#fffe, #888e 60deg, #fffe 180deg);
  user-select: none;
  box-sizing: border-box;
}
</style>
</head>
<body>

<script>
'use strict';
{
  // タッチデバイスか否かでイベント名振り分け
  const isTouchDevice = window.ontouchstart !== undefined;
  const ev = {
    down: isTouchDevice ? 'touchstart' : 'mousedown',
    move: isTouchDevice ? 'touchmove'  : 'mousemove',
    up  : isTouchDevice ? 'touchend'   : 'mouseup',
  };

  // 操作時の各値保持用オブジェクト
  const p = {};

  // 要素生成
  const body = document.querySelector('body');
  for(let i = 0; i < 30; i++) {
    body.insertAdjacentHTML('beforeend', "<div class='wheel'></div>");
    const e = body.lastChild;
    e.style.width = e.style.height = `${Math.floor(50 + Math.random() * 150)}px`;
    e.style.left = `${Math.random() * (window.innerWidth * 1.5 - e.clientWidth)}px`;
    e.style.top = `${Math.random() * (window.innerHeight * 1.5 - e.clientHeight)}px`;
    e.style.backgroundColor = `hsl(${Math.random() * 360}deg, 40%, 50%)`;

    // タッチデバイスで操作時のスクロール抑制
    if(isTouchDevice) {
      e.addEventListener('touchmove', e => e.preventDefault());
    }
  }

  // マウスボタンorタッチディスプレイ押下
  window.addEventListener(ev.down, e => {
    // 対象要素でなければreturn
    if(!e.target.classList.contains('wheel')) {
      return;
    }
    p.target = e.target;
    const e_ = isTouchDevice ? e.touches[0] : e;

    // 押下開始時の要素の角度
    p.startDeg = + p.target.style.transform.replace(/[^\d.-]/g, '');

    // 要素の中心座標
    p.cx = p.target.offsetLeft + p.target.offsetWidth / 2;
    p.cy = p.target.offsetTop + p.target.offsetHeight / 2;

    // 中心座標に対するクリック位置の角度
    // (0時位置を0°、6時位置へ向かって時計回りに ~+180°、反時計回りに ~-180°)
    p.clickDeg = Math.atan2(e_.pageX - p.cx, p.cy - e_.pageY) * 180 / Math.PI;
  });

  // 回転操作
  window.addEventListener(ev.move, e => {
    if(!p.target) {
      return;
    }
    const e_ = isTouchDevice ? e.touches[0] : e;

    // 要素の元の角度と初期押下位置角度を加味した操作後の角度 (0~360°)
    const d = (Math.atan2(e_.pageX - p.cx, p.cy - e_.pageY) * 180 / Math.PI
               + p.startDeg - p.clickDeg + 360) % 360;

    // 要素に角度を反映
    p.target.style.transform = `rotate(${d}deg)`;
  });

  // 開放
  window.addEventListener(ev.up, () => delete p.target);
}
</script>
</body>

これまで回転操作系のUIをいくつか作成していますが、回転操作で行なっている処理は設定の細かな差こそありますが基本はどれもだいたい同じです。

カラーピッカー
ジョグシャトル型回転UI
タイムピッカー


8
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?