Reputation: 890
This is my code:
$(document).ready(function() {
$('.scrollable-area').on('wheel', function(e) {
var scrollLeft = $(this).scrollLeft();
var width = $(this).get(0).scrollWidth - $(this).width();
var deltaY = e.originalEvent.deltaY;
var deltaX = e.originalEvent.deltaX;
var newScrollLeft = scrollLeft + deltaY + deltaX;
if ((deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)) {
e.preventDefault();
}
if (newScrollLeft <= 0) {
$(this).scrollLeft(0);
} else if (newScrollLeft >= width) {
$(this).scrollLeft(width);
} else {
$(this).scrollLeft(newScrollLeft);
}
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gallery-container {
position: relative;
width: 100%;
height: 90vh;
background-color: yellow;
overflow: hidden;
}
.scrollable-area {
width: 100%;
height: 100%;
overflow-x: auto;
}
.gallery-items {
display: flex;
min-width: 100%;
height: 100%;
}
.gallery-item {
flex: 0 0 auto;
height: 100%;
display: flex;
}
.gallery-item img {
max-width: 100%;
height: auto;
object-fit: contain;
}
.gallery-item iframe {
background-color: blue;
width: auto;
width: 800px;
}
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<div class="gallery-container">
<div class="scrollable-area">
<div class="gallery-items">
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/da/Sky_landscape.jpg">
</div>
<div class="gallery-item">
<iframe src="https://player.vimeo.com/video/584985260" frameborder="0" allow="fullscreen"></iframe>
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
</div>
</div>
</div>
If you have the cursor on the media gallery and scroll down normally, you will first scroll horizontally through the gallery. That's on purpose. However, it stops when an iframe is included. I've already tried to prevent the pointer events during scrolling, but it leads to some other issues like making it impossible to click the play button of a video.
Also, it would be cool to find a way to always resize the iframe to that of the video and to fit the overall height of the horizontal gallery. Does anyone know how this works?
Upvotes: 3
Views: 1046
Reputation: 401
There is one convoluted way that I've used in the past. It's an event listener injection into the iFrame and then a return back to the parent page.
I've just done a very quick test and it kinda works with your example.
$(document).ready(function() {
....your code here.....
...and just add this...
//this will inject event listeners to any iframe in your page, you can do the selector any way you want, this is just an example
let iframes = document.getElementsByTagName('iframe')
for(let iframe of iframes){
iframe.contentWindow.addEventListener("wheel", function(e){
//IMPORTANT: you need to call a function outside this scope as this is actually being executed inside the iframe, not here. We are basically telling the iframe to fire a function "someFunction()" inside it's parent which is this window where we are.
window.parent.someFunction(e) //someFunction() is further below
})
}
});
// this needs to exists otherwise you will get a script error
function someFunction(e){
//and we should get the wheel event re-broadcast here, thank you mister iFrame :0)
console.log(e) // on my comp don't need to do anything with this, the gallery keeps scrolling on its own or you may need to just pass this event to your main scrolling code
}
Now, this will most likely not work if the page that you are loading in the iFrame implements strict CORS (your video example is not fussy and seems to work fine)
Also, it may require some tweaking if the iFrame background is exposed it may not to react to the wheel but that may be solved by attaching another onwheel event to the iframe itself.
Hope that helps, if not, heck it's a bit of iFrame trivia.
Upvotes: 0
Reputation: 101
I think you can use setTimeout
to implement this. I know this is not a good way. If you can update the iframe
source website, no problem.
$(document).ready(function () {
$(".scrollable-area").on("wheel", function (e) {
var scrollLeft = $(this).scrollLeft()
var width = $(this).get(0).scrollWidth - $(this).width()
var deltaY = e.originalEvent.deltaY
var deltaX = e.originalEvent.deltaX
var newScrollLeft = scrollLeft + deltaY + deltaX
if (
(deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)
) {
e.preventDefault()
}
if (newScrollLeft <= 0) {
$(this).scrollLeft(0)
} else if (newScrollLeft >= width) {
$(this).scrollLeft(width)
} else {
$(this).scrollLeft(newScrollLeft)
}
})
let frameBack = document.querySelector(".background")
frameBack.addEventListener("mousemove", (e) => {
frameBack.classList.remove("z-1")
frameBack.classList.add("-z-1")
setTimeout(() => {
frameBack.classList.remove("-z-1")
frameBack.classList.add("z-1")
}, 100)
})
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gallery-container {
position: relative;
width: 100%;
height: 90vh;
background-color: yellow;
overflow: hidden;
}
.scrollable-area {
width: 100%;
height: 100%;
overflow-x: auto;
}
.gallery-items {
display: flex;
min-width: 100%;
height: 100%;
}
.gallery-item {
flex: 0 0 auto;
height: 100%;
display: flex;
}
.gallery-item img {
max-width: 100%;
height: auto;
object-fit: contain;
}
.gallery-item iframe {
background-color: blue;
width: auto;
width: 800px;
}
.relative {
position: relative;
}
.background {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.z-1 {
z-index: 1;
}
.-z-1 {
z-index: -1;
}
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<div class="gallery-container inactive">
<div class="scrollable-area">
<div class="gallery-items">
<div class="gallery-item">
<img
src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG"
/>
</div>
<div class="gallery-item">
<img
src="https://upload.wikimedia.org/wikipedia/commons/d/da/Sky_landscape.jpg"
/>
</div>
<div class="gallery-item relative">
<iframe
src="https://player.vimeo.com/video/584985260"
frameborder="0"
allow="fullscreen"
></iframe>
<div class="background z-1"></div>
</div>
<div class="gallery-item">
<img
src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG"
/>
</div>
</div>
</div>
</div>
Upvotes: 0
Reputation: 17195
You might add an overlay to your scrolling div to disable iframe pointer events and re-enable pointer events on mouse movements.
Based on trincot's answer "How to detect when mousemove has stopped"
we could use a custom mousestop
event.
aspect-ratio
e.g. 16/9let galleryWrap = document.querySelector('.gallery-container');
(function(mouseStopDelay) {
var timeout;
document.addEventListener('mousemove', function(e) {
clearTimeout(timeout);
timeout = setTimeout(function() {
var event = new CustomEvent("mousestop", {
detail: {
clientX: e.clientX,
clientY: e.clientY
},
bubbles: true,
cancelable: true
});
e.target.dispatchEvent(event);
}, mouseStopDelay);
});
}(1000));
// Example use
galleryWrap.addEventListener('mousestop', function(e) {
galleryWrap.classList.add('inactive')
});
galleryWrap.addEventListener('mousemove', function(e) {
galleryWrap.classList.remove('inactive')
});
galleryWrap.addEventListener('click', function(e) {
galleryWrap.classList.remove('inactive')
});
$(document).ready(function() {
let galleryWrap = $('.gallery-container')
let scrollArea = $('.scrollable-area')
galleryWrap.on('wheel', function(e) {
scrolling = true;
var scrollLeft = scrollArea.scrollLeft();
var width = scrollArea.get(0).scrollWidth - scrollArea.width();
var deltaY = e.originalEvent.deltaY;
var deltaX = e.originalEvent.deltaX;
var newScrollLeft = scrollLeft + deltaY + deltaX;
if ((deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)) {
e.preventDefault();
}
if (newScrollLeft <= 0) {
scrollArea.scrollLeft(0);
} else if (newScrollLeft >= width) {
scrollArea.scrollLeft(width);
} else {
scrollArea.scrollLeft(newScrollLeft);
}
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gallery-container {
position: relative;
width: 100%;
height: 250px;
background-color: yellow;
overflow: hidden;
}
.scrollable-area {
width: 100%;
height: 100%;
overflow-x: auto;
}
.gallery-items {
display: flex;
min-width: 100%;
height: 100%;
}
.gallery-item {
flex: 0 0 auto;
height: 100%;
display: flex;
}
.gallery-item img {
max-width: 100%;
height: auto;
object-fit: contain;
}
.gallery-item iframe {
width: 100%;
aspect-ratio: 16/9;
display: block;
}
.scrollable-area {
position: relative;
}
.gallery-container.inactive:after {
content: "";
position: absolute;
display: block;
left: 0;
top: 0;
right: 0;
width: 100%;
height: 100%;
background: red;
opacity: 0.1;
z-index: 100;
}
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<div class="gallery-container inactive">
<div class="scrollable-area">
<div class="gallery-items">
<div class="gallery-item">
<iframe frameborder="0" scrolling="no" srcdoc='<html><body style="margin:0; padding:0;"><video style="margin:0; padding:0; width:100%; aspect-ratio:16/9" controls muted playsinline controls preload="meta"><source src="https://cdn.jsdelivr.net/npm/[email protected]/video.mp4#t0" type="video/mp4"></video></html></body>'></iframe>
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/da/Sky_landscape.jpg">
</div>
<div class="gallery-item">
<img src="https://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast%2C_Dhaka%2C_Bangladesh.JPG">
</div>
</div>
</div>
</div>
I've added a semitransparent reddish tint to illustrate the overlay toggling.
Upvotes: 2
Reputation: 1393
Modify your jQuery code to handle scrolling events for both images and iframes and you may also dynamically resize the iframes to fit their content and adjust the height of the horizontal gallery accordingly.
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script>
$(document).ready(function() {
$('.scrollable-area').on('wheel', function(e) {
var scrollLeft = $(this).scrollLeft();
var width = $(this).get(0).scrollWidth - $(this).width();
var deltaY = e.originalEvent.deltaY;
var deltaX = e.originalEvent.deltaX;
var newScrollLeft = scrollLeft + deltaY + deltaX;
if ((deltaY > 0 && newScrollLeft < width) ||
(deltaY < 0 && newScrollLeft > 0)) {
e.preventDefault();
}
if (newScrollLeft <= 0) {
$(this).scrollLeft(0);
} else if (newScrollLeft >= width) {
$(this).scrollLeft(width);
} else {
$(this).scrollLeft(newScrollLeft);
}
});
// Resize iframes to fit their content
function resizeIframes() {
$('.gallery-item iframe').each(function() {
this.height = this.contentWindow.document.body.scrollHeight + 'px';
});
}
// Call the function on initial load and on window resize
resizeIframes();
$(window).resize(function() {
resizeIframes();
});
});
</script>
Upvotes: 0