In my webpage I have 4 "waypoints" that have their respective links in a menu. What I need is to also bind the scroll of the page to these waypoints. So when the page loads, the pointer is at the top and based on the scrolling direction, the page moves to the next/previous waypoint. Until now I have come up with this simplistic approach, which goes into a scroll loop due to the scrollTo() function triggering the whole method again.
$(function () {
var top = $(window).scrollTop();
var currentWaypoint = 0;
var previousWaypoint = 0;
$(window).scroll(function () {
console.log("Scroll triggered");
console.log("Current Waypoint: " + currentWaypoint);
var curTop = $(window).scrollTop();
if (top < curTop) {
if (currentWaypoint < 4) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint+1;
}
}
else {
if (currentWaypoint > 0) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint-1;
}
}
top = curTop;
if (previousWaypoint != currentWaypoint) {
switch (currentWaypoint) {
case 1:
$.scrollTo(document.getElementById("waypoint-collection"));
case 2:
$.scrollTo(document.getElementById("waypoint-report"));
case 3:
$.scrollTo(document.getElementById("waypoint-video"));
case 4:
$.scrollTo(document.getElementById("waypoint-mail"));
default:
}
}
console.log("New Waypoint: " + currentWaypoint);
});
});
I've seen this sort of behaviour implemented in some websites but cannot seem to find anything relevant with google. Any ideas?
EDIT:
The relevant HTML code:
<html>
<head>
<style>
body {
background-color: #FFFFFF;
}
.features-container-wh {
min-height: 12.5rem;
text-align: center;
height: 100%;
}
.features-container-bl {
background-color: #43bfcb;
text-align: center;
color: #FFFFFF;
height: 100%;
}
.features-container-bottom {
height: 100%;
}
</style>
</head>
<body>
<div class="features-container-wh">
Collection
Report
Video
Mail
</div>
<div class="features-container-bl" id="waypoint-collection">
<p>Stuff...</p>
</div>
<div class="features-container-wh" id="waypoint-report">
<p>Stuff...</p>
</div>
<div class="features-container-bl" id="waypoint-video">
<p>Stuff...</p>
</div>
<div class="features-container-bottom" id="waypoint-mail">
<p>Stuff...</p>
</div>
</body>
$('html, body').animate({scrollTop: $("#.wayPoint1").offset().top}, 2000);
Related
Check the demo here: https://jsfiddle.net/g2djbwm5/1/
Scroll the page untill the input is visible.
Type in something but keep the focus into it
Using the mouse scroll the page again until the input is no longer visible
Now type in something
Input will be scrolled into view to the very top like this
Is there any way to show this input not very top but some 20px from the top when user type in? something like
Code:
<div style="width: 100%; height: 800px;">..............</div>
<input type="text"/>
<div style="width: 100%; height: 800px;" />
In CSS you can use this to make the scroll stops some px above:
scroll-margin-top: 50px;
an example here
Create a function to locate the y position of the element -> input. Then an event listener for input and conditional to check the position of the element. If it is off the page when focused and the event is input, place it on top and change the position to sticky else position relative.
let input = document.getElementById('input');
let inputPos = -1;
if (input === document.activeElement) {
input.addEventListener("input", () => {
if (inputPos < 0) inputPos = findPosY(input);
if (pageYOffset > inputPos) {
input.style.cssText = 'position:sticky; top: 0px; bottom: 0px;';
} else {
input.style.position = 'relative;';
}
});
}
function findPosY(obj) {
let curtop = 0;
if (typeof(obj.offsetParent) != 'undefined' && obj.offsetParent) {
while (obj.offsetParent) {
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
curtop += obj.offsetTop;
} else if (obj.y)
curtop += obj.y;
return curtop;
}
<div style="width: 100%; height: 800px;">..............</div>
<input id="input" type="text" />
<div class="input" style="width: 100%; height: 1800px;" />
This decision comes to my mind, but this solution is a "crutch" (hack).
The problem with this solution is that when scrolling, the input loses its sticky positioning and returns its default coordinates.
If my small solution is modified, taking into account the preservation of the position of the input when scrolling, then the solution will be good, as it seems to me.
let input_text = document.querySelector('input[type="text"]');
input_text.oninput = function() {
this.classList.add('top_for_input');
}
window.onscroll = function() {
input_text.classList.remove('top_for_input');
}
.top_for_input {
position: sticky;
top: 20px;
bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="width: 100%; height: 800px;">..............</div>
<input type="text"/>
<div style="width: 100%; height: 800px;" />
I have a fixed div on the page which contains a logo and as the user scrolls and this logo passes over other divs I wnat to the change the colour of the logo.
I have this working over a single div but need to it work across multiple so any help appreciated.
The WIP site can be seen here... dd.mintfresh.co.uk - if you scroll down you'll (hopefully) see the logo change from black to white as it crosses an illustrated egg. I need the same to happen when it crosses other divs further down the page.
The script so far...
jQuery(window).scroll(function(){
var fixed = jQuery("logo");
var fixed_position = jQuery("#logo").offset().top;
var fixed_height = jQuery("#logo").height();
var toCross_position = jQuery("#egg").offset().top;
var toCross_height = jQuery("#egg").height();
if (fixed_position + fixed_height < toCross_position) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else if (fixed_position > toCross_position + toCross_height) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else {
jQuery("#logo img").css({filter : "invert(0%)"});
}
}
);
Any help appreciated. Thanks!
you need to fire a div scroll event. you can assign
$("div1").scroll(function(){
//change the color of the div1
}
});
$("div2").scroll(function(){
//change the color of the div2
}
});
or you can assign a class to divs which you want to change the color
$(".div").scroll(function(){
//change the color of the div which you are scrolling now
}
});
You can use like this :-
$(window).scroll(function() {
var that = $(this);
$('.section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('active')) {
$('.logo').addClass('invert');
} else {
$('.logo').removeClass('invert');
}
}
});
});
body {
padding: 0;
margin: 0;
}
div {
background: #f00;
height: 400px;
}
.logo {
position: fixed;
top: 0;
left: 0;
width: 100px;
}
.logo.invert {
filter: invert(100%);
}
div:nth-child(even) {
background: #ff0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="https://dd.mintfresh.co.uk/wp-content/uploads/2018/06/DD_logo.svg" class="logo" />
<div id="page1" class="section"></div>
<div id="page2" class="section active"></div>
<div id="page3" class="section"></div>
<div id="page4" class="section active"></div>
<div id="page5" class="section"></div>
As your site code you can do like this :
$(window).scroll(function() {
var that = $(this);
$('#content > section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('black')) {
$('#logo img').css({filter: 'invert(0%)'});
} else {
$('#logo img').css({filter: 'invert(100%)'});
}
}
});
});
I know the question of closing a pop-up by clicking outside of it has been asked before. I have a somewhat complex pop-up and the solution offered by Phillip Walton isn't working for me.
His code simply made my page blurry but stopped the popup from appearing.
$(document).on('click', function(event) {
if (!$(event.target).closest('.maincontainer').length) {
popup.classList.remove('popup--open');
popup.style.display = 'none';
popupAccessory.style.display = 'none';
popupAccessory.classList.remove('popup--accessory--open');
maincontainer.classList.remove('blurfilter');
}
});
I also tried:
window.addEventListener('click', function(event) {
if (event.target != popup) {
popup.classList.remove('popup--open');
popup.style.display = 'none';
popupAccessory.style.display = 'none';
popupAccessory.classList.remove('popup--accessory--open');
maincontainer.classList.remove('blurfilter');
}
}, true);
This closes the popup when I click anywhere, including on the popup itself. I want it to close only when I click on part of the screen that isn't the popup.
The code to open the popup:
function openpopup() {
popup.style.display = 'initial';
setTimeout(function(){
popup.classList.add('popup--open');
popup.style.boxShadow = '0 0 45px 2px white';
maincontainer.classList.add('blurfilter')}, 10);
for (let i = 0; i < listitems.length; i++ ) {
setTimeout(function() {
listitems[i].classList.add('visible');
}, 100);
}
}
I added the event listener to a button
popupOpenbtn.addEventListener('click', openpopup);
The HTML structure:-
<div class="maincontainer>
...all my page content...
</div>
<div class="popup">
...popup contents...
</div
I would suggest using only css classes to style your popup and use JS only to add, remove and toggle that class. Not sure how close to your working exercise is this fiddle but I've prepared this to show how the document/window click event can be checked to successfully open/close the popup window.
var popupOverlay = document.querySelector('#popup__overlay');
var popupOpenButton = document.querySelector('#popupOpenButton');
var popupCloseButton = document.querySelector('#popupCloseButton');
var mainContainer = document.querySelector('main');
function closestById(el, id) {
while (el.id != id) {
el = el.parentNode;
if (!el) {
return null;
}
}
return el;
}
popupOpenButton.addEventListener('click', function(event) {
popupOverlay.classList.toggle('isVisible');
});
popupCloseButton.addEventListener('click', function(event) {
popupOverlay.classList.toggle('isVisible');
});
mainContainer.addEventListener('click', function(event) {
if (popupOverlay.classList.contains('isVisible') && !closestById(event.target, 'popup__overlay') && event.target !== popupOpenButton) {
popupOverlay.classList.toggle('isVisible');
}
});
#popup__overlay {
display: none;
background-color: rgba(180, 180, 180, 0.5);
position: absolute;
top: 100px;
bottom: 100px;
left: 100px;
right: 100px;
z-index: 9999;
text-align: center;
}
#popup__overlay.isVisible {
display: block;
}
main {
height: 100vh;
}
<aside id="popup__overlay">
<div class="popup">
<h2>Popup title</h2>
<p>
Lorem ipsum
</p>
<button id="popupCloseButton">Close popup</button>
</div>
</aside>
<main>
<div class="buttonWrapper">
<button id="popupOpenButton">Open popup</button>
</div>
</main>
I am creating a simple website which should have multiple pages showing a different background and main text, but with the same logo and menu. The next page should slide in from the right when a button is pressed and selecting a page from the menu should transition directly to that page. I have decided to make this a single page site to make use of CSS3 transitions. Example code for the next button (minus transitions) is here: http://jsfiddle.net/xoa029jz/1/
I am currently working out which background and text to display using the following javascript:
function getNextPage(pageid) {
if (pageid == "page-1") {
return $('#page-2');
} else if (pageid == "page-2") {
return $('#page-3');
} else if (pageid == "page-3") {
return $('#page-1');
}
}
The site will have 7 pages, so this seems cumbersome. Is there a better way of using sequential ids in javascript?
The site will only have one image and one sentence per "page", so I don't think it is necessary to use Ajax, but I am willing to be corrected on this.
You can use class in this case which will not bound you for any number of pages,
function getNextPage(pageid) {
if($('.current-page').next('.page-text').length){
return $('.current-page').next('.page-text');
}
return $('.page-text:first');
}
function slideToNext() {
var currentPage = $('.current-page');
var nextPage = getNextPage(currentPage.attr('id'));
$(currentPage).removeClass('current-page');
$(nextPage).addClass('current-page');
var currentBackground = getCurrentBackground();
var nextBackground = getNextBackground(currentBackground);
$('#bg').removeClass(currentBackground);
$('#bg').addClass(nextBackground);
}
function getNextPage(pageid) {
if($('.current-page').next('.page-text').length){
return $('.current-page').next('.page-text');
}
return $('.page-text:first');
}
function getCurrentBackground() {
var bg = $('#bg');
if (bg.hasClass('bg-1')) {
return "bg-1";
} else if (bg.hasClass('bg-2')) {
return "bg-2";
} else if (bg.hasClass('bg-3')) {
return "bg-3";
}
}
function getNextBackground(bg) {
if (bg == "bg-1") {
return "bg-2";
} else if (bg == "bg-2") {
return "bg-3";
} else if (bg == "bg-3") {
return "bg-1";
}
}
.page {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-size: cover;
background-position: center center;
z-index:1;
}
.page-text {
margin-top: 71px;
display: none;
}
.current-page {
display: inline;
visibility: visible;
}
.bg-1 {
background-color:#D8F6CE;
}
.bg-2 {
background-color:#CEECF5;
}
.bg-3 {
background-color:#E2A9F3;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<body class="page bg-1" id="bg">
<div id="page">
<img id="logo" src="images/logo.png" width="295" height="92" />
<div id="menu">
<ul>
<li>
<button>Page 1</button>
</li>
<li>
<button>Page 2</button>
</li>
<li>
<button>Page 3</button>
</li>
</ul>
</div>
<div class="page-text current-page" id="page1">Page 1 text</div>
<div class="page-text" id="page2">Page 2 text</div>
<div class="page-text" id="page3">Page 3 text</div>
<button type="button" onclick="slideToNext()">Next</button>
</div>
</body>
Yes. Get the ID as a number, and increment it:
var num = +pageid[5];
if (num < 7) {
return $('#page-'+(num+1));
}
return $('#page-1');
If there is only 7 pages, cant u loop it, like:
for(var i=0;i<=7;i++){
if (pageid == "page-"+i) {
return $('#page-'+i);
}
}
Change your code to this
//just remove the word page so that only the number will left (e.g. "page"1 )
var nextPage = getNextPage(currentPage.attr('id').replace('page', ''));
Then your function will be shorter and no element count hard coding.
function getNextPage(pageid) {
return $('#page' + (pageid + 1)); //just take care the logic for returning to first page
}
I have added 2 codes here the window.scroll works on my example but not the second one binding the div to the scroll.
Any one knows what am I doing wrong!?
Just so you know I'm working in MeteorJS <- I dont think that this is the problem bc. the window scrolling works.
This 2 codes are in the same js file.
$(window).scroll(function() {
lastSession = Session.get('c_info')[Session.get('c_info').current]
if(lastSession.list == 0 && $(window).height() + $(window).scrollTop() >= $(document).height()){
lastItem = $( ".list-item div:last" ).html();
if (lastSession.page == 1){
currentSession().more();
lastItem2 = $( ".list-item div:last" ).html();
} else if( lastItem2 != lastItem) {
currentSession().more();
lastItem2 = $( ".list-item div:last" ).html()
}
}
});
$('#playlist').bind('scroll',function() {
console.log("div is scrolling");
});
I tried this too:
$('#playlist').scroll(function() {
console.log("div is scrolling");
});
MeteorJS Template:
<template name="playList">
<div id="playlist" class="playlist show-for-large-up">
{{#each list}}
<a href="/video/{{_id}}" class="large-12 columns" id="pl{{v_id}}">
<div>
<div class="large-7 columns plRight">
<span>{{vTitle}}</span>
</div>
</div>
</a>
{{/each}}
</div>
</template>
Also Tried:
$('#playlist').on('scroll',function() {console.log('test')});// not working
Tried to Change the id name and putting on the document ready:
$( document ).ready(function (){
$('#pl_list').bind('scroll',function() {
console.log("div is scrolling");
});
})//failed
The div has a scrollbar and the list is long and i have a css like this:
.playlist {
padding: 0;
overflow-y: scroll;
height: 458px;
}
Also tried:
Template.playList.rendered = function () {
console.log("playlist rendered");// i can see this on logs this tells that template is in doom
Meteor.setTimeout(function(){
$('#playlist').on('scroll',function(){
console.log('Scrolling...');
});
}, 2000);// with settimeout i have giveng it 2 more seconds
}
Try this out -
$(document).ready(function(){
$('#playlist').on('scroll',function(){
console.log('Scrolling...');
});
});
Use
$('#playlist').scroll(function() {
console.log("div is scrolling");
});
instead (like you did for window).
Thats the purpose of scroll(). See jquery documentation.
Scrolling event is fired on the element, if it has scrolled. So if you only scrolling the "body" element of the DOM it will not be triggered for #playlist.
So you have put a scrollbar to the container element of #playlist. Shot answer, cut the height and add a scrollbar, then the event will fire on it.
I did a Jsfiddle http://jsfiddle.net/34j0qnpg/4/
html
<div id="playlist-wrapper">
<div id="playlist" class="playlist show-for-large-up">
<a href="/video/1" class="large-12 columns" id="pl1">
<div>
<div class="large-7 columns plRight">
<span>Titel</span>
</div>
</div>
</a>
css part
body, html {
padding: 0;
margin: 0;
background-color: lightgrey;
color: #fff;
font-family: Arial;
height: 5000px;
overflow-y:scroll;
}
#stats {
position: relative;
}
#playlist-wrapper {
border: 1px solid #000;
padding: 10px;
height: 300px;
overflow-y: scroll;
}
#playlist {
height: 1000px;
background-color: darkgrey;
}
var $stats = $('#stats');
$('#playlist-wrapper').on('scroll', function() {
$stats.html('playlist scrolling');
console.log('playlist scrolling');
});
$(window).on('scroll', function() {
$stats.html('window scrolling');
console.log('window scrolling');
});
Solved with this code:
Tried it earlyer no results, after meteorjs project reset it just automagicly workded:
Template.playList.rendered = function () {
console.log("playlist rendered");
$('#playlist').on('scroll',function(){
console.log('Scrolling...');
});
}
I answered my question just if anybody is searching for the same answer.
Thanks to anybody who tried to help me.
I LOVE THIS COMMUNITY.