Scrolling Text to Change Fixed Background Image on Scroll - javascript

I'm looking for some help, I'm trying to recreate the homepage on this site.
https://madebyarticle.com/
I don't want to use Jquery, either Plain JS or Vue.
I've got it to do most what I want it to but have a few issues.
Codepen Example
HTML
<main id="parent" class="Loop js-loop">
<section>
<h1 class="step1">One</h1>
</section>
<section>
<h1 class="step2">For</h1>
</section>
<section>
<h1 class="step3">All</h1>
</section>
<section>
<h1>And</h1>
</section>
<section>
<h1>All</h1>
</section>
<section>
<h1>For</h1>
</section>
<!--
These blocks are the same as the first blocks to get that looping illusion going.
You need to add clones to fill out a full viewport height.
-->
<section class="green is-clone">
<h1>One</h1>
</section>
<section class="red is-clone">
<h1>For</h1>
</section>
</main>
CSS
html,
body {
height: 100%;
overflow: hidden;
}
.Loop {
position: relative;
height: 100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
section {
position: relative;
text-align: center;
/* min-height: 300px;
max-height: 700px; */
height: 100vh;
}
::scrollbar {
display: none;
}
body {
font-family: "Avenir Next", Helvetica, sans-serif;
font-weight: normal;
font-size: 100%;
}
h1 {
margin: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
font-size: 80px;
letter-spacing: 5px;
/* color: #fff; */
text-transform: uppercase;
}
.mystyle {
background: red;
}
.mystyle1 {
background-image: url(https://images.unsplash.com/photo-1528834379234-2de7f8328fd8?ixlib=rb-1.2.1&auto=format&fit=crop&w=1920&q=10);
}
.mystyle2 {
background-image: url(https://images.unsplash.com/photo-1501854140801-50d01698950b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2600&q=80);
}
JS
var doc = window.document,
context = doc.querySelector(".js-loop"),
clones = context.querySelectorAll(".is-clone"),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
function getScrollPos() {
return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}
function setScrollPos(pos) {
context.scrollTop = pos;
}
function getClonesHeight() {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc() {
scrollPos = getScrollPos();
scrollHeight = context.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate() {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function() {
disableScroll = false;
}, 40);
}
}
function init() {
reCalc();
context.addEventListener(
"scroll",
function() {
window.requestAnimationFrame(scrollUpdate);
},
false
);
window.addEventListener(
"resize",
function() {
window.requestAnimationFrame(reCalc);
},
false
);
}
if (document.readyState !== "loading") {
init();
} else {
doc.addEventListener("DOMContentLoaded", init, false);
}
// Just for this demo: Center the middle block on page load
window.onload = function() {
setScrollPos(
Math.round(
clones[0].getBoundingClientRect().top +
getScrollPos() -
(context.offsetHeight - clones[0].offsetHeight) / 2
)
);
};
const images = document.querySelectorAll('h1');
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
entry.target.classList.add('active');
} else {
entry.target.classList.remove('active');
}
});
});
images.forEach(image => {
observer.observe(image);
});
const header = document.getElementById("parent");
const sectionOne = document.querySelector("h1.step1");
const sectionTwo = document.querySelector("h1.step2");
const sectionThree = document.querySelector("h1.step3");
const sectionOneObserver = new IntersectionObserver(function(
entries,
sectionOneObserver
) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
header.classList.add("mystyle");
} else {
header.classList.remove("mystyle");
}
});
});
sectionOneObserver.observe(sectionOne);
const sectionTwoObserver = new IntersectionObserver(function(
entries,
sectionTwoObserver
) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
header.classList.add("mystyle1");
} else {
header.classList.remove("mystyle1");
}
});
});
sectionTwoObserver.observe(sectionTwo);
const sectionThreeObserver = new IntersectionObserver(function(
entries,
sectionThreeObserver
) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
header.classList.add("mystyle2");
} else {
header.classList.remove("mystyle2");
}
});
});
sectionThreeObserver.observe(sectionThree);
// if (document.querySelectorAll('h1.step1.active')){
// document.getElementById("parent").classList.toggle("mystyle");
// } else {
// document.getElementById("parent").classList.remove("mystyle");
// }
// if (document.classList.contains("h1.step1.active")) {
// document.getElementById("parent").classList.add("mystyle");
// } else {
// document.getElementById("parent").classList.remove("mystyle");
// }
I'm having to duplicate the IntersectionObserver for every image I need, is there a cleaner way todo this?
At some points, there are 2 active states so it doesn't display any image only a background colour.
What would be the best way to fade the image on change like the example website?
Are there any examples or scripts that can do what I'm trying todo?
Thanks

