Skip to content
Advertisement

smooth scroll to mouse position on first mousemove

I created an area that scrolls automatically to the mouseposition with the mousemove() function. The problem is that the first mousemove in that area, jumps directly to the position with no smooth scroll.

How can I realize that? It should just be the first and after it, it should scroll throught the css property translate3d.

I created a pen: https://codepen.io/rwillhaus/pen/LYrPNod

var docWidth = $("body").width(),
    slidesWidth = $("#stage").width(),
    rangeX = slidesWidth - docWidth,
    $divStage = $("#stage");

$(window).on("resize", function () {
    var docWidth = $("body").width(),
         slidesWidth = $("#stage").width(),
         rangeX = slidesWidth - docWidth;
});

initialScroll = true;

$(document).mousemove(function (e) {
          var mouseX = e.pageX;
          var percentMouse = mouseX / (docWidth / 2);
          var offset = percentMouse * slidesWidth - percentMouse * docWidth;
  
          //check if left or right direction
          var sl = offset;
  
          $divStage.css({
              transform: "translate3d(" + -(offset / 2) + "px,0,0)",
              "-webkit-transform": "translate3d(" + -(offset / 2) + "px,0,0)",
              "-moz-transform": "translate3d(" + -(offset / 2) + "px,0,0)",
              "-ms-transform": "translate3d(" + -(offset / 2) + "px,0,0)",
              "-o-transform": "translate3d(" + -(offset / 2) + "px,0,0)",
          });
}); 

I tried to add an “transition: transform 0s ease-in;” in the CSS but the problem is that the effect still lasts after the first smooth scroll to the mouse pointer.

Thanks

Advertisement

Answer

I think there may be a misunderstanding about the smooth scroll thing in your example app.

Nothing in the code is smooth scroll. It all jumps to the position it should be in immediately.

It only appears like smooth scrolling when the mouse is moving inside the target zone. That’s because the mouse can only move a little bit before the position of the div is updated in the screen (probably at 60 frames per second).

The same exact behaviour happens on mouseenter or first mousemove. The difference is that the amount the mouse has moved is far bigger between a mouseenter and mouseexit than between two mousemove events. So it appears to jump unnaturally.

How to make it smooth scroll

To make it truly smooth scroll you’d have to change the transition property in your CSS to more than 0. E.g. #stage {transition: 0.1s ease-in;}.

Back to the drawing board

I’m not sure if the solution above is what you want. You might have to go back to the drawing board and think about how your program should work. E.g. I can imagine you might want something like:

  • On mouseenter, for the next 1 second the div should appear to be smooth scrolling.
  • Otherwise, there should be no smooth scrolling.

I think you might have to control the “smooth scrolling behaviour” with JavaScript rather than CSS. Otherwise the div might jump weirdly when you change the CSS between transition: 0.2s ease-in and transition: 0s ease-in.

You could try something like this:

// add this somewhere at the top of your code
const stageNode = document.querySelector('#stage');
const msSmoothScrollingOnMouseEnter = 200; // milliseconds. Change this to what you like.

let hasMouseMoveEventFired = false;
let initialMouseMoveDate = new Date();

const getRemainingSmoothScrollingTime = () => {
  return Math.max(
    msSmoothScrollingOnMouseEnter - (new Date() - initialMouseMoveDate),
    0,
  ); // get milliseconds remaining for smooth scrolling
};

$(document).mouseenter(function () {
  initialMouseMoveDate = new Date();
});

$(document).mousemove(function (e) {
  if (!hasMouseMoveEventFired) {
    hasMouseMoveEventFired = true;
    initialMouseMoveDate = new Date();
  }
  const remainingMsSmoothScrollingTime = getRemainingSmoothScrollingTime();
  stageNode.style.transition = `${remainingSmoothScrollingTime / 1000}s linear`;
  // ... rest of the code goes here
});

The mouseenter code sets the time of the last mouseenter. The getRemainingSmoothScrollingTime functions returns the milliseconds of smooth scrolling time remaining. The mousemove handler changes the transition property in CSS to the value of smooth scrolling time remaining.

Edit: Modified the example code to answer the problem of the “first mouse move” rather than mouseenter and mouseexit. Edit 2: Fixed a typo in code.

Advertisement