scroll on mouse movement - javascript

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

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>

Related

How can I change parent of an element with transform translate animation?

I want to move an element from one parent to another parent. Here I wanna apply CSS transform animation.
function abc() {
let child = document.querySelector("#child");
let parent = document.querySelector("#div_b");
parent.appendChild(child);
}
<div id="div_a" style="height:30px; width:30px; background-color:yellow;">
<div id="child" class="new-box">
<div style="width: 20px; height: 20px; background-color: green;"></div>
</div>
</div>
<div id="div_b" style="height:30px; width:30px; background-color:red;">
</div>
<button onclick="abc()">move</button>
You can find out where the element is currently, move it to its new parent and find out where it is now, put it back in its original parent and set an animation for it to translate to its new position.
When the animation has completed then you put the element into its new position (ie into its new parent).
function abc() {
const child = document.querySelector("#child");
const parent = document.querySelector("#div_b");
const parentOriginal = document.querySelector("#div_a");
parentOriginal.appendChild(child); //put back to where it was
const x0 = child.getBoundingClientRect().left;
const y0 = child.getBoundingClientRect().top;
parent.appendChild(child);
const x1 = child.getBoundingClientRect().left;
const y1 = child.getBoundingClientRect().top;
parentOriginal.appendChild(child);
child.style.setProperty('--dx', (x1 - x0) + 'px');
child.style.setProperty('--dy', (y1 - y0) + 'px');
child.addEventListener('animationend', function() {
parent.appendChild(child);
child.classList.remove('move');
});
child.classList.add('move');
}
.move {
animation: move 2s linear 1;
}
#keyframes move {
0% {
transform: translateX(0) translateY(0);
}
100% {
transform: translateX(var(--dx)) translateY(var(--dy));
}
}
<div id="div_a" style="height:30px; width:30px; background-color:yellow;">
<div id="child" class="new-box">
<div style="width: 20px; height: 20px; background-color: green;"></div>
</div>
</div>
<div id="div_b" style="height:30px; width:30px; background-color:red;">
</div>
<button onclick="abc()">move</button>
In addition to A Haworth's excellent answer, you could further iterate on this by using the Web Animations API. This API uses the same fundamentals as CSS Animations, but allows you to perform the actions through JavaScript.
Like Haworth, get the first position of the #child element. Then move it to it's destination. Measure the position of the #child again. Subtract the last position from the first position. The result of this subtraction is the difference between the two points, otherwise known as the delta.
Use the delta to translate the #child to it's previous first and then animate it to the last known position.
const moveButton = document.querySelector('#move');
const origin = document.querySelector('#div_a');
const target = document.querySelector('#div_b');
const child = document.querySelector("#child");
moveButton.addEventListener('click', () => {
const { left: x0, top: y0 } = child.getBoundingClientRect();
target.append(child);
const { left: x1, top: y1 } = child.getBoundingClientRect();
const dx = x0 - x1;
const dy = y0 - y1;
if (dx === 0 && dy === 0) {
return;
}
const transformFrom = `translate3d(${dx}px, ${dy}px, 0)`;
const transformTo = `translate3d(0, 0, 0)`;
const animation = child.animate([
{ transform: transformFrom },
{ transform: transformTo },
], {
duration: 2000,
easing: 'linear',
});
});
<div id="div_a" style="height:30px; width:30px; background-color:yellow;">
<div id="child" class="new-box">
<div style="width: 20px; height: 20px; background-color: green;"></div>
</div>
</div>
<div id="div_b" style="height:30px; width:30px; background-color:red;">
</div>
<button id="move">move</button>
I think this will solve your problem.
const firstContainer = document.querySelector('.first-container');
const secondContainer = document.querySelector('.second-container');
const box = document.querySelector('.box');
box.addEventListener('click', () => {
box.classList.add('move');
setTimeout(() => {
firstContainer.removeChild(box);
box.classList.remove('move');
secondContainer.appendChild(box);
},1000);
},{once:true})
*,
*::before,
*::after {
box-sizing: border-box;
}
body{
min-height: 100vh;
overflow: hidden;
display: grid;
place-content: center;
margin:0;
background-color: bisque;
}
.container{
background-color: aquamarine;
display: flex;
flex-direction: row;
}
.first-container,
.second-container{
width: 20rem;
height: 20rem;
background-color: aquamarine;
border: 1px solid black;
display: grid;
place-content: center;
}
.box{
width: 10rem;
height: 10rem;
background-color: brown;
border-radius: 100%;
display: grid;
place-content: center;
}
.box p{
color:white;
font-size: 2rem;
font-weight: 500;
width: 100%;
}
.move {
animation: movement 1s forwards;
}
#keyframes movement {
100%{
transform: translateX(200%);
}
}
<div class="container">
<div class="first-container">
<div class="box">
<p>Click me</p>
</div>
</div>
<div class="second-container"></div>
</div>

