1

I am posting this because I did not find any solution to this question so far.

I have already implemented my own codes as the solution, but I want to know if there are any better way of doing this.

Scenario: There is a list of div tags that are enclosed in a parent div tag, which presents you with a scrollbar to scroll through the list of divs.

Objective: The objective is to highlight the div tag that is next/closest to the scrollbar at any point in time while scrolling.

Here is the HTML code for the scenario:

<div id="main">
    <div id="container">
        <div>Text 1</div>
        <br/>
        <div>Text 2</div>
        <br/>
        <div>Text 3</div>
        <br/>
        <div>Text 4</div>
        <br/>
        <div>Text 5</div>
        <br/>
        <div>Text 6</div>
        <br/>
        <div>Text 7</div>
        <br/>
        <div>Text 8</div>
        <br/>
        <div>Text 9</div>
        <br/>
        <div>Text 10</div>
        <br/>
    </div>
</div>

Ths CSS code:

#main {
    width:100px;
    height:100px;
    overflow-y:auto;
}

Note that:

  1. when the scrollbar is at the top, the first div should be highlighted.
  2. when the scrollbar is in the middle, the div in the middle should be highlighted.
  3. when the scrollbar is at the bottom, the last div should be highlighted

Here is a JSFiddle for the above code

Ahs N
  • 8,233
  • 1
  • 28
  • 33
  • Here is the solution for getting scrollbar location : http://stackoverflow.com/questions/2481350/retrieve-scrollbar-position-with-javascript Based on scroll events you can set the div display –  Aug 14 '15 at 12:44
  • 2
    Read the scroll position and calculate which one you need? Btw. what's the middle div from the list of 10 divs? – Shomz Aug 14 '15 at 12:44
  • @Shomz Assume its the 5th div tag with text "Text 5" – Ahs N Aug 14 '15 at 12:46
  • @amitmahajan Getting the scrollbar position is easy, but then how would you locate the child _div_ closest to it and highlight it? :) – Ahs N Aug 14 '15 at 12:50
  • You can add class to your divs like top, mid and bottom. During scrollbar events you can add highlight css to these classes. –  Aug 14 '15 at 12:52
  • @amitmahajan and what about the _divs_ inbetween? Only _one_ div is to be highlighted at a time. Do post your solution, I'll accept the best answer :) – Ahs N Aug 14 '15 at 12:54
  • If its only single div to be updated then the div id's needs to be used along with div position (full box). This will need more javascript calculation to calculate the minimum distance of all the divs. You can write a script to display all 4 corners of div and its distances for all divs. Then get the one nearest. Try this jquery ui element https://jqueryui.com/position/ –  Aug 14 '15 at 13:01

2 Answers2

1

This is my possible solution—might appear a bit complicated, but it is actually quite simple. Before you start listening to the scroll position, you will need to establish:

  1. The relative position of each <div> element in the scrollable #main parent. This is computed by using the offset from the top and its height, so that we are using the bottom border of the element as the benchmark.
  2. The scrollable height of the #main parent.

You might want to recompute these values upon layout changes, DOM manipulations and etc, but I will leave that out now for the sake of simplicity.

After you have done that, you will have to listen to the scroll event and then determine the relative scroll position of the parent element (the value). Once that is done, you find the next immediate div shoe relative position (see point #1) exceeds this value, which you will highlight it.

// Get scrollable height and 
// You might want to perform this computation within event handlers that are triggered by: window resize, element resize, DOM manipulation, because scrollable height will change
var scrollableHeight = $('#main')[0].scrollHeight - $('#main').height();
$('#container div').each(function() {
    $(this).data('relPos', ($(this).position().top + $(this).height()) / $('#main')[0].scrollHeight);
});

// Listen to scorll event
$('#main').scroll(function() {
  
    // Get absolute scroll position
    var absScrPos = $(this).scrollTop();
    
    // Get relative scroll position
    var relScrPos = absScrPos/scrollableHeight;
    
    // Highlight the correct div
    $(this).find('#container > div')
    .removeClass('highlight')
    .filter(function() {
        return parseFloat($(this).data('relPos')) > relScrPos;
    })
    .first()
    .addClass('highlight');
});
#main {
    width:100px;
    height:100px;
    overflow-y:auto;
}
.highlight {
    background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
    <div id="container">
        <div>Text 1</div>
        <br/>
        <div>Text 2</div>
        <br/>
        <div>Text 3</div>
        <br/>
        <div>Text 4</div>
        <br/>
        <div>Text 5</div>
        <br/>
        <div>Text 6</div>
        <br/>
        <div>Text 7</div>
        <br/>
        <div>Text 8</div>
        <br/>
        <div>Text 9</div>
        <br/>
        <div>Text 10</div>
    </div>
</div>
Terry
  • 63,248
  • 15
  • 96
  • 118
  • Very good :D Thats exactly whats required! I'll wait some more to see what other solutions others come up with (if any), then mark the best answer :) – Ahs N Aug 14 '15 at 18:11
0
You have to do a couple of things.

1)listen when the scrolling stops
2)find the "closest" container
3)scroll to its top value, without triggering "the scroll end detection"

var items = $(".item");
var animating = false;

$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));
if (!animating) {
    $.data(this, 'scrollTimer', setTimeout(function() {
        items.each(function(key, value) {
            if ($(value).offset().top > $(window).scrollTop()) {
                animating = true;
        $('body').animate( { scrollTop: $(value).offset().top + 'px'}, 250);
                setTimeout(function() { animating = false; }, 300);
                return false;
            }
        });
    }, 200));
}

});

Sumanta736
  • 695
  • 3
  • 10