Related

Iterate HTML classes to create class objects with javascript

class CVP {
constructor(obj) {
const { P, V, PC, BPB, MPB, VRC, VBC, FS, PROG, PROGC, TW, TC } = obj;
// player
this.player = document.querySelector(P);
// video el
this.video = document.querySelector(V);
// player controller
this.playerController = document.querySelector(PC);
// play controlers
this.bigPlayBtn = document.querySelector(BPB);
this.miniPlayBtn = document.querySelector(MPB);
// volume controllers
this.volumeRangeController = document.querySelector(VRC);
this.volumeBtnController = document.querySelector(VBC);
// fullscreen
this.fullscreen = document.querySelector(FS);
// progress bar
this.progress = document.querySelector(PROG);
this.progressCurr = document.querySelector(PROGC);
// time displayers
this.timeWhole = document.querySelector(TW);
this.timeCurr = document.querySelector(TC);
// bool vars
this.isMousedown = false;
this.isFullScreen = false;
// timer vars
this.timer = '';
this.timerTime = 1000;
}
setIsMouseDown = () => {
this.isMousedown = !this.isMousedown;
};
bigPlayBtnHandler = () => {
this.bigPlayBtn.classList.toggle('HideBigPlayBtn');
};
showHideControlls = () => {
this.player.classList.toggle('paused');
};
static changeIcon(target, remove, add) {
target.classList.remove(remove);
target.classList.add(add);
}
changePlayIcon() {
console.log(this.video.src);
const target = this.miniPlayBtn;
let icon = this.video.paused ? 'play' : 'pause';
if (icon === 'pause') {
CVP.changeIcon(target, 'play', 'pause');
} else {
CVP.changeIcon(target, 'pause', 'play');
}
}
changeVolumeIcon(volElIconID) { // not in use
const target = document.querySelector(volElIconID);
if (this.video.muted) {
CVP.changeIcon(target, 'max', 'mute');
} else {
CVP.changeIcon(target, 'mute', 'max');
}
}
handleVideoTime(time) {
// minutes and seconds So Far
let hours;
let min = Math.floor(time / 60);
let sec = Math.floor(time % 60);
let output = '';
sec = (sec < 10) ? sec = `0${sec}` : sec;
min = (min < 10) ? min = `0${min}` : min;
output = `${min}:${sec}`;
return output;
}
rangeVolumeController() {
cvp.video[this.name] = this.value;
if (cvp.volumeRangeController.value == 0) {
cvp.video.muted = true;
CVP.changeIcon(cvp.volumeBtnController, 'max', 'mute');
} else {
cvp.video.muted = false;
CVP.changeIcon(cvp.volumeBtnController, 'mute', 'max');
}
}
btnVolumeController() {
if (cvp.video.muted) {
cvp.video.muted = false;
CVP.changeIcon(cvp.volumeBtnController, 'mute', 'max');
cvp.volumeRangeController.value = 1;
cvp.video.volume = 1;
} else {
cvp.video.muted = true;
CVP.changeIcon(cvp.volumeBtnController, 'max', 'mute');
cvp.volumeRangeController.value = 0;
}
}
hideWhenFullScreen() {
if (this.isFullScreen) {
this.playerController.hidden = false; // or this.playerController.style.bottom = '0px';
document.body.style.cursor = 'auto';
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.playerController.hidden = true; // or this.playerController.style.bottom = '-50px';
document.body.style.cursor = 'none';
}, this.timerTime);
} else {
this.playerController.hidden = false; // or this.playerController.style.bottom = '0px';
document.body.style.cursor = 'auto';
}
}
toggleFullScreen() {
if (this.isFullScreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else {
console.error('Unable to find a fullscreen exit method.');
}
} else {
if (this.player.requestFullscreen) {
this.player.requestFullscreen();
} // standard
else if (this.player.webkitRequestFullscreen) {
this.player.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (this.player.mozRequestFullScreen) {
this.player.mozRequestFullScreen();
} else if (this.player.msRequestFullscreen) {
this.player.msRequestFullscreen();
} else {
console.error('Unable to find a fullscreen request method');
}
}
}
toggleFullScreenHelper() {
this.player.classList.toggle('isFullScreen');
this.isFullScreen = !this.isFullScreen;
}
togglePlay() {
const action = this.video.paused ? 'play' : 'pause';
this.video[action]();
this.playerController.style.bottom = '0px';
this.changePlayIcon();
this.showHideControlls();
}
showVideoTime() {
const {
currentTime,
duration
} = cvp.video;
const pct = (currentTime / duration) * 100;
cvp.progressCurr.style.width = pct + '%';
cvp.timeCurr.innerText = cvp.handleVideoTime(currentTime.toFixed(0));
cvp.timeWhole.innerText = cvp.handleVideoTime(duration);
}
scrub(e) {
console.log(e);
console.log('e', e, 'this', this);
let seconds = (e.offsetX / this.progress.offsetWidth) * this.video.duration;
this.video.currentTime = seconds;
}
loadVideo() {
// il metodo è da applciare assieme a un loader e ad altre gestioni degli eventi video
// esempi di loader: https://www.w3schools.com/howto/howto_css_loader.asp
// metodi video: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loadeddata_event
// per i tooltips: https://www.w3schools.com/howto/howto_css_tooltip.asp
console.log(this.video.src);
}
init() {
// Hook up the Event Listeners
// toggle Play
this.video.addEventListener('click', this.togglePlay.bind(this));
this.miniPlayBtn.addEventListener('click', this.togglePlay.bind(this));
this.bigPlayBtn.addEventListener('click', this.togglePlay.bind(this));
this.video.addEventListener('loadeddata', this.loadVideo.bind(this));
// bigPlayBtn show/hide handler
this.video.addEventListener('click', this.bigPlayBtnHandler);
this.bigPlayBtn.addEventListener('click', this.bigPlayBtnHandler);
this.miniPlayBtn.addEventListener('click', this.bigPlayBtnHandler);
// time update
this.video.addEventListener('timeupdate', this.showVideoTime);
// progress bar events
this.progress.addEventListener('click', this.scrub.bind(this));
this.progress.addEventListener('mousemove', (e) => this.isMousedown && this.scrub(e));
this.progress.addEventListener('mousedown', this.setIsMouseDown);
this.progress.addEventListener('mouseup', this.setIsMouseDown);
// fullscreen
this.fullscreen.addEventListener('click', this.toggleFullScreen.bind(this));
// volume controllers
this.volumeBtnController.addEventListener('click', this.btnVolumeController);
this.volumeRangeController.addEventListener('change', this.rangeVolumeController);
this.volumeRangeController.addEventListener('mousemove', this.rangeVolumeController);
// cross-browser fullscreen hanlder
const browsersFullScreen = [
'fullscreenchange',
'mozfullscreenchange',
'webkitfullscreenchange',
'msfullscreenchange',
];
browsersFullScreen.forEach(browser => document.addEventListener(browser, this.toggleFullScreenHelper.bind(this)));
// player show/hide controlls on mousemove event
this.player.addEventListener('mousemove', this.hideWhenFullScreen.bind(this));
}
}
const initializeCVP = {
P: '.CVP',
V: '.video',
PC: '.playerController',
BPB: '.bigPlayBtn',
MPB: '.miniPlayBtn',
VRC: '.volumeRC',
VBC: '.volumeBC',
FS: '.fullscreen',
PROG: '.progress',
PROGC: '.progressCurr',
TW: '.timeWhole',
TC: '.timeCurr',
};
let cvp = new CVP(initializeCVP);
cvp.init();
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
align-items: center;
height: 100vh;
background-image: linear-gradient(to top, #dad4ec 0%, #dad4ec 1%, #f3e7e9 100%);
/* background-image: linear-gradient(-20deg, #f794a4 0%, #fdd6bd 100%); */
}
[hidden] {
display: none !important;
}
.player {
display: flex;
justify-content: center;
border-radius: 10px;
width: 700px;
max-height: 100%;
position: relative;
font-size: 16px;
overflow: hidden;
text-align: center;
background: #000;
color: #fff;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.4), 0 10px 20px -3px rgba(0, 0, 0, 0.2);
margin-bottom: 5vh;
}
/* This css is only applied when fullscreen is active. */
.player.isFullScreen {
max-width: none;
max-height: none;
width: 100%;
height: 100%;
background: #000;
}
.player.isFullScreen video {
width: 100%;
height: auto;
}
.video {
max-width: 100%;
max-height: 100%;
-o-object-fit: fill;
object-fit: fill;
/* These are the actual dimensions of the video. Avoid the awkward element resize after the video loads. */
/* width: 640px;
height: 358px; */
}
.playerController {
display: flex;
align-items: center;
justify-content: space-evenly;
width: 98%;
max-width: 1000px;
/* limiting in fullscreen mode */
position: absolute;
background: rgba(51, 51, 51, 0.8);
color: #fff;
border-radius: 10px;
margin-bottom: 1%;
z-index: 2147483649;
transform: translateY(150px);
transition: .2s;
bottom: -50px;
/* 0 to show in preview */
}
.playerController * {
color: rgba(255, 255, 255, 0.9);
}
.playerController button {
background: none;
border: 0;
outline: 0;
text-align: center;
cursor: pointer;
}
.icon {
font-size: 16px;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
}
.player:hover .playerController,
.player.paused .playerController {
transform: translateY(0);
}
.player__btn {
max-width: 50px;
}
.play::before {
content: '\f04b';
}
.pause::before {
content: '\f04c';
}
.progress {
/* position: relative; */
width: 50%;
cursor: pointer;
user-select: none;
height: 10px;
/* or 15px */
background: rgba(160, 154, 154, 0.8);
overflow: hidden;
border-radius: 50px;
}
.progressCurr {
height: 100%;
width: 0;
background: rgba(255, 255, 255, 0.9);
/* flex: 0;
flex-basis: 0%; */
/* old styles yellow progressCurr bg flex-basic insted of width*/
}
.fullscreen::before {
font-family: 'FontAwesome';
content: '\f065';
font-size: 16px
}
.player.isFullScreen .playerController .fullscreen::before {
content: '\f066';
}
.timeCurr,
.timeWhole {
font-size: 14px;
user-select: none;
}
.volumeContainer {
display: flex;
}
.volumeBC {
cursor: pointer;
padding-right: 5px;
}
.volumeRC {
width: 10px;
height: 30px;
}
.max::before {
content: '\f028'
}
.mute::before {
content: '\f6a9'
}
.bigPlayBtn {
font-size: 80px;
position: absolute;
top: 50%;
left: 50%;
cursor: pointer;
box-sizing: border-box;
transform: translate(-50%, -50%);
transition: .5s;
}
.bigPlayBtn::before {
content: '\f04b';
}
.HideBigPlayBtn {
cursor: default;
opacity: 0;
transform: translate(-50%, -50%) scale(1.2);
}
<div class='player paused CVP'>
<video class='video' src='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' width='700' height='350' poster='https://i.ytimg.com/vi/A1sVB8XBNDo/maxresdefault.jpg'>
</video>
<div class='bigPlayBtn icon'></div>
<div class='playerController'>
<button class='player__btn miniPlayBtn icon' title='Play/Pause'></button>
<div class='timeCurr'>00:00</div>
<div class='progress'>
<span id='buffered'>
<div class='progressCurr'></div>
</span>
</div>
<div class='timeWhole'>--:--</div>
<div class='volumeContainer'>
<button class='player__btn max volumeBC icon'></button>
<input type='range' name='volume' class='volume volumeRC' min='0' max='1' step='0.01' value='1' title='Volume' />
</div>
<button class='player__btn fullscreen icon' title='Full Screen'></button>
</div>
</div>
<div class='player paused CVP'>
<video class='video' src='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4' width='700' height='350' poster='https://i.ytimg.com/vi/A1sVB8XBNDo/maxresdefault.jpg'>
</video>
<div class='bigPlayBtn icon'></div>
<div class='playerController'>
<button class='player__btn miniPlayBtn icon' title='Play/Pause'></button>
<div class='timeCurr'>00:00</div>
<div class='progress'>
<span id='buffered'>
<div class='progressCurr'></div>
</span>
</div>
<div class='timeWhole'>--:--</div>
<div class='volumeContainer'>
<button class='player__btn max volumeBC icon'></button>
<input type='range' name='volume' class='volume volumeRC' min='0' max='1' step='0.01' value='1' title='Volume' />
</div>
<button class='player__btn fullscreen icon' title='Full Screen'></button>
</div>
</div>
Sorry if I'm disturbing you for something that will probably appear you very simple, but I can't find a way to solve the problem on my own.
And, maybe, the title is not appropriated...
Well, I have a class with a constructor that works with HTML tag VIDEO, named CVP. It creates methods to act on video controls. The initial method consist in hooking the event listeners to HTML controls'classes.
Anyway, with a single VIDEO tag in the HTML code, it works correctly, but I don't know how to iterate the class on any VIDEO when there are many of them. This is an examples of the VIDEO tag:
<div class='player paused CVP'>
<video class='video' src="../../video/pietro.mp4">
</video>
etc...
This is the beginnig of the JS CLASS:
class CVP {
constructor (obj) {
const { P, V, PC, BPB, MPB, VRC, VBC, FS, PROG, PROGC, TW, TC } = obj;
this.player = document.querySelector(P);
this.video = document.querySelector(V);
etc..
The class ends this way:
(many other methods...)
init () {
// Hook up the Event Listeners
// toggle Play
this.video.addEventListener('click', this.togglePlay.bind(this));
this.miniPlayBtn.addEventListener('click', this.togglePlay.bind(this));
this.bigPlayBtn.addEventListener('click', this.togglePlay.bind(this));
etc...
}
}
Then, there's a inizialization's variable:
const initializeCVP = {
P: '.CVP',
V: '.video',
PC: '.playerController',
etc...
};
To add a single VIDEO tag:
const cvp = new CVP(initializeCVP);
cvp.init();
In this case it works perfectly. But, How can I assign the JS class to many VIDEO tags?
I tried this way, but it doesn't work:
window.onload = function () {
const CVPs = document.querySelectorAll('.CVP');
CVPs.forEach((cvp) => {
cvp = new CVP(initializeCVP);
cvp.init();
});
};
Is it clear? I hope so. I'm quite a beginner, so plase, don't complain...
Change your constructor so it takes elements rather than selectors. The caller can call document.querySelector() or document.querySelectorAll() when creating the initialization object.
class CVP {
constructor (obj) {
const { P, V, PC, BPB, MPB, VRC, VBC, FS, PROG, PROGC, TW, TC } = obj;
this.player = P;
this.video = V;
etc..
}
}
window.onload = function() {
const players = document.querySelectorAll('.player');
players.forEach(player => {
const initializeCVP = {
P: player,
V: player.querySelector('.video'),
PC: player.querySelector('.playerController'),
BPB: player.querySelector('.bigPlayBtn'),
MPB: player.querySelector('.miniPlayBtn'),
VRC: player.querySelector('.volumeRC'),
VBC: player.querySelector('.volumeBC'),
FS: player.querySelector('.fullscreen'),
PROG: player.querySelector('.progress'),
PROGC: player.querySelector('.progressCurr'),
TW: player.querySelector('.timeWhole'),
TC: player.querySelector('.timeCurr'),
};
const cvp = new CVP(initializeCVP);
cvp.init();
});
};
I found a way to fix what #Barman and #RandyCasburn pointed out regarding the single 'cvp' istance connected to class methods.
First, I applied #Barman suggestion, so to iterate all players has in the previous answer.
Then, I put a global array to collect the single 'cvp', with a couple of other new variables:
let cvpItems = [];
let cvpItem;
let currentCVP;
Then, I pushed all player istances in the HTML, applying to anyone an addEventListener. The window.onload code is changed in this way:
window.onload = function () {
const players = document.querySelectorAll('.player');
players.forEach(player => {
const initializeCVP = {
P: player,
V: player.querySelector('.video'),
PC: player.querySelector('.playerController'),
BPB: player.querySelector('.bigPlayBtn'),
MPB: player.querySelector('.miniPlayBtn'),
VRC: player.querySelector('.volumeRC'),
VBC: player.querySelector('.volumeBC'),
FS: player.querySelector('.fullscreen'),
PROG: player.querySelector('.progress'),
PROGC: player.querySelector('.progressCurr'),
TW: player.querySelector('.timeWhole'),
TC: player.querySelector('.timeCurr'),
};
cvpItem = new CVP(initializeCVP);
cvpItems.push(cvpItem);
cvpItem.init();
player.addEventListener('click', currentItem, false);
});
};
With the currentItem function I find the current player iteration using the title attribute in the HTML video tags:
let currentItem = function () {
for (var i = 0; i < cvpItems.length; i++) {
if (cvpItems[i].video.title == this.querySelectorAll('.video')[0].title) {
currentCVP = i;
break;
}
}
};
So, now I can identify the specific player in the JS class. For examples, the previous rangeVolumeController method changes from:
rangeVolumeController () {
cvp.video[this.name] = this.value;
if (cvp.volumeRangeController.value == 0) {
cvp.video.muted = true;
CVP.changeIcon(cvp.volumeBtnController, 'max', 'mute');
} else {
cvp.video.muted = false;
CVP.changeIcon(cvp.volumeBtnController, 'mute', 'max');
}
}
to
rangeVolumeController () {
console.log(CVP, this, event.target);
cvpItems[currentCVP].video[this.name] = this.value;
if (cvpItems[currentCVP].volumeRangeController.value == 0) {
cvpItems[currentCVP].video.muted = true;
CVP.changeIcon(cvpItems[currentCVP].volumeBtnController, 'max', 'mute');
} else {
cvpItems[currentCVP].video.muted = false;
CVP.changeIcon(cvpItems[currentCVP].volumeBtnController, 'mute', 'max');
}
}
It works! But, I know, it's not an elegant way for coding. If someone wants to propose a better or more "elegant" solution, I'll be grateful.

How can I trigger onwheel event up and down effect in javascript?

I want to trigger a function or loop when onwheel scroll up or scroll down.
Please see my snippet.
let demo = document.querySelector('#demo');
let c = 0;
window.onwheel = function() {
c ++;
demo.innerHTML = c;
}
body{
height: 300vh;
}
h1{
position: fixed;
text-align: center;
width: 100vw;
}
<h1 id="demo" > Hello World </h1>
I need when it will scroll up the number should be increment and
when scroll down number should be decrements. but it's just increment the number, I need js clear solution. Thanks.
You can use wheel event listener and get the direction with event.deltaY :
let demo = document.querySelector('#demo');
let c = 0;
window.addEventListener('wheel', function(event) {
if (event.deltaY < 0) {
console.log('scrolling up');
if (c == 0) { // no negative values
demo.innerHTML = 0;
} else {;
c--;
demo.innerHTML = c;
}
} else if (event.deltaY > 0) {
console.log('scrolling down');
//if (c != 0) {
c++;
demo.innerHTML = c;
// }
}
});
body {
height: 300vh;
}
h1 {
position: fixed;
text-align: center;
width: 100vw;
}
<h1 id="demo"> Hello World </h1>
window.onwheel = function(event) {
if (event.deltaY > 0) {
// down
} else {
// up
}
}
You could also just remember window.pageYOffset and check if you actually scrolled down (must be greater than remembered value)
let demo = document.querySelector('#demo');
let c = 0;
let last_scroll= window.pageYOffset;
window.onwheel = function() {
if(window.pageYOffset >= last_scroll && last_scroll != 0){
c ++;
demo.innerHTML = c;
}
last_scroll = window.pageYOffset;
}
body{
height: 300vh;
}
h1{
position: fixed;
text-align: center;
width: 100vw;
}
<h1 id="demo" > Hello World </h1>
var demoHeight = demo.offsetHeight;
demo.onscroll = function(){}

Things are becoming slow while making an android like drawer using HTML , CSS , vanilla Javascript

What I am trying to do is make a drawer where drawer can be opened with left swipe from the edge and can be closed from right swipe from anywhere, if swipe is more than 150px.
I have achieved everything, however, the drawer becomes laggy and ultimately the browser freezes. The code for the following is as below.
let drawer = document.getElementsByClassName('drawer')[0];
function openDrawer(start) {
document.addEventListener('touchend', function() {
let end = event.changedTouches[0].pageX;
if ((end > start) && ((end - start) > 150)) {
drawer.classList.add('tra')
drawer.style.transform = `translateX(0px)`;
}
});
}
function closeDrawer(start) {
document.addEventListener('touchend', function() {
let end = event.changedTouches[0].pageX;
if ((end < start) && ((start - end) > 150)) {
drawer.classList.add('tra')
drawer.style.transform = `translateX(-104%)`;
}
});
}
document.addEventListener('touchstart', function() {
drawer.classList.remove('tra')
let start = event.changedTouches[0].pageX;
if (start < 50) {
document.addEventListener('touchmove', function() {
let change = event.changedTouches[0].pageX;
let drawerWidth = drawer.offsetWidth;
let move = change - drawerWidth;
let min = 0;
let max = -drawerWidth;
if (move < max) {
move = max;
}
if (move > min) {
move = min;
}
drawer.style.transform = `translateX(${move}px)`;
document.addEventListener('touchmove', function() {
document.addEventListener('touchend', function() {
if (change >= drawerWidth / 2) {
drawer.classList.add('tra');
drawer.style.transform = `translateX(0%)`;
} else {
drawer.classList.add('tra');
drawer.style.transform = `translateX(-104%)`;
}
});
})
})
openDrawer(start)
} else {
closeDrawer(start)
}
}, 500);
html,
body {
margin: 0px;
padding: 0px;
background: lightgrey;
}
.drawer {
position: fixed;
top: 0px;
left: 0px;
bottom: 0px;
width: 80%;
background: hotpink;
transform: translateX(-104%);
}
.tra {
transition: 500ms ease;
}
<div class="drawer" id="drawer">
</div>
Here is the jsFiddle: https://jsfiddle.net/0xre4uo5/5/

Javascript scroll listener not working in chrome or firefox

I have created a simple slider that on scroll scrolls down 100vh. It works perfectly in Safari but it doesn't seem to fire at all in both Chrome or Firefox.
Really appreciate it if anyone could point out to me where i may have gone wrong. I'm sure it's something simple but I just can't figure it out.
I have uploaded the files to my test web server so you can see the issue.
test.liamcrane.co.uk
var slider = document.querySelector('.section__wrapper__inner');
var sections = document.querySelectorAll('.section');
var currentTransform = 0;
var activeSection = 0;
function slideDown() {
if (!(activeSection === sections.length - 1)) {
sectionReset();
currentTransform -= 100;
slider.style.transform = "translate3d(0," + currentTransform + "vh, 0)";
activeSection++;
sections[activeSection].classList.add('active');
}
setTimeout(function() {
ready = true;
}, 2000);
}
function slideUp() {
if (!(activeSection === 0)) {
sectionReset();
currentTransform += 100;
slider.style.transform = "translate3d(0," + currentTransform + "vh, 0)";
activeSection--;
sections[activeSection].classList.add('active');
}
setTimeout(function() {
ready = true;
}, 2000);
}
function sectionReset() {
sections[activeSection].classList.remove('active');
}
var ready = true;
document.addEventListener('scroll', function() {
if (ready && window.pageYOffset > 0) {
ready = false;
slideDown();
} else if (ready && window.pageYOffset <= 0) {
ready = false;
slideUp();
}
});
.section__wrapper {
height: 100vh;
overflow: hidden;
}
.section__wrapper__inner {
height: 100%;
transform: translate3d(0, 0, 0);
transition: transform 1s;
}
.section {
position: relative;
height: 100vh;
color: black;
text-align: center;
}
.section span {
line-height: 100vh;
display:block;
}
<div class="section__wrapper">
<div class="section__wrapper__inner">
<section class="section"><span>1</span></section>
<section class="section"><span>2</span></section>
<section class="section"><span>3</span></section>
<section class="section"><span>4</span></section>
<section class="section"><span>5</span></section>
</div>
</div>
I think is that what you want
I have made a little workarround to force scroll ... maybe a little bit ugly but work see fakeScroll() function bellow.
That force the scrollbar to does not reach the beggining and the end. Because in your example above if the scroll bar reach the end ... scroll event can't be triggered (same if reach the begining).
I have also changed the conditions and the timming from setTimeout (ready = true) to 500. You can change it as you want
Sory for my English.
var slider = document.querySelector('.section__wrapper__inner');
var sections = document.querySelectorAll('.section');
var currentTransform = 0;
var activeSection = 0;
var lastOffset = window.pageYOffset;
var actualOffset = lastOffset;
function fakeScroll(){
if(lastOffset > 1){
window.scrollTo(0,lastOffset - 1);
}else{
window.scrollTo(0,1);
}
}
function slideDown() {
if (!(activeSection === sections.length - 1)) {
sectionReset();
currentTransform -= 100;
slider.style.transform = "translate3d(0," + currentTransform + "vh, 0)";
activeSection++;
sections[activeSection].classList.add('active');
}
fakeScroll();
setTimeout(function() {
ready = true;
}, 500);
}
function slideUp() {
if (!(activeSection === 0)) {
sectionReset();
currentTransform += 100;
slider.style.transform = "translate3d(0," + currentTransform + "vh, 0)";
activeSection--;
sections[activeSection].classList.add('active');
}
fakeScroll();
setTimeout(function() {
ready = true;
}, 500);
}
function sectionReset() {
sections[activeSection].classList.remove('active');
}
var ready = true;
window.addEventListener('scroll', function() {
actualOffset = window.pageYOffset;
if (actualOffset > lastOffset) {
if(ready){
ready = false;
slideDown();
}else{
fakeScroll();
}
} else if (window.pageYOffset <= lastOffset) {
if(ready){
ready = false;
slideUp();
}else{
fakeScroll();
}
}
lastOffset = window.pageYOffset;
});
.section__wrapper {
height: 100vh;
position:relative;
overflow: hidden;
}
.section__wrapper__inner {
height: 100%;
position:relative;
transform: translate3d(0, 0, 0);
transition: transform 1s;
}
.section {
position: relative;
height: 100vh;
color: black;
text-align: center;
}
.section span {
line-height: 100vh;
display:block;
}
<div class="section__wrapper">
<div class="section__wrapper__inner">
<section class="section"><span>1</span></section>
<section class="section"><span>2</span></section>
<section class="section"><span>3</span></section>
<section class="section"><span>4</span></section>
<section class="section"><span>5</span></section>
</div>
</div>
window.addEventListener('scroll', function() {
if (ready && window.pageYOffset > 0) {
ready = false;
slideDown();
} else if (ready && window.pageYOffset <= 0) {
ready = false;
slideUp();
}
});

jQuery autoScroll to the nearest section

If the user is place in the top half of current section it automatically scroll top of that section.
Then if the user is in the bottom half of the current section it automatically scroll to the top next section.
function autoScroll(aid){
var aTag = $("#"+ aid);
body.animate({scrollTop: aTag.offset().top},1500);
}
$(window).scroll(function() {
var windowScroll = $(window).scrollTop();
if(windowScroll < ($("#Section2").offset().top/2) && !(windowScroll > ($("#Section2").offset().top/2))){
section_id = 'Section1';
}
$(document).off('scroll');
console.log(section_id);
autoScroll(section_id);
});
http://jsfiddle.net/x6xzh69v/2/
I created a working example in CODEPEN.
$(document).ready(function() {
var origHeight = [];
var curScroll = 0;
var cumSumHeight = 0;
var animHeight = 0;
var i = 0;
var timeoutVar;
$(".section").each(function(index) {
origHeight.push($(this).height());
});
$(window).scroll(function() {
curScroll = $("body").scrollTop();
cumSumHeight = 0;
while ((cumSumHeight + origHeight[i]) < curScroll) {
cumSumHeight += origHeight[i];
i++;
}
if (i == 0) {
if (curScroll < (origHeight[i] / 2)) {
animHeight = 0;
} else {
animHeight = origHeight[i];
}
} else {
if ((curScroll - cumSumHeight) < (origHeight[i] / 2)) {
animHeight = cumSumHeight;
} else {
animHeight = origHeight[i] + cumSumHeight;
}
}
clearTimeout(timeoutVar);
timeoutVar = setTimeout(function() {
$("body").stop(true,true).animate({
scrollTop: animHeight
}, 200);
}, 300);
});
});
.section {
width: 100%;
position: relative;
height: 300px;
}
#Section1 {
background: red;
}
#Section2 {
background: blue;
}
#Section3 {
background: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="Section1" class="section"></section>
<section id="Section2" class="section"></section>
<section id="Section3" class="section"></section>

Categories

Resources