Javascript mousemove event

I have this snippet.
I have the div bar on which I act with a listener for the mousemove event. Depending on the coordinates of the mouse, the hello elements move on the x-axis.
How can I, when the mouse is no longer on the bar, that is, outside, the hello elements in the bar, return to the initial position?
For example, while the mouse is over the bar, the hello elements move to the right, and when the mouse is no longer on the bar, they return to their original position.
const bar = document.querySelector('.bar');
const layer = document.querySelectorAll('.layer');
const eff = function(mouse) {
layer.forEach(layer => {
const x = (window.innerWidth - mouse.pageX) / 10;
const y = (window.innerHeight - mouse.pageY) / 10;
layer.style.transform = `translateX(${x}px)translateY(${y}px)`;
})
};
bar.addEventListener('mousemove', eff);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.bar {
height: 20vh;
background: black;
position: relative;
display: flex;
align-items: center;
justify-content: space-around;
}
#red {
color: red;
}
#blue {
color: blue;
}
<div class="bar">
<div class="hello">
<h2 id='red' class='layer'>Hello</h2>
<h2 id='blue' class='layer'>Hello</h2>
</div>
</div>
You can add another listener for the mouseleave event and then simply reset the translation to 0px for each layer.
const bar = document.querySelector('.bar');
const layer = document.querySelectorAll('.layer');
const eff = function(mouse) {
layer.forEach(layer => {
const x = (window.innerWidth - mouse.pageX) / 10;
const y = (window.innerHeight - mouse.pageY) / 10;
layer.style.transform = `translateX(${x}px)translateY(${y}px)`;
})
};
const reset = function(mouse) {
layer.forEach(layer => {
layer.style.transform = `translateX(0px)translateY(0px)`;
})
};
bar.addEventListener('mousemove', eff);
bar.addEventListener('mouseleave', reset);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.bar {
height: 20vh;
background: black;
position: relative;
display: flex;
align-items: center;
justify-content: space-around;
}
#red {
color: red;
}
#blue {
color: blue;
}
<div class="bar">
<div class="hello">
<h2 id='red' class='layer'>Hello</h2>
<h2 id='blue' class='layer'>Hello</h2>
</div>
</div>

Problem with creating loop for carousel - back to first element

I'm having issue with creating loop inside carousel so it will go back to first card after reaching last one on a click event - rightButton.
So far carousel stops when reach last card.
const carousel = document.querySelector("[data-target='carousel']");
const card = carousel.querySelector("[data-target='card']");
const leftButton = document.querySelector("[data-action='slideLeft']");
const rightButton = document.querySelector("[data-action='slideRight']");
const carouselWidth = carousel.offsetWidth;
const cardStyle = card.currentStyle || window.getComputedStyle(card)
const cardMarginRight = Number(cardStyle.marginRight.match(/\d+/g)[0]);
const cardCount = carousel.querySelectorAll("[data-target='card']").length;
let offset = 0;
const maxX = -((cardCount / 3) * carouselWidth +
(cardMarginRight * (cardCount / 3)) -
carouselWidth - cardMarginRight);
leftButton.addEventListener("click", function() {
if (offset !== 0) {
offset += carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
}
})
rightButton.addEventListener("click", function() {
if (offset !== maxX) {
offset -= carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
}
})
.wrapper {
height: 100px;
width: 432px;
position: relative;
overflow: hidden;
margin: 0 auto;
}
.button-wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
}
.carousel {
margin: 0;
padding: 0;
list-style: none;
width: 100%;
display: flex;
position: absolute;
left: 0;
transition: all 1s ease;
}
.card {
background: black;
min-width: 100px;
height: 100px;
margin-right: 1rem;
display: inline-block;
}
span {
color:#ffffff;
}
<div class="wrapper">
<ul class="carousel" data-target="carousel">
<li class="card" data-target="card"><span>1</span></li>
<li class="card" data-target="card"><span>2</span></li>
<li class="card" data-target="card"><span>3</span></li>
<li class="card" data-target="card"><span>4</span></li>
<li class="card" data-target="card"><span>5</span></li>
<li class="card" data-target="card"><span>6</span></li>
<li class="card" data-target="card"><span>7</span></li>
<li class="card" data-target="card"><span>8</span></li>
<li class="card" data-target="card"><span>9</span></li>
</ul>
<div class="button-wrapper">
<button data-action="slideLeft">L</button>
<button data-action="slideRight">R</button>
</div>
</div>
Code available on jsfiddle:
https://jsfiddle.net/2qv6mpb1/
Is there a chance that someone could point me in a proper direction on how to achieve that? I
You need to handle when your offset is equal to the maxX, and reset the offset back to zero.
rightButton.addEventListener("click", function() {
if (offset !== maxX) {
offset -= carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
} else {
offset = 0;
carousel.style.transform = `translateX(${offset}px)`;
}
})
This will use fixed widths with a gap of 10px (see CSS) - (to make it responsive you should modify the px used in JS to translate in % steps).
Also, it will work for any number of .Carousel elements on the page.
Also, simplify the HTML markup as per below, which is more consistent with the CSS for a better modular methodology
const Carousel = (EL) => {
const CARDS = EL.querySelector(".Carousel-cards");
const PREV = EL.querySelector(".Carousel-prev");
const NEXT = EL.querySelector(".Carousel-next");
const w = EL.offsetWidth;
const d = CARDS.offsetWidth - w; // widths diff
let x = 0;
const anim = (dir) => {
x += w * dir;
x = Math.min(d, Math.max(0, x));
CARDS.style.transform = `translateX(-${x}px)`;
};
PREV.addEventListener("click", () => anim(-1))
NEXT.addEventListener("click", () => anim(+1))
};
document.querySelectorAll(".Carousel").forEach(Carousel);
.Carousel {
height: 100px;
width: 430px; /* (100px * 4) + (10px * 3gap) */
position: relative;
overflow: hidden;
margin: 0 auto;
}
.Carousel-nav {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
}
.Carousel-cards {
position: absolute;
left: 0;
margin: 0;
padding: 0;
list-style: none;
display: flex;
transition: transform 1s ease;
gap: 10px;
}
.Carousel-cards > * {
background: black;
min-width: 100px;
height: 100px;
}
span {
color: #ffffff;
}
<div class="Carousel">
<ul class="Carousel-cards">
<li><span>1</span></li>
<li><span>2</span></li>
<li><span>3</span></li>
<li><span>4</span></li>
<li><span>5</span></li>
<li><span>6</span></li>
<li><span>7</span></li>
<li><span>8</span></li>
<li><span>9</span></li>
</ul>
<div class="Carousel-nav">
<button class="Carousel-prev">L</button>
<button class="Carousel-next">R</button>
</div>
</div>
There's more to improve, i.e: makes no sense to have buttons if the content does not require animating, or one of the buttons depending if a direction is completed.

How can I trigger on mouse movement Variable font in different section?

I was looking to trigger different sections with a variable font based on my mouse movement.
For the first section, everything looks great, but when I tried to trigger the second section, it does not work as I expected since is connected to the first one I guess.
I would need to make the section working independently and in the correct way (to have an idea see section one how react in debug mode)
I was wondering what I have to modify in my Javascript code to make my snippet work with all the sections I want, working independently with their respective variable font interaction. Any ideas?
$('.square').on('mousemove', function(e) {
var x = e.pageX - $(this).offset().left;
var y = e.pageY;
var $tlSquare = $('.division--top.division--left');
var $trSquare = $('.division--top.division--right');
var $blSquare = $('.division--bottom.division--left');
var $brSquare = $('.division--bottom.division--right');
var squareWidth = $(this).width(),
squareHeight = $(this).height();
$tlSquare.width(x).height(y);
$trSquare.width(squareWidth - x).height(y);
$blSquare.width(x).height(squareHeight - y);
$brSquare.width(squareWidth - x).height(squareHeight - y);
stretchLetter(false);
});
stretchLetter(false);
$('.square').on('mouseleave', function() {
$('.division').width('50%').height('50%');
$('.letter').css('transform', '');
stretchLetter(false);
});
function stretchLetter(animation) {
$('.letter').each(function() {
var parentWidth = $(this).parent().width();
var parentHeight = $(this).parent().height();
var thisWidth = $(this).width();
var thisHeight = $(this).height();
var widthPercent = parentWidth / thisWidth;
var heightPercent = parentHeight / thisHeight;
var timing = animation == true ? .5 : 0;
TweenMax.to($(this), timing, {
scaleX: widthPercent,
scaleY: heightPercent
})
//$(this).css('transform', 'scalex('+ widthPercent +') scaley('+ heightPercent +')');
});
}
body,
html {
margin: 0;
padding: 0;
font-weight: bold;
font-family: helvetica;
}
section {
height: 200px;
background: blue;
color: white;
font-size: 28px;
}
.wrapper {
display: flex;
justify-content: center;
/*justify-content: flex-end;*/
width: 100%;
height: 100vh;
//background-color: blue;
overflow: hidden;
}
.square {
display: flex;
flex-wrap: wrap;
width: 100vh;
height: 100vh;
background-color: black;
}
.square-2 {
display: flex;
flex-wrap: wrap;
width: 100vh;
height: 100vh;
background-color: yellow;
}
.division {
//display: flex;
//align-items: center;
//justify-content: center;
width: 50%;
height: 50%;
//background-color: red;
//border: 1px solid white;
box-sizing: border-box;
}
.letter {
cursor: -webkit-grab;
cursor: grab;
}
.letter {
display: inline-block;
font-size: 50vh;
margin: 0;
padding: 0;
line-height: .8;
transform-origin: top left;
color: white;
}
/* .division:nth-child(1){
background-color: blue;
}
.division:nth-child(2){
background-color: red;
}
.division:nth-child(3){
background-color: green;
}
.division:nth-child(4){
background-color: orange;
} */
.circle {
width: 100%;
height: 100%;
border-radius: 50%;
border: 1px solid white;
background-color: blue;
box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>SECTION-01</section>
<main>
<div class="wrapper">
<div class="square">
<div class="division division--top division--left">
<div class="letter">L</div>
</div>
<div class="division division--top division--right">
<div class="letter">A</div>
</div>
<div class="division division--bottom division--left">
<div class="letter">S</div>
</div>
<div class="division division--bottom division--right">
<div class="letter">T</div>
</div>
</div>
</main>
<section>SECTION-02</section>
<div class="wrapper">
<div class="square">
<div class="division division--top division--left">
<div class="letter">F</div>
</div>
<div class="division division--top division--right">
<div class="letter">A</div>
</div>
<div class="division division--bottom division--left">
<div class="letter">S</div>
</div>
<div class="division division--bottom division--right">
<div class="letter">T</div>
</div>
</div>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
https://jsfiddle.net/CAT999/ohaf61qp/5/
See working FIDDLE
You had to change the y variable because you were calculating with the offset top of the mouse position inn the document. This is always bigger than the element, so you have to extract the offset top of the element you were scrolling on, to get the right value.
var y = e.pageY - $(this).offset().top;

On horizontal scroll of overflown div, fill in progress bar

I have a div which contains an image. The container of this image has overflow:scroll, so that the user can scroll left or right to see the rest of the image.
I've also implemented a progress bar, which should indicate how much of the image remains to scroll. I.e. if the user has scrolled 5% to the right, it'll fill up 5% of the progress bar (and vice versa).
I can get the function working based on scrollHeight, but can't get it working based on scrollWidth.
Where am I going wrong?
window.onscroll = function() {myFunction()};
function myFunction() {
var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
var width = document.documentElement.scrollLeft - document.documentElement.clientWidth;
var scrolled = (winScroll / width) * 100;
document.getElementById("myBar").style.width = scrolled + "%";
}
.imgCont {
background: black;
overflow: scroll;
position: relative;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<div class="imgCont">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>
You need to add listeners on the .imgCont element and use it's scrollLeft, scrollWidth and clientWidth properties
let scrEl = document.getElementById("scr-el")
scrEl.addEventListener('scroll', event => {
let scrolled = (scrEl.scrollLeft / (scrEl.scrollWidth - scrEl.clientWidth) ) * 100
document.getElementById("myBar").style.width = scrolled + "%"
});
.imgCont {
background: black;
overflow-x: scroll;
position: relative;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<div id="scr-el" class="imgCont">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>
windows.onscroll won't emit any events while you scroll horizontally because scroll is happening in the element with class imgCont.
put an id imgCont
<div class="imgCont" id="imgCont">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
and call the on scroll event as
document.getElementById("imgCont").onscroll
Jquery solution setps:
subtract the visible width of the image and the real image width
var winScroll = $(".imgCont img").width() - $(".imgCont").width();
get the left scroll position
var width = $(".imgCont").scrollLeft();
get the percentage from the width and position
var scrolled = ((width / winScroll) * 100);
Check the snippet:
$(function(){
$(".imgCont").scroll(function(){
var winScroll = $(".imgCont img").width() - $(".imgCont").width();
var width = $(".imgCont").scrollLeft();
var scrolled = ((width / winScroll) * 100);
$("#myBar").width(scrolled + "%");
});
});
.imgCont {
background: black;
overflow: scroll;
position: relative;
height:200px;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="imgCont">
<img src="https://static.toiimg.com/photo/msid-67868104/67868104.jpg?1368689">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>
Another solution.
let div = document.getElementById("theDiv")
div.addEventListener('scroll', function(e) {
let inner = window.innerWidth
let left = div.scrollLeft
let sWidth = div.scrollWidth
let total = sWidth - inner
let width = 1 * left / total * 100
if (width >= 100) {
return document.getElementById("myBar").style.width = "100%";
}
document.getElementById("myBar").style.width = `${width}%`;
});
body {
margin: 0;
}
.imgCont {
background: black;
overflow: auto;
position: relative;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<div class="imgCont" id="theDiv">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>

Categories

Resources