James Manes
James Manes

Reputation: 526

Faking Scrollbars With JavaScript or jQuery

I am currently working on a custom table that I have made with knockoutJS and jQuery. Because this table is possibly dealing with 1,000 - 100,000 rows, I have implemented my own virtual scrolling technique in KnockoutJS to ensure that only 35 or so elements are visible at a time (depending on viewport height). When scrolling with the scroll-wheel, the table's tr elements are dynamically updated in-place to give the illusion of scrolling. This much works.

However, I need to think of a way to implement fake scrollbars. I am needing a fake scrollbar that does not actually scroll the page, but rather calls a function when dragged so that I can re-direct that info to my knockoutJS virtual scroller for updating the tr elements.

I have looked a bit into jScrollPane, but am not sure if it will support what I want. Does anyone else have experience with this?

Thanks.

Upvotes: 1

Views: 718

Answers (1)

Roy J
Roy J

Reputation: 43899

Here's a rough demo of doing it with actual scrollbars and scrolling. You can see it better if you make the snippet full-screen.

The idea is that you have a window of visible items, somewhat like you have already, but it is displayed in fixed position over a tall, scrolling window. When the window is scrolled, you find its new position and use that to recompute which of your items should be visible.

As it is here, I had to put in a fudge factor to get to the last items in the list. I did say it's a "rough" demo.

const vm = {
  items: ko.observableArray([]),
  percent: ko.observable(0),
  visibleItems: ko.pureComputed(() => {
    const start = Math.floor(vm.percent() * vm.items().length);

    return vm.items.slice(start, start + 22);
  })
};

for (let i = 0; i < 5000; ++i) {
  vm.items.push(i);
}

ko.bindingHandlers.scroll = {
  init: (el, va) => {
    let top = el.parentNode.scrollTop;
    const percent = va();

    setInterval(() => {
      const newTop = el.parentNode.scrollTop;

      if (newTop !== top) {
        percent(newTop / (0.859 * el.parentNode.scrollHeight));
        top = newTop;
      }

    }, 50);
  }
};

ko.applyBindings(vm);
.scroll-me {
  background-color: rgba(255, 30, 30, 0.3);
  height: 3000px;
}
.all-you-see {
  background-color: white;
  width: 100%;
  position: fixed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="scroll-me" data-bind="scroll: percent">
  <div class="all-you-see">
    <div data-bind="foreach:visibleItems">
      <div data-bind="text:$data"></div>
    </div>
  </div>
</div>

Upvotes: 1

Related Questions