70
63

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人開発エンジニア応援 - 個人開発の成果や知見を共有しよう!-

ゲームなどでよく見る「長押しのボタン」のUIをWEBで表現してみた

Last updated at Posted at 2023-10-07

はじめに

スマホゲームやSwitchなどのゲームのUIでよく見る、「長押しボタン」をWEB画面で実装します。

使う技術としては、HTMLCSSJavaScriptだけで、JavaScriptのライブラリや画像やSVGは使いません。

長押しボタンと言ってもイメージが付かないと思いますので、完成系のGifを用意しました。(なぜか、WEBではあまり見かけないUIですよね...)

Animation.gif

実装

1. メータ部分の作成

まずは、メータ部分を作成するのですが、divタグを使って円を作成します。
background-imageconic-gradientを指定して、円グラフのような見た目ができるスタイルを使っています。

html
<div id="outer_circle"></div>
css
#outer_circle {
    position: relative;
    margin-right: auto;
    margin-left: auto;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background-image: conic-gradient(#d5525f 0% 0%, #d9d9d9 0% 100%);
}

conic-gradientの第二引数または第三引数の割合を増やしていくと、以下のような動きになります。(今回はJavaScript側で動きを制御したいので、CSSのアニメーションは使いません)

Animation4.gif

2. ボタン部分の見た目を作成

次は、ボタン部分の見た目を完成させます。
先ほど作成した、outer_circledivタグinner_circleを作成し、中に少し小さい円を作成します。

html
<div id="outer_circle">
    <div id="inner_circle"></div>
</div>
css
#inner_circle {
    text-align: center;
    background-color: #676767;
    width: 80px;
    height: 80px;
    border-radius: 50%;
    position: relative;
    top: 10px;
    left: 10px;
}

見た目はこれで完成になります。まだ、JavaScript部分を作っていないのでクリックしても動作しませんが、疑似的に動かすと以下のような感じになります。

Animation4.gif

3. 長押しの処理を実装

次にボタンの長押し時の処理をJavascriptで実装します。
longPressのオブジェクトを作成し状態を管理しており、長押し中にconic-gradientの割合を計算し画面に随時反映しています。
(下記処理は、画面読み込み後に実行されるようにする必要があります)

javascript
const longPress = {
    // プロパティ
    innerEl: document.getElementById("inner_circle"), //内側の円
    outerEl: document.getElementById("outer_circle"), //外側の円
    second: 3, //長押しの時間
    count: 0,
    timerId: 0,
    interval: 10,

    // 初期化処理
    init: function(param){
       // イベントリスナー
        this.innerEl.addEventListener('pointerdown', ()=>{this.start()}, false);
        this.innerEl.addEventListener('pointerup', ()=>{this.end()}, false);
    },

    // 長押し中の処理
    start: function(){
        this.timerId = setInterval(()=>{
            this.count++;
            this.outerEl.style.backgroundImage = 'conic-gradient(#d5525f 0% '+ this.count/this.second +'%, #d9d9d9 0% 100%)';

            if (this.count / 100 === this.second) {
                alert('ボタンを' + this.second + '秒長押ししました!');
                this.end();
            }
        }, this.interval);
    },

    // 長押し中断の処理
    end: function(){
        clearInterval(this.timerId);
        this.count = 0;
        this.outerEl.style.backgroundImage = 'conic-gradient(#ff0019 0% 0%, #d9d9d9 0% 100%)';
    }
};

//longPressの初期化
longPress.init();

実際に長押し操作を行うと以下のような動作になります。

Animation4.gif

4. バグについて

実は、上記コードだと考慮していない操作があり、長押しメーターが止まらないというバグがあります。バグが発生する操作としては以下の通りです。

  • 長押し中に右クリック
  • 長押し中にマウスのポインタが外れる

initメソッド内に下記の処理を追記することで解消されます。

javascript
this.innerEl.addEventListener('pointerout', ()=>{ this.end() }, false);
this.innerEl.oncontextmenu = () => {return false;}

おわりに

長押しのボタンをHTML・CSS・JavaScriptで実装してみました。

今回は、円グラフのようなUIで作成しましたが、カスタマイズすることで棒グラフが伸びていくUIや水が溜まっていくようなUIにすることも可能かと思います。

また、longPressのオブジェクトを使って長押しメーターの色タイマーの時間や長押しし終わったときにコールバック関数を使って特定の処理を実行することも可能です。下記リンクが、パラメータを色々とカスタマイズできるようにしたサンプルです。(気になった方は、ぜひ触ってみてください)

ここまで見ていただきありがとうございました。

70
63
3

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
70
63

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?