レベル評価のためのスナップ式スライドバーの作成

顧客に要望を尋ねる時、YESかNOの二者択一ではなく、例えば、「とても悪い」と「とても良い」の間のどれぐらいのレベルですか、と尋ねたい時はしばしばあります。

「悪い」「良い」に限らず、「シンプル」「複雑」や、「単色」「カラフル」のどちらのデザインを希望ですかというような場合もあります。

そのような場合に、WEBサイト上で活用してもらうための部品として、このスライドバーを作りました。

整数値のところごとにピタリと止まるスナップを設定しているので、仮に「スナップ式スライドバー」と名付けさせていただきました。

色々な作り方があるかもしれませんが、ここでは、JQueryのdraggableとdroppableを使った方式をご紹介させていただきます。

JQueryを利用していますので、あらかじめJQueryを読み込んでおく必要があります。

“jquery.js”、”jquery-ui.css”、”jquery-ui.min.js”、”jquery.ui.touch-punch.min.js”を予め読み込んでおいてください。(※minはついていなくても良いです。)

スマホでも表示するため、次のようなviewportの設定もあった方が良いです。

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

テーブル枠を設定

まず、styleの設定です。

あまり整っていないかもしれませんが、適宜修正してください。

<style>
        .wrap {margin: 10%; margin-bottom: 20px; position: relative; width: 80%; height: 50px;}
        table {position: absolute; top: 0; left: 0; width: 100%; height: 25px;}
        table th {text-align: center;}
        .drop {height: 25px; width: 3%;}
        .space {height: 25px; width: 6%;}
        .ind {width: 100%; height: 25px; text-align: center; background: #5FC; border: 1px #333 solid; z-index: 2;}
        .rule {position: absolute; top: 35px; left: 0; width: 100%; height: 5px; background: #CCC;}
        .textboxlabel {margin-left: 70%; height: 30px; width: 10%; font-size: 22px; vertical-align: top; line-height: 35px;}
        .textbox {display: inline-block; height: 30px; width: 10%; font-size: 22px; text-align: center; border: 1px #333 solid;}
    @media screen and (max-width: 479px) { 
        .drop {width: 6%;}
        .space {width: 3%;}
        .wrap {margin: 2%; margin-top: 100px; width: 96%;}
        .textboxlabel {margin-left: 50%; width: 25%;}
        .textbox {width: 25%;}
    }
</style>

ここでは、一般的な形で作成し、後からスマホ用に手直しが必要なCSSだけ一部上書きいたました。

「@media screen and (max-width: 479px) { }」がそれです。

次に、表示のHTML部分の説明です。

<body>
<div class="wrap">
<table>
    <tr>
        <th>-5</th><th></th><th>-4</th><th></th><th>-3</th><th></th><th>-2</th><th></th><th>-1</th><th></th><th>0</th><th></th><th>1</th><th></th><th>2</th><th></th><th>3</th><th></th><th>4</th><th></th><th>5</th>
    </tr>
    <tr>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"><div class="ind"></div></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
        <td class="space"></td>
        <td class="drop"></td>
    </tr>
</table>
<div class="rule"></div>
</div>

<span class="textboxlabel">評価点</span><div class="textbox">0</div>
</body>
</html>

テーブル枠内で動くように、-5点から5点までの数字の入った一行目と、実際にスライドバーの動く二行目を作ります。

二行目は、tdタグを用いて、クラス名を「drop」と「space」の互い違いに設定しています。

「drop」は、四角のボックス(ここでは仮に「インデックスバー」と呼びます)がドロップ可能な枠、「space」はドロップできない枠として指定するためです。

なお、前後しますが、インデックスバーがスライドする横棒は、最後のクラス名ruleのところで作成しています。

スライドバーを覆うクラス名wrapの要素をposition: relativeにして、横棒はposition: absoluteで上書きしました。

この関係でインデックスバー indのz-index: 2としてボックスが横棒の下にならないようにしています。

JQueryで移動

<script>
$(function() {
    $('.ind').draggable({snapMode: 'inner', snap: '.drop', snapTolerance: 35, revert: "invalid", containment: 'table'});
    $('.drop').droppable({
        drop: function(ev, ui) {
            ele=ev.target;
            index=$(ele).index();
            num=index/2-5;
            $('.textbox').text(num);
        }
    });
});
</script>

JQueryの部分は、そんなに長くありません。

ドラッグする方のボックス(ind)にはdraggableを、ドロップする方の枠(drop)にはdroppableを指定します。

ドラッグの方には、snapMode、 snap、snapTolerance、revert、containmentの指定をしています。

snapを指定すると、枠線にピタッと吸着してくれます。

snapMode: ‘inner’を指定すると、内側だけに吸着するようになります。これがないと枠の外側にも吸着しますので、ここの目的にはそぐいません。

snapToleranceは、スナップが始まる許容幅といったところでしょうか。大きい数字だと、遠くからでも吸い寄せられていきます。

revertでは、ドロップできなかった場合に、元に戻るようにできます。

containmentは、ドラッグで動ける範囲の指定です。

この辺りは、必要に応じて、検索してマニュアルなどに書いてあるものを試してみてください。

私も勘で色々試してみただけです(笑)。

一方、dropの方は、dropした場合の関数を入れ込んでいます。

これは、-5から5点までの評価値を読み取る必要があるために、後から付け足しました。

動くだけなら、droppable()だけで何も入れになくても大丈夫のはずです。

ev.targetでドロップしたセル要素が取り出せるので、そのtd要素が全体の何番目であるかをindex()で取り出します。(※最初はゼロになります。)

セルはdropが11個、spaceが10個ありますから、レベルの点数に一致するように「num=index/2-5」の計算をしてボックスに代入しています。

まとめ

いかがでしたか。

このようなスライドバーを活用する機会はそんなに多くないかもしれませんが、draggableとdroppabeと組み合わせて様々なことができそうだと感じられたのではないでしょうか。

dragの方にもstartなどのイベントが用意されていますので、ここのdroppableのdropのような使い方をすれば、さらに高度なことが可能になります。

ev.targetのidを読み取ったりすれば、様々に活用でできるわけです。

ぜひ、この機会にドラッグ&ドロップにトライしてみてください。