Rourke McLaren Rourke McLaren - 4 months ago 18
jQuery Question

Built a scroll controller, need to reverse it

My code allows scrolling vertically in the bottom section to control scrolling horizontally in the top section.

My jsfiddle

You'll see the colors shift through a gradient. Works pretty well. Problem is that I can't quite seem to get the inverse to work. Scrolling horizontally in the top controls scrolling in the bottom.

Any ideas?

Here's the script that makes it work:

// Add event listener for scrolling
$("#bottom").on("scroll", function bottomScroll() {
var scrolledleft = parseInt($("#bottom").scrollTop()) * 1;
console.log(scrolledleft + scrolledright)
$("#top").scrollLeft(scrolledleft + scrolledright)
})

//Move right column to bottom initially
$("#top").scrollLeft($("#top").height())

//Get actual distance scrolled
var scrolledright = parseInt($("#top").scrollLeft())

Answer

Your event handlers need to temporarily cancel each other so that they don't both fire at once. You want to calculate your position percentage based on the current scrollLeft / (width of child div - width of container), then apply that percentage to the other element, and likewise for top/height. Also I changed the height of #top to 50% in CSS.

var handler = function (e) {
  var src = e.target;
  
  // the first element that triggers this function becomes the active one, until it's done
  if (!activeScroller) activeScroller = src.id;
  else if (activeScroller != src.id) return;
  
  var $b = $("#bottom");
  var $t = $("#top");

  var scrollH = $("#bottom-content").height() - $b.height();
  var scrollW = $("#top-content").width() - $t.width();

  var scrollPct = 0;

  if (src.id == "top") {
    if (scrollW > 0) {
      scrollPct = $t.scrollLeft() / scrollW;
    }

    $b.scrollTop(scrollH * scrollPct);
  } else {
    if (scrollH > 0) {
      scrollPct = $b.scrollTop() / scrollH;
    }

    $t.scrollLeft(scrollW * scrollPct);
  }
  
  // give all animations a chance to finish
  setTimeout(function () { activeScroller = ""; }, 100);
};
var activeScroller = "";
$("#top,#bottom").on("scroll", handler);
#top {
  position: absolute;
  margin: auto;
  top: 0;
  right: 0;
  left: 0;
  width: 100%;
  height: 50%;
  position: fixed;
  overflow: auto;
  background: red;
}

#top-content {
  height: 100%;
  width: 2000px;
  background: linear-gradient(90deg, red, blue);
}

#bottom {
  position: absolute;
  margin: auto;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 50%;
  position: fixed;
  overflow: auto;
  background: green;
  z-index: 100;
}

#bottom-content {
  height: 2000px;
  width: 100%;
  background: linear-gradient(0deg, orange, green);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="top">
  <div id="top-content"></div>
</div>
<div id="bottom">
    <div id="bottom-content"></div>
</div>