在JS中构建时间轴滑块

时间:2012-10-02 19:44:08

标签: javascript jquery

我正在制作时间轴,但我的滑块遇到了一些问题。在示例中(更新:http://jsfiddle.net/WMnsc/3/)每次我滑动绿色div时,div“holder”会沿着绿色div的方向滑动。持有者div在时间轴中包含每个li的div,代表一年。

我正在使用乘法来计算“持有者”div的速度,所以年份正确排列正在工作但我需要的是当绿色div滑动十年然后恢复时滑动减速它不是正常的速度。

从周日开始,我的脑子已经走了一千个,但我仍然无法弄清楚如何计算。

另外,如果你看一下jsfiddle例子,你会看到我正在根据拖动的方向递增/递减。告诉滑块的工作方式有效,但基于此的递增/递减总是关闭..............

1 个答案:

答案 0 :(得分:4)

零,

他们没有给你一个轻松的任务,但幸运的是,这是我真正喜欢解决的问题。它花了我一天中最好的一部分,我的工作很快。

这是我的测试页面,包含CSS,HTML和javascript - 这三个版本都是原版的修改版本:

<!DOCTYPE html>
<html>
<head>
<style>
#box {
    position: absolute;
    width: 400px;
    height: 400px;
    background-color: #e0e0c0;
    top: 100px;
    overflow: hidden;
}
#holder {
    position: absolute;
    width: auto;
    height: 400px;
}
.boxes {
    position: relative;
    width: 398px;
    height: 400px;
    border-right: 2px solid blue;
    float: left;
}
.year {
    position: relative;
    float: left;
    border-right: 1px solid blue;
    height: 13px;
    min-width: 8px;
}
.year:first-child {
    border-left: 1px solid blue;
}
#trackWrapper {
    position: relative;
    top: 10px;
    width: auto;
}
#trackWrapper .track {
    position: absolute;
    margin: 0;
    padding: 0;
    list-style-type: none;
    top: 21px;
    width: auto;
}
#trackWrapper .slider1, #trackWrapper .slider2 {
    position:absolute;
}
#trackWrapper .slider1 {
    background-color: green;
    width: 8px;
    height: 20px; 
    top: 0px;
    left: 0px;
}
#trackWrapper .slider2 {
    background-color: orange;
    width: 12px;
    height: 10px;
    top: 37px;
    left: 220px;
    /* 
    display: none; 
    */
}
#msg {
    position: absolute;
    left: 480px;
    top: 80px;
    height: 1.0em;
}
</style>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type='text/javascript'>
$(function() {
    function log(x){
        var logSwitch = false;
        if(logSwitch) { console.log(x); }
    }

    //Put numbers in the boxes for testing
    $(".boxes").each(function(i) {
        $(this).text(i);
    });

    function courseFineSlider($trackWrapper, $holder, sensitivityDivider) {
        var $slider1 = $trackWrapper.find(".slider1"),
            $slider2 = $trackWrapper.find(".slider2"),
            $track = $trackWrapper.find(".track"),
            $boxes = $(".boxes"),
            $year = $(".year");
        var $slider = null;
        var trackLength = $track.width();// - $year.width() / 2;
        var startX = null;
        var sliderOffSet = null;
        var _pos1 = 0;
        var ePos = 0;

        sensitivityDivider = (!sensitivityDivider) ? 10 : sensitivityDivider;

        $holder.width($boxes.outerWidth() * $boxes.length);
        var holderScale = $boxes.outerWidth() * ($boxes.length - 1);

        function hold(e) {
            log('hold');
            e.preventDefault();
            $slider = $(e.target);
            $(window).on('mousemove', $slider, move);
            startX = e.clientX;
            sliderOffSet = parseInt($slider.css('left'));
            _pos1 = getPos($slider1);
            e.returnValue = false;
        }
        function release(e) {
            if(!$slider) return;
            log('release');
            if($slider.get(0) === $slider2.get(0)) {//if it's the orange slider
                setPos($slider1, ePos);//adjust green according to any movement in orange
                setPos($slider2, 0.5, true);//recenter the orange slider
            }
            $slider = null;
            $(window).off('mousemove');
        }
        function move(e) {
            //console.log('move');
            e.preventDefault();
            var trueSliderX = e.pageX - $trackWrapper.get(0).offsetLeft;
            setPos($slider, applyLimits(0, trueSliderX / trackLength, 1));
            //$holder.css('left', shape(sliderPos()) + 'px'); // *** totally linear ***
            $holder.css('left', -holderScale * shape2(sliderPos()) + 'px'); // *** non-linear - slows down at the decade boundaries ***
        }

        // *** Equations ***
        function sliderPos() {
            var pos1 = getPos($slider1);//green position (0 to 1)
            var pos2 = getPos($slider2);//orange position (0 to 1)
            if($slider.get(0) === $slider1.get(0)) {//if it's the green slider
                ePos = applyLimits(0, (pos1 + (pos2 - 0.5) / sensitivityDivider), 1);
            }
            else {
                ePos = applyLimits(0, (_pos1 + (pos2 - 0.5) / sensitivityDivider), 1);
            }
            return ePos;//effective position of green, taking orange into account
        }

        var LINEAR = function(x1, y1) {//Namespace pattern to keep the $(function(){...}) closure uncluttered
            function Line(m, c) {//Constructor
                this.calc = function(x) {
                    return m * x + c;
                };
            }
            var m1 = y1/x1;
            var m2 = (1-y1)/(1-x1);
            var c1 = 0;
            var c2 = y1 - m2 * x1;
            return {
                x1: x1,
                y1: y1,
                line_1: new Line(m1, c1),
                line_2: new Line(m2, c2)
            };
        }(0.7, 0.90);// change these params as required. 
        /*
     * First param:  Determines the leading edge of the "sluggish zone". 0.7 is about right for the test data.
     * Second param: Determines the height of the two slopes at their intersection. ie. where steep changes to shallow. 
     * Try playing with the second param in the range 0.7 (completely linear) to 0.999999 (comatose). 
     * If the value of the 2nd param is set to something less than the first param, then the "zone" will be more sensitive rather than more sluggish.
         */

        // *** Shaping functions ***
        function shape(x) {
            return x;
        }
        function shape2(x) { //0...1
            var c = 4, //The number of cycles (decades)
                n = x * c,//0...4
                d = Math.floor(n),//"decade" //0, 1, 2, 3, 4
                r = n - d,//remainder //0
                y = (r < LINEAR.x1) ? LINEAR.line_1.calc(r) : LINEAR.line_2.calc(r),
                rtn = (y + d) / c;//unscaled return value
/*
            inspect([
                'x: ' + x.toFixed(2),
                '<br>n: ' + n.toFixed(5),
                '<br>d: ' + d,
                '<br>r: ' + r.toFixed(2),
                '<br>y: ' + y.toFixed(2),
                '<br>rtn: ' + rtn.toFixed(2)]);
*/
            return rtn;
        }

        // *** Utilitiy functions ***
        function applyLimits(min, x, max) {
            return Math.max(min, Math.min(max, x));
        }
        function getPos($sl) {
            return (parseInt($sl.css('left')) + $sl.width() / 2) / trackLength;
        }
        function setPos($sl, val, animate) {
            val = (val * trackLength) - ($sl.width() / 2);
            if(animate) { $sl.animate({left: val}, 'fast'); }
            else { $sl.css({left: val}); }
        }
        function inspect(arr){ //for debugging
            $("#msg").html(arr.join(', '));
        }

        setPos($slider1, 0);//center the green slider
        setPos($slider2, 0.5);//center the orange slider

        $slider1.on('mousedown', hold);
        $slider2.on('mousedown', hold);
        $(window).on('mouseup', release);
    }
    var x = new courseFineSlider($("#trackWrapper"), $('#holder'), 5);
});
</script>
</head>

<body>

<div id="msg"></div>
<div id="trackWrapper">
    <div class='slider1'></div>
    <div class='slider2'></div>
    <ul class='track'>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'>2000</li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'>2010</li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'>2020</li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'></li>
        <li class='year'>2030</li>
    </ul>
</div>

<div id='box'>
    <div id="holder">
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
        <div class="boxes"></div>
    </div>
</div>

</body>
</html>

<强> DEMO

你会看到我从你的设计简介和我的橙色辅助滑块实现了“缓慢区域”,这与我原来的概念略有不同(算术和变量范围变得相当激烈)。要在没有橙色滑块#slider2的情况下运行,只需在样式表中使用display:none设置样式。 javascript不需要更改。有一天,当设计师意识到他们制造了一个蠢货时,你可以透露奥兰治先生。

我没有时间详细描述它是如何工作的,但代码中有很多注释。

查看脚本底部的LINEAR命名空间,了解如何控制“缓慢区域”的位置和敏感度。

如果您需要我解释其他任何内容,请告诉我。