Horizontal scroll on mouseMove - wide div in smaller div with overflow:hidden (Can't get the math to work)
Asked Answered
M

2

9

I'm trying to make a "line" of image thumbs, where it scrolls on mousemove. And I got it to work, but my problem now is that i wanted to make a "padding" on the sides so I doesn't have to have the mouse all the way out to the sides to see the first/last thumb. But I really really can't get it to work :/

This is the script I have now:

// MouseMove scrolling on thumbs
var box = $('.thumbs-block'),
    innerBox = $('.thumbs'),
    lastElement = innerBox.find('a:last-child');

var offsetPx = 100;
var boxOffset = box.offset().left;

var boxWidth = box.width() /* - (offsetPx*2)*/;
var innerBoxWidth = (lastElement[0].offsetLeft + lastElement.outerWidth(true)) - boxOffset /* + (offsetPx*2)*/;

scrollDelayTimer = null;
box.mousemove(function (e) {
    console.log('boxWidth: ' + boxWidth + '   innerBoxWidth: ' + innerBoxWidth + '   box.scrollLeft(): ' + box.scrollLeft());

    var mouseX = e.pageX;
    var boxMouseX = mouseX - boxOffset;

    if ((boxMouseX > offsetPx) && (boxMouseX < (boxWidth - offsetPx))) {
        var left = (boxMouseX * (innerBoxWidth - boxWidth) / boxWidth) /* - offsetPx*/;

        clearTimeout(scrollDelayTimer);
        scrollDelayTimer = setTimeout(function () {
            scrollDelayTimer = null;
            box.stop().animate({
                "scrollLeft": left
            }, {
                queue: false,
                duration: 500,
                easing: 'linear'
            });
        }, 10);
    }
});

There are some of the places I've tried adding the offset (commented out inline), some of it gets it working in one end but not the other :/

I'm pretty sure it's a problem in the math, but I can't figure out what I should do :/

Here's a jsFiddle: http://jsfiddle.net/6CJfs/1/

I hope I made my problem clear enough, not sure how to explain it otherwise, and hope someone can help :)

Marcelenemarcelia answered 17/4, 2013 at 2:46 Comment(1)
just out of my head what you could do is telling it somehow that the innerbox is smaller than what it is, and then add max values to scrolleft accordinglyAzobenzene
C
22

You script is not smooth, so I modified it completely (sorry :)
with a really simple approach:

$(function() {

  const $bl = $(".thumbs-block"),
    $th = $(".thumbs"),
    blW = $bl.outerWidth(),
    blSW = $bl.prop("scrollWidth"),
    wDiff = (blSW / blW) - 1, // widths difference ratio
    mPadd = 60, // Mousemove Padding
    damp = 20; // Mousemove response softness

  let posX = 0,
    mX2 = 0, // Modified mouse position
    mmAA = blW - (mPadd * 2), // The mousemove available area
    mmAAr = (blW / mmAA), // get available mousemove fidderence ratio
    itv = null;

  const anim = () => {
    posX += (mX2 - posX) / damp; // zeno's paradox equation "catching delay"    
    $th.css({
      transform: `translateX(${-posX * wDiff}px)`
    });
  };

  $bl.on("mousemove", function(e) {
    const mouseX = e.pageX - $(this).prop("offsetLeft");
    mX2 = Math.min(Math.max(0, mouseX - mPadd), mmAA) * mmAAr;
  }).on("mouseenter", function(e) {
    itv = setInterval(anim, 10);
  }).on("mouseleave", function() {
    clearInterval(itv);
  });

});
.thumbs-block {
  position: relative;
  overflow: hidden;
  max-width: 100%;
}

.thumbs-block .thumbs {
  display: flex;
  flex-flow: row nowrap;
}
<div class="thumbs-block">
  <div class="thumbs">
    <a class="thumb"><img src="http://placehold.it/120x120/0bf&text=01" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/f0b&text=02" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/bf0&text=03" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/b0f&text=04" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/fb0&text=05" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/0fb&text=06" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/0bf&text=07" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/f0b&text=08" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/bf0&text=09" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/b0f&text=10" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/fb0&text=11" /></a>
    <a class="thumb"><img src="http://placehold.it/120x120/0fb&text=12" /></a>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
Chism answered 17/4, 2013 at 13:16 Comment(5)
Sorry for the late answer, have been a busy ;) But it looks really awesome :P thanks so much for the help, hope I can implement it in my project later today ;)Marcelenemarcelia
I've just testet it in my project, works like a charm :P Thanks for your help, voted up and accepted ;)Marcelenemarcelia
Help needed. Its not getting proper width on resizing the window thus some the first and end div get hide. Any fix to it?Thrilling
Can this script be changed to work with various carousels in the same page? If so, how?Obvert
@user1991185 you can wrap it inside an .each() but I'd suggest to create a flexible and reusable a jQuery plugin: learn.jquery.com/plugins/basic-plugin-creation ... if that's over the top, sorry for not being of much help, I have no time currently to create a snippet.Chism
P
-1
var $imgWrapper = $(".js-img-wrapper");
var $imgInnerWrapper;
var elementLength = 0;
var width = 0;
var elementRangeWidth = 0;
var saveShowedNumberOfElement = 1;

$imgWrapper.on("mouseenter", function() {
    $imgInnerWrapper = $(this).find(".js-img-inner");
    elementLength = $imgInnerWrapper.children().length;
    width = $(this).outerWidth();
    elementRangeWidth = width / elementLength;
}).on("mousemove", function(e) {
    var mousePosition = e.pageX - $(this).offset().left;
    if (mousePosition > 0 && mousePosition <= width) {
        var showedNumberOfElement = Math.ceil(mousePosition / elementRangeWidth);

        if (saveShowedNumberOfElement !== showedNumberOfElement) {
            saveShowedNumberOfElement = showedNumberOfElement;
            var imagePositionOffset = -width * (showedNumberOfElement - 1);
            $imgInnerWrapper.css({
                transform: "translateX("+ imagePositionOffset +"px)"
            });
        }
    }
}).on("mouseleave", function() {
    $imgInnerWrapper.css({
        transform: "translateX(0px)"
    });

    $imgInnerWrapper = undefined;
    elementLength = 0;
    width = 0;
    elementRangeWidth = 0;
    saveShowedNumberOfElement = 1;
});

You can watch how it work on CodePen

Pharsalus answered 6/5, 2021 at 23:35 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.