vis.js-timeline-vertical-scroll

A work-around to the vis.js timeline where focusing on an item doesn't scroll vertically if it is off the screen.

by Chitkala More

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.1/vis.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.1/vis.min.js"></script>
<button id="nextFocus">Next Focus</button>
<button id="prevFocus">Previous Focus</button>
<br/>
<button id="next">Next Workaround</button>
<button id="prev">Previous Workaround</button>
<br/>

<div style="margin-top: 10px; margin-bottom: 10px;">
  <input type="text" id="idInput" value="g0_0" style="width: 50px; display: block;" />
  <button id="scrollToButton">Scroll To This ID (Workaround)</button>
</div>
<div id="visualization"></div>

JavaScript

var groups = [];
var items = [];
var groupItems = {};

for (var g = 0; g < 10; g++) {
  groups.push({
    id: g,
    content: "Group " + g
  });

  groupItems[g] = [];

  for (var i = 0; i < 10; i++) {
    items.push({
      id: "g" + g + "_" + i,
      content: "g" + g + "_" + i,
      group: g,
      start: "2014-01-20"
    });

    groupItems[g].push(items[items.length - 1]);
  }
}

var container = document.getElementById('visualization');
var options = {
  editable: false,
  stack: true,
  height: 300,
  verticalScroll: true,
  groupOrder: 'id'
};

var timeline = new vis.Timeline(container, items, groups, options);

var groupIndex = 0;
var itemIndex = 0;

var timelineFocus = function(id) {
  timeline.setSelection(id);
  timeline.focus(id);
};

var moveToItem = function(direction, fn) {
  itemIndex += direction;
  groupIndex += direction;

  if (groupIndex < 0) {
    groupIndex = groups.length - 1;
  } else if (groupIndex >= groups.length) {
    groupIndex = 0;
  }

  var items = groupItems[groupIndex];

  if (itemIndex < 0) {
    itemIndex = items.length - 1;
  } else if (itemIndex >= items.length) {
    itemIndex = 0;
  }

  var id = items[itemIndex].id;

  fn.call(timeline, id);
}

$("#nextFocus").on("click", function() {
  moveToItem(1, timelineFocus);
});
$("#prevFocus").on("click", function() {
  moveToItem(-1, timelineFocus);
});

/* Work-Around */
// This is a quick-and-dirty animation for scrolling
var animateScroll = function(from, to, duration, timeline) {
  var initTime = new Date().valueOf();
  //var duration = 500;
  var easingFunction = function(t) {
    return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t
  };

  var defer = $.Deferred();

  var next = function() {
    var now = new Date().valueOf();
    var time = now - initTime;
    var ease = easingFunction(time / duration);
    var done = time > duration;
    var s = done ? to : (from + (to - from) * ease);

    timeline._setScrollTop(-s);
    timeline._redraw();

    if (!done) {
     ...