We Blog Weblog

ボタン長押し

Web

2023年9月6日

みなさんこんにちは。
ケミストのWeb担当みやのです。

「Web」記事では、これまでに得たWebに関する知識を記録として残していきたいと思います。

今回は「ボタン長押し」に挑戦してみました。

下準備

iPhoneでは画面を長押し(ロングタップ)すると「コピー」「すべてを選択」「選択部分を検索」などのメニューが出てしまうので、このページでは無効化しておきます。

body {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
}

別に必要ありませんが(ないんかい)ボタンのsvgを2通り作っておきます。

button-off.svg
button-on.svg

 

何秒押されたかわかる

参考:iwb.jp|JavaScriptでマウス(タップ)ボタンの長押しイベントを実装する方法

まずボタンと、秒数の出力欄を作ります。

<div id="button"></div>
            
<p id="r">赤い部分をマウスかタップで長押し</p>
#button {
  width: 300px;
  height: 100px;
  margin: 0 auto 20px;
  background: #a00;
  position: relative;
  cursor: pointer;
}

#button.active {
  background: #f00;
}

さっき作ったsvgを疑似要素で追加します。

#button::before {
  content: "";
  background-color: #fff;
  display: block;
  height: 3rem;
  width: 4rem;
  -webkit-mask: url("img/button-off.svg");
  mask: url("img/button-off.svg");
  -webkit-mask-size: cover;
  mask-size: cover;
  margin : auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

#button.active::before {
  content: "";
  background-color: #fff;
  display: block;
  height: 3rem;
  width: 4rem;
  -webkit-mask: url("img/button-on.svg");
  mask: url("img/button-on.svg");
  -webkit-mask-size: cover;
  mask-size: cover;
  margin : auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

そしてスクリプトを記述します。

let count = 0;
let timer;
const ua = navigator.userAgent.toLowerCase();
const isSP = /iphone|ipod|ipad|android/.test(ua);
const b = document.getElementById('button');
const r = document.getElementById('r');
const eventStart = isSP ? 'touchstart' : 'mousedown';
const eventEnd   = isSP ? 'touchend' : 'mouseup';
const eventLeave = isSP ? 'touchmove' : 'mouseleave';
 
b.addEventListener(eventStart, e => {
  e.preventDefault();
  b.classList.add('active');
  timer = setInterval(() => {
    count++;
    r.textContent = (count / 100) + '秒';
  }, 10);
})
 
b.addEventListener(eventEnd, e => {
  e.preventDefault();
  if (count) {
    b.classList.remove('active');
    clearInterval(timer);
    r.textContent = (count / 100) + '秒長押しされました';
    count = 0;
  }
});
 
b.addEventListener(eventLeave, e => {
  e.preventDefault();
  let el;
  el = isSP ? document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY) : b;
  if (!isSP || el !== b) {
    b.classList.remove('active');
    clearInterval(timer);
    r.textContent = '処理を中断';
    count = 0;
  }
});

参考元のサイトで非常に丁寧に説明してくれていますが、まだ全然理解できていません。

赤い部分をマウスかタップで長押し

 

加算されていく

参考:Qiita|javascriptでクリックやタップの長押し処理をする方法

ボタンと出力欄を作ります。

さっきのsvgを疑似要素で追加します。

buttonタグはダブルタップしたら拡大されたり、長押ししたままスワイプするとずっと押しっぱなし判定になったりしてしまうので、いろいろ追記しておきます。

<button id="btn" style="touch-action: none; user-select: none;" oncontextmenu="return false;"></button>

<p id="target">0</p>
#btn {
  display: block;
  width: 300px;
  height: 100px;
  margin: 0 auto;
  padding: 10px;
  border: 0;
  box-shadow: none;
  color: #ffffff;
  background-color: #0a0;
  cursor: pointer;
  position: relative;
}

#btn:active {
  background: #0f0;
}

#btn::before {
  content: "";
  background-color: #fff;
  display: block;
  height: 3rem;
  width: 4rem;
  -webkit-mask: url("img/button-off.svg");
  mask: url("img/button-off.svg");
  -webkit-mask-size: cover;
  mask-size: cover;
  margin : auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

#btn:active::before {
  content: "";
  background-color: #fff;
  display: block;
  height: 3rem;
  width: 4rem;
  -webkit-mask: url("img/button-on.svg");
  mask: url("img/button-on.svg");
  -webkit-mask-size: cover;
  mask-size: cover;
  margin : auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

スクリプトを記述します。

document.getElementById('btn').addEventListener('pointerdown', () => {
  const intervalId = setInterval(increment, 50)
  
  document.addEventListener('pointerup', () => {
    clearInterval(intervalId)
  }, { once: true })
})

const increment = () => {
  const target = document.getElementById('target')
  let targetNum = Number(target.textContent)
  targetNum++
  target.textContent = targetNum
}

50ミリ秒につき1カウント増えていくということでしょうか。

どうやったらさっきのように秒数(小数点)にできるんだろう。

0

 

規定の秒数押したらイベント

参考:Into the Program|【JavaScript】クリック・タッチの長押しを判定する

参考:GitHub|long-press-event

参考:かちびと.net|JavaScriptでロングタップイベントを実装する

long-press-eventというライブラリがあるようなので使ってみたいと思います。

まずは上記のサイトからlong-press-event.min.jsをダウンロードしてヘッダー内で読み込みます。

<script src="js/long-press-event.min.js"></script>

スクリプトを記述します。

document.addEventListener('long-press', function(e) {
  e.target.setAttribute('data-editing', 'true');
});

ボタンとゲージを作ります。

data-long-press-delayで「何ミリ秒押し続けたらイベントが起きるか」を設定します。今回は1秒にしてみました。

「ボタンを1秒間押し続けるとゲージが右端まで溜まる」というイベントにしてみました。

<div class="charge" data-long-press-delay="1000"></div>

<div class="gauge"></div>
.charge {
  width: 300px;
  height: 100px;
  margin: 1.5rem auto;
  padding: 10px;
  border: 0;
  box-shadow: none;
  color: #ffffff;
  display: block;
  cursor: pointer;
  position: relative;
  background:#00a;
}

.charge::before {
  content: "";
  background-color: #fff;
  display: block;
  height: 3rem;
  width: 4rem;
  -webkit-mask: url("img/button-off.svg");
  mask: url("img/button-off.svg");
  -webkit-mask-size: cover;
  mask-size: cover;
  margin : auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
  
.charge[data-editing="true"]{
  background: #00f;
}
  
.charge[data-editing="true"]::before {
  content: "";
  background-color: #fff;
  display: block;
  height: 3rem;
  width: 4rem;
  -webkit-mask: url("img/button-on.svg");
  mask: url("img/button-on.svg");
  -webkit-mask-size: cover;
  mask-size: cover;
  margin : auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0; 
}

.gauge{
  position: relative;
  width: 100%;
  height: 20px;
  background: #eee;
}

.gauge:before{
  content: '';
  width: 100%;
  height: 20px;
  background: rgb(0,255,0);
  background: linear-gradient(90deg, rgba(0,255,0,1) 0%, rgba(255,255,0,1) 50%, rgba(255,0,0,1) 100%);
  position: absolute;
  left: 0;
  bottom: 0;
}

.gauge:after{
  content: '';
  width: 100%;
  height: 20px;
  background: #333;
  position: absolute;
  right: 0%;
  bottom: 0;
}

@-webkit-keyframes gaugeGo {
  0% {
    width: 100%;
  }
  50% {
    width: 50%;
  }
  100% {
    width: 0;
  }
}

@keyframes gaugeGo {
  0% {
    width: 100%;
  }
  50% {
    width: 50%;
  }
  100% {
    width: 0;
  }
} 

.charge[data-editing="true"] +.gauge:after{
  animation: gaugeGo 2s forwards;
  animation-timing-function: linear;
}

なんか微妙なものができましたが、いつかどこかで使いたいと思います。

 

まとめ

これでロッ〇バスターや波〇砲が作れますね!いや作れねーだろ

「押している間だけゲージが溜まる」「離したらゲージが空になる」ようにするにはどうしたらいいんでしょう。

この記事を書いた人
みやの
Web・DTP担当

Contact Us

ご意見、ご相談、料金のお見積もりなど、お気軽にお問い合わせください。

お問い合わせはこちら

TOP