Zohaib Khan
Zohaib Khan

Reputation: 13

scroll on mouse movement

I have a div in my html and i have added overflow: scroll. I want it to scroll according to mouse movement. If the mouse is on left side of screen the scroll should be at the start. If the mouse is on the center of the screen the scroll should be in the center and same goes for right. Have a look at this website. You should see a top navigation bar of thumbnails which scrolls according to your mouse movements. I want the same effect exactly same. I have built it but it's not working as expected. If my mouse is in the center of screen the scrollbar is not the center but at the right side. have a look. Below is my code:

const gallery = document.getElementById('gallery');
const activeImage = document.getElementById('active-image');
const thumbnail = document.querySelector('.thumbnail');
const thumbnailWrapper = document.getElementById('thumbnail-wrapper');

thumbnailWrapper.addEventListener('mouseenter', handleMouseMove);
thumbnailWrapper.addEventListener('mousemove', handleMouseMove);

function handleMouseMove(e) {
  const noOfPics = Array.from(thumbnailWrapper.childNodes).length
  const clientX = e.clientX;
  const clientY = e.clientY;
  const width = window.innerWidth;
  const height = window.innerHeight;
  const wrapperWidth = thumbnail.clientWidth * noOfPics;
  const wrapperHeight = thumbnailWrapper.clientHeight;
  const percentX = clientX / width * 100;
  const percentY = clientY / height * 100;
  const scrollX = (wrapperWidth - width) * percentX / 100 - width / 2;
  thumbnailWrapper.scroll(scrollX, 0)
}
* {
  box-sizing: border-box;
  padding: 0%;
  margin: 0%;
}

#gallery {
  width: 100vw;
  height: 100vh;
  background-color: #303030;
  display: flex;
  flex-direction: column;
}

#thumbnail-wrapper {
  display: flex;
  /* justify-content: center; */
  overflow-x: scroll;
  padding: 0.5rem 1rem;
}

#thumbnail-wrapper::-webkit-scrollbar {
  /* display: none; */
  background-color: #000;
}

::-webkit-scrollbar-thumb {
  background: red;
}

.thumbnail {
  flex: none;
  width: 150px;
  height: 100px;
  border: 3px solid #303030;
  background-color: #202020;
  border-radius: 10px;
}

#active-image {
  flex: 1;
  position: relative;
  margin: 1rem;
}

.overflow-hidden {
  overflow: hidden;
}

.overflow-scroll {
  overflow: scroll;
}

.fit {
  height: 100%;
  margin: 0 auto;
}

.original {
  height: auto;
  position: absolute;
  top: 0%;
}
<div id="gallery">
  <div id="thumbnail-wrapper">
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
  </div>
  <div id="active-image" class="overflow-scroll">
    <img src="https://www.lifewire.com/thmb/_cH2YBd-iyPP1cqqj2WWXiCWudg=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/hdwallpapersnet-free-wallpaper-5919d3ca3df78cf5fa49bda3.jpg" alt="something went wrong" class="original">
  </div>
</div>

It think i am not calculation scrollX correctly i have tried many combination but can't get the behaviour i expected

Upvotes: 0

Views: 966

Answers (1)

IT goldman
IT goldman

Reputation: 19485

So basically it's a linear thing, starting from (0, 0) to the (clientWidth, maxScroll). So I calculate the linear formula then it's easy to put in a clientX and get an offsetX.

It might need some tweaking across the edges. Probably calculate the equation from 0+imageWidth to maxWidth-imageWidth. Have a play with it.

Update: I had a play with it. Now should be perfect.

function getLinearFunction(x1, y1, x2, y2) {
  var slope = (y2 - y1) / (x2 - x1);
  return function(x) {
    return slope * (x - x1) + y1;
  }
}


const gallery = document.getElementById('gallery');
const thumbnail = document.querySelector('.thumbnail');
const thumbnailWrapper = document.getElementById('thumbnail-wrapper');

thumbnailWrapper.addEventListener('mousemove', handleMouseMove);
// document.addEventListener('key')

function handleMouseMove(e) {
  const noOfPics = Array.from(thumbnailWrapper.childNodes).length
  const clientX = e.clientX;
  const clientY = e.clientY;
  const width = thumbnailWrapper.clientWidth;
  const height = thumbnailWrapper.clientHeight;
  const wrapperWidth = thumbnail.clientWidth * noOfPics;
  const wrapperHeight = thumbnailWrapper.clientHeight;
  const percentX = clientX / width * 100;
  const percentY = clientY / height * 100;
  const scrollLeft = thumbnailWrapper.scrollLeft
  var maxScrollLeft = thumbnailWrapper.scrollWidth - thumbnailWrapper.clientWidth;
  // when clientX = 0 you want scrollx = 0
  // when clientx = width you want scrollX = maxScrollLeft
  var foo = getLinearFunction(0, 0, width, maxScrollLeft);

  // EDIT: improvement: 
  var foo = getLinearFunction(0 + 150, 0, width - 150, maxScrollLeft);

  output.innerHTML = JSON.stringify({
    clientX,
    clientY,
    width,
    height,
    wrapperWidth,
    wrapperHeight,
    scrollLeft,
    maxScrollLeft
  }, null, 4)

  thumbnailWrapper.scroll(foo(clientX), 0)
}
* {
  box-sizing: border-box;
  padding: 0%;
  margin: 0%;
}

#gallery {
  width: 100vw;
  background-color: #303030;
  display: flex;
  flex-direction: column;
}

#thumbnail-wrapper {
  display: flex;
  /* justify-content: center; */
  overflow-x: scroll;
  padding: 0.5rem 1rem;
  background: yellow;
}

#thumbnail-wrapper::-webkit-scrollbar {
  /* display: none; */
  background-color: #000;
}

::-webkit-scrollbar-thumb {
  background: red;
}

.thumbnail {
  flex: none;
  width: 150px;
  height: 100px;
  border: 3px solid #303030;
  background-color: #202020;
  border-radius: 10px;
}

#active-image {
  flex: 1;
  position: relative;
  margin: 1rem;
}

.overflow-hidden {
  overflow: hidden;
}

.overflow-scroll {
  overflow: scroll;
}

.fit {
  height: 100%;
  margin: 0 auto;
}

.original {
  height: auto;
  position: absolute;
  top: 0%;
}
<div id="gallery">
  <div id="thumbnail-wrapper">
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
    <div class="thumbnail"></div>
  </div>
</div>
<pre id="output"></pre>

Upvotes: 2

Related Questions