ゴミ溜め@技術系日常系雑文

主にWeb技術やそのほかつまづいたこととか引っかかって調べたこととかをまとめてます。

はてなダイアリーから引っ越しました。)

最低限文化的な階調機能付きスライダー

404 Blog Not Found:DHTML - 最低限文化的なスライダーの実装
http://trackback.blogsys.jp/livedoor/dankogai/51733122
で記述されてたスライダーに、階調機能をつけた。

なんかIE7で動かないような気がするけど気のせいかな。

動作デモはこちら

<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title></title>

        <style>
            .slider   { 
                -webkit-user-select: none;
                -webkit-tap-highlight-color: transparent;
                border:inset 1px; height: 2em;
            }
            .slider > div {
                height:100%;
            }
            #status > dt {
                border-top: 2px solid #909090;
                margin-top: 5px;
            }
        </style>

    </head>
    <body>
        <div style="border:outset 1px; padding:0.5em">
            <dl>
                <dt>Red</dt>
                <dd><div id="rslider" class="slider"><div style="background-color:#f00;">&nbsp;</div></div></dd>

                <dt>Green</dt>
                <dd><div id="gslider" class="slider"><div style="background-color:#0f0;">&nbsp;</div></div></dd>

                <dt>Blue</dt>
                <dd><div id="bslider" class="slider"><div style="background-color:#00f;">&nbsp;</div></div></dd>

                <dt>RGB</dt>
                <dd>
                <div id="rgb" class="slider"></div>
                </dd>
            </dl>
        </div>

        <script>

            // 各種設定。
            var setting = {
                tone : 5,   // スライドの階調:falseまたは任意の正の数
                initial: {
                    red   : "100%",
                    green : "80%",
                    blue  : "20%"
                }
            };

            // 数字をゼロ埋めする。
            // 参考 : http://saboten009.blogspot.com/2009/04/javascript0.html
            function formatNum(keta, num) {
                var src = new String(num);
                var cnt = keta - src.length;
                if (cnt <= 0) return src;
                while (cnt-- > 0) src = "0" + src; return src;
            }

            // IE〜8でxEventListenerが使えない仕様の回避。
            var eventListener = {
                add: (function(w){
                    return w.addEventListener
                        ? function(obj, evt, func, bool) { obj.addEventListener(evt, func, bool) }
                        : w.attachEvent
                        ? function(obj, evt, func, bool) { obj.attachEvent("on"+evt, func) }
                        : function(obj, evt, func, bool) { obj["on"+evt] = func };
                })(window),
                remove: (function(w) {
                    return w.removeEventListener
                        ? function(obj, evt, func, bool) { obj.removeEventListener(evt, func, bool) }
                        : w.detachEvent
                        ? function(obj, evt, func, bool) { obj.detachEvent("on"+evt, func) }
                        : function(obj, evt, func, bool) { delete pbj["on"+evt] };
                })(window)
            };

            // IEでgetBoundingClientRectの値がずれる,widthがない等を修正。
            // 参考 : http://d.hatena.ne.jp/terurou/20080223/1203705170
            var getRect = (function(elem) {
                var rect = elem.getBoundingClientRect();

                var pageBorderLeft = document.body.scrollLeft
                || document.documentElement.scrollLeft;
                var pageBorderTop  = document.body.scrollTop
                || document.documentElement.scrollTop;

                return {
                    left  : rect.left   - pageBorderLeft,
                    top   : rect.top    - pageBorderTop,
                    right : rect.right  - pageBorderLeft,
                    bottom: rect.bottom - pageBorderTop,
                    width : rect.right  - rect.left,
                    height: rect.bottom - rect.top
                }
            });

            (function(d){

                var addSliderEvents = function(me, cb){
                    var move, mdown, mmove, mup, tstart, tmove, tend;
                    move = function(clientX, rect){

                        var width = clientX - rect.left
                            unit_with = rect.width / setting.tone;

                        if     (width<0)          width = "0%";
                        else if(rect.width<width) width = "100%";
                        else {
                            if (!setting.tone && setting.tone==0) {
                                width = width/rect.width*100 +"%";
                            }
                            else {
                                width = ( Math.floor(width/unit_with) * unit_with ) / rect.width * 100 + "%";
                            }
                        }
                        me.firstChild.style.width = width;
                        cb();
                    };
                    mdown = function(ev){
                        eventListener.add(d, 'mousemove', mmove, false);
                        eventListener.add(d, 'mouseup', mup, false);
                        mmove(ev);
                    };
                    mmove = function(ev){
                        move(ev.clientX, getRect(me));
                    };
                    mup = function(ev){
                        eventListener.remove(d, 'mousemove', mmove, false);
                        eventListener.remove(d, 'mousedown', mup, false);
                    };
                    eventListener.add(me, 'mousedown', mdown, false);

                    tstart = function(ev){
                        eventListener.add(d, 'touchmove', tmove, false);
                        eventListener.add(d, 'touchend', tend, false);
                        tmove(ev);
                    }
                    tmove = function(ev){
                        ev.preventDefault();
                        move(ev.touches[0].clientX, me.getBoundingClientRect());
                    };
                    tend = function(ev){
                        eventListener.remove(d, 'touchmove', tmove, false);
                        eventListener.remove(d, 'touchend', tend, false);
                    };
                    eventListener.add(me, 'touchstart', tstart, false);
                };
            
                var changecolor = function() {

                    var rgb = d.getElementById('rgb');
                    var bgcolor = (function(bg) {
                        for(var i=0,rgb=['r','g','b']; i<rgb.length; i++ ) {
                            bg+= Math.round( document.getElementById(rgb[i]+'slider')
                            .firstChild.style.width.replace(/%/,'') / 100 * 255 ) + ',';
                        }
                        return ('rgb('+bg.replace(/,$/,')'));
                    })('');
                    rgb.style.backgroundColor = rgb.innerHTML = bgcolor;
                };
                
                for(var i=0, rgb=['r','g','b']; i < rgb.length; i++ ) {
                    addSliderEvents(d.getElementById(rgb[i] + 'slider'), changecolor);
                }

                // 初期化。
                window.onload = function() {

                    if (setting.initial.red)
                        document.getElementById("rslider").firstChild.style.width = setting.initial.red;
                    if (setting.initial.green)
                        document.getElementById("gslider").firstChild.style.width = setting.initial.green;
                    if (setting.initial.blue)
                        document.getElementById("bslider").firstChild.style.width = setting.initial.blue;

                    changecolor();
                };

            })(document);
        </script>
    </body>
</html>