Could you please tell me how to add an active class while scrolling in a div? I have one container, in which there are four divs. In the footer I also have four li (first, second, third). I want to select the li when the user scrolls the div.
Example
When the code runs, the first li should be selected because the first div is in the view port. If the user scrolls and moves to the second div, the second li should be selected. And so on.
I tried like that
https://jsbin.com/giwizufotu/edit?html,css,js,output
(function(){
'use strict';
$(function(){
$( "#container" ).scroll(function() {
console.log('scrlling');
if (elementInViewport2($('#first'))) {
// The element is visible, do something
console.log('first visible')
} else {
console.log('second visible')
}
});
})
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
})()
I don't want to use plugin
I have tried to use almost all the code you have written with little modifications:
Here is the working example link: https://jsfiddle.net/almamun1996/21wc37sx/3/
CSS:
.item {
width:25%;
display:inline-block;
margin:0;
padding:0;
color:blue;
font-size:20px;
text-align: center;
}
.footer{
border:1px solid;
position:fixed;
width:100%;
bottom:0px;
}
#container {
border:1px solid red;
overflow:auto;
width:100%;
height:300px;
}
.fC{
background-color:yellow;
padding:0;
}
#first{
background-color:blue;
}
#second {
background-color:green;
}
#third {
background-color:pink;
}
#fourth {
background-color:red;
}
.active {
background-color : red;
}
JS:
(function(){
'use strict';
$(function(){
$('.fC li:eq(0)').css('background-color','red').css('color','#ffffff');
$( "#container" ).scroll(function() {
//console.log('scrlling');
if (elementInViewport($('#first'))) {
// The element is visible, do something
//console.log('first visible')
} else {
//console.log('second visible')
}
});
});
function elementInViewport(e) {
var winBottom = $(window).scrollTop() + $(window).height();
var visibleETop = e.offset().top - winBottom;
var first = parseInt($('#first').css('height'));
var second = parseInt($('#second').css('height'));
var third = parseInt($('#third').css('height'));
var fourth = parseInt($('#fourth').css('height'));
if(Math.abs(e.offset().top) > first - parseInt($('#container').css('height')) && Math.abs(e.offset().top) <= first+second - parseInt($('#container').css('height')))
{
$('.fC li:eq(0)').css('background-color','').css('color','');
$('.fC li:eq(2)').css('background-color','').css('color','');
$('.fC li:eq(3)').css('background-color','').css('color','');
$('.fC li:eq(1)').css('background-color','red').css('color','#ffffff');
}
else if(Math.abs(e.offset().top) > first+second - parseInt($('#container').css('height')) && Math.abs(e.offset().top) <= first+second+third - parseInt($('#container').css('height')))
{
$('.fC li:eq(0)').css('background-color','').css('color','');
$('.fC li:eq(1)').css('background-color','').css('color','');
$('.fC li:eq(3)').css('background-color','').css('color','');
$('.fC li:eq(2)').css('background-color','red').css('color','#ffffff');
}
else if(Math.abs(e.offset().top) > first+second+third - parseInt($('#container').css('height')) && Math.abs(e.offset().top) <= first+second+third+fourth - parseInt($('#container').css('height')))
{
$('.fC li:eq(0)').css('background-color','').css('color','');
$('.fC li:eq(1)').css('background-color','').css('color','');
$('.fC li:eq(2)').css('background-color','').css('color','');
$('.fC li:eq(3)').css('background-color','red').css('color','#ffffff');
}
else{
$('.fC li:eq(1)').css('background-color','').css('color','');
$('.fC li:eq(2)').css('background-color','').css('color','');
$('.fC li:eq(3)').css('background-color','').css('color','');
$('.fC li:eq(0)').css('background-color','red').css('color','#ffffff');
}
if(visibleETop < 0){
return false;
}else{
return true;
}
}
})();
HTML:
Just replace the id='three' to id='third' in third div from your html.
You should consider changing class based on one edge-
function elementInViewport(e) {
var winBottom = $(window).scrollTop() + $(window).height();
var visibleETop = e.offset().top - winBottom;
if(visibleETop < 0){
return false;
}else{
return true;
}
}
Related
My HTML has a div and when I hover the div a card will be displayed on the right side. When the div is in left side then this still show right side. When I reduce the browser width then this card partially show the detail.
How to automatically position using jquery.
var thisEl = $(this);
var offsets = thisEl.offset();
var thisElTopOffset = offsets.top;
var thisElLeftOffset = offsets.left;
This will show as i mentioned in the image. But i try to position the div to left when the elements are in right.
Code: I tried so far
allHoverCardTriggers.on({
click: function(event) {
event.preventDefault();
var thisEl = $(this);
cardTimer = setTimeout(function(){
var docWidth = $(document).width();
var rightSide = false;
//return user id
var userLink = thisEl.attr('href');
if($('.ViewProfilePage').length && $('img.lia-user-avatar-profile',thisEl).length){
var userLink = document.location.href;
} else if(thisEl.attr('href')=='#'){
return false;
}
var thisLen = (userLink).split('/');
thisUserID = (thisLen)[thisLen.length-1];
var thisCard = $('.profileCard[data-user='+thisUserID+']',cardWrapper);
var offsets = thisEl.offset();
var thisElTopOffset = offsets.top;
var thisElLeftOffset = offsets.left;
if(thisCard.length && $('.profileCard[data-user='+thisUserID+'] .preloader',cardWrapper).length<1)
{
$('.profileCard',cardWrapper).hide();
rightSide?thisCard.addClass('rightArrow'):thisCard.removeClass('rightArrow');
thisCard.delay(500).css({'top':thisElTopOffset,'left':thisElLeftOffset}).stop().show();
}
else
{
var ajaxReturn = '';
thisCard.remove();
//profile card wrapper markup
var rightArrowClass = rightSide?'rightArrow':'';
var profileCardHtml = '<div class="profileCard '+rightArrowClass+'" style="display:block;top:'+thisElTopOffset+'px;left:'+thisElLeftOffset+'px;" data-user="'+thisUserID+'"><div class="inner"><img src="/html/assets/feedback_loading_trans.gif" class="preloader" style="margin:80px auto;display:block;" /></div></div>';
$.when(
//get the background
$.ajax({
type: 'GET',
url: userApiUrl+thisUserID,
dataType: 'html',
success: function(data) {
$('.profileCard',cardWrapper).hide();
ajaxReturn = data;
}
})
)
.done(function(){
cardWrapper.append(profileCardHtml);
$('.profileCard[data-user='+thisUserID+']',cardWrapper).eq(0).empty().html(ajaxReturn);
if($('.profileCard[data-user='+thisUserID+'] .preloader',cardWrapper).length){
$('.profileCard[data-user='+thisUserID+'] .preloader',cardWrapper).parents('div.profileCard').remove();
}
})
.fail(function(){
// Hide if failed request
$('.profileCard',cardWrapper).hide();
});
}
}
},400);
},
mouseleave: function() {
clearTimeout(cardTimer);
if($('.profileCard[data-user='+thisUserID+']',cardWrapper).length){
$('.profileCard[data-user='+thisUserID+']',cardWrapper).delay(500).fadeOut('fast');
}
}
});
}
Here is a jQuery solution. Prior to displaying the popup, the script checks if the offset position of the trigger div plus the popup width falls beyond the screen width and adjusts the popup position accordingly.
hover = function(e) {
//var position = e.position();
var popup = $('.popup');
popup.attr('style', '');
if (e.offsetLeft + popup.outerWidth() > $( window ).width()) {
// adjust for screen width
popup.css({
right: $( window ).width() - e.offsetLeft - e.offsetWidth + 'px',
top: e.offsetTop - popup.outerHeight()
});
}
else {
// position normally
popup.css({
left: e.offsetLeft,
top: e.offsetTop - popup.outerHeight()
});
}
popup.show();
}
hide = function() {
$('.popup').hide();
}
.left-hover {
position:absolute;
left:20px;
top:80px;
border:1px solid black;
}
.right-hover {
position:absolute;
right:20px;
top:80px;
border:1px solid black;
}
.popup {
position:absolute;
display:none;
border:1px solid red;
width:100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="left-hover" onmouseover="hover(this)" onmouseout="hide()">Hover me</div>
<div class="right-hover" onmouseover="hover(this)" onmouseout="hide()">Hover me</div>
<div class="popup">My popup</div>
I have editable div with overflow set to hidden, I'd like the div to expand as the user types (if needed). II'm using jquery to change the class of the div each time the height changes.
I cant seem to get to work at all, it chnages the class but nothing happens
Fiddle
HTML:
<div class="contanier">
<div class="1" id="msgWriteArea" contenteditable="true"></div>
</div>
CSS:
#msgWriteArea{
outline: 0;
border: none;
resize: none;
width: 100%;
height:20px;
line-height:20px;
font-size:18px;
border:solid 1px #000;
background:#FFF;
}
.contanier .1{
height:20px;
overflow:hidden;
}
.contanier .2{
height:40px;
overflow:hidden;
}
.contanier .3{
height:60px;
overflow:hidden;
}
.contanier .4{
height:80px;
overflow:hidden;
}
.contanier .5{
height:80px;
overflow-y:scroll;
}
Javascript:
var chatBoxSize = {
oldHeight : 0,
scrollHeight : 0,
lastClass : 1,
maxClass : 5
};
function updateChatSize() {
var id = '#msgWriteArea';
var element = document.querySelector(id);
if((element.offsetHeight < element.scrollHeight) || (element.offsetWidth < element.scrollWidth)){
if(chatBoxSize.lastClass == null){
//add size 1
console.log('ADD SIZE 1');
$(id).addClass('1');
chatBoxSize.lastClass = '1';
} else if(chatBoxSize.oldHeight != $(id)[0].scrollHeight){
//get the correct size to add
if(parseInt(current) >= parseInt(chatBoxSize.maxClass)){
var current = chatBoxSize.maxClass,
last = parseInt(chatBoxSize.maxClass) - 1;
chatBoxSize.lastClass = current;
console.log('IS AT MAX SIZE');
} else if(chatBoxSize.scrollHeight < $(id)[0].scrollHeight){
var current = parseInt(chatBoxSize.lastClass) + 1,
last = parseInt(chatBoxSize.lastClass);
chatBoxSize.lastClass = current;
} else if(chatBoxSize.scrollHeight > $(id)[0].scrollHeight) {
var current = parseInt(chatBoxSize.lastClass) - 1,
last = parseInt(chatBoxSize.lastClass);
chatBoxSize.lastClass = current;
} else {
//console.log('No Change in height');
}
if(last != undefined){
console.log('Add', current, 'Remove', last);
$('#msgWriteArea').addClass(current + "");
$('#msgWriteArea').removeClass(last + "");
$('#display').val('Add ' + current + ' Remove' + last);
}
}
chatBoxSize.oldHeight = element.offsetHeight;
chatBoxSize.scrollHeight = $(id)[0].scrollHeight;
chatBoxSize.oldHeight = element.offsetHeight;
}
};
$(function (){
$('#msgWriteArea').bind('change keydown input', function () {
if(event.type == 'keydown'){
updateChatSize();
}
});
});
This is part of a larger page. So would need to the class to change on other elements but just one for now to get the hang of how this works
You can do it by adding this CSS:
#msgWriteArea{
height: auto !important;
max-height: 80px; // Max Chat Box Size..
overflow-y: scroll;
}
See JsFiddle
if you set a fix height to contenteditable this won't expand vertically,
so to begin with remove height attribute;
then using line-height attribute instead of el.offsetHeight (in the evaluation for adding a class depending on height) should fix your fiddle;
fiddle
I've some trouble with my script, I'm trying to figure out how I can make a mask/filter over the website when the menu is opened. In the HTML is a class called cmask and there is also a class called cmask is-active
It only has to do this when the screen is smaller than 900px. I've been trying to use cmask.addClass("is-active") and removeclass but its not working like that and it keeps crashing(makes the other part of the script not working anymore). Does someone knows what im doing wrong?
//scrolling----------------
//scrolling----------------
//scrolling----------------
var nav = $("#nav_id");
var nav_overflow = $("#nav_overflow");
var page_end_logo_nav = $("#page_end_logo_nav").visible();
var logo_container = $("#logo_container");
var nav_ani_speed = 200 //in ms
var nav_state = 0 // 0 is nav 1 is hamburger visable
var hamburger = $("#hamburgermenu") //hamburger elemnt
var distanceY;
var shrinkOn;
var winkel_mand = $("#winkel_mand")
//set scroll for desktop nav
function nav_desktop_check() {
distanceY = window.pageYOffset || document.documentElement.scrollTop;
shrinkOn = 100;
//run the header script
if (distanceY > shrinkOn) {
if (nav_state === 0) {
nav_hamburger();
}
} else {
if (nav_state === 1 ){
if ($(window).width() >= 900){
nav_normal_desktop();
}
}
}
}
//tablet nav check
function tablet_nav_check() {
if (nav_state === 0){
if ($(window).width() <= 900){
nav_hamburger();
}
}
}
tablet_nav_check()
//hambutton onclikc
hamburger.click(function() {
if (nav_state === 1){
if ($(window).width() >= 900){
nav_normal_desktop();
} else {
nav_normal_mobile();
}
logo_animation();
remove_winkel_icon_check()
} else{
nav_hamburger()
}
});
//nav to hamburger
function nav_hamburger() {
hamburger.removeClass("active")
nav_overflow.animate({
width: 0
}, nav_ani_speed, function() {
hamburger.addClass("active")
});
nav_state = 1;
logo_animation();
}
//hamburger to nav
function nav_normal_desktop() {
hamburger.addClass("active");
hamburger.removeClass("active");
nav_overflow.css("width", "auto");
nav_witdh = nav_overflow.innerWidth();
nav_overflow.css("width", 0);
nav_overflow.animate({
width: nav_witdh
}, nav_ani_speed, function() {
hamburger.removeClass("active")
});
nav_state = 0;
}
function nav_normal_mobile() {
nav_overflow.animate({
width: "100%"
}, nav_ani_speed, function() {
hamburger.removeClass("active")
});
nav_state = 0;
}
First I would add semicolons to all statements where it could fit, just to be sure you are not missing a mandatory one.
I've made a small overlay mask example
Javascript
$('#element').on("click",function() {
if($('#overlay').length == 0) {
$(this).wrap('<div id="overlay"><div>');
} else {
$(this).unwrap();
}
});
CSS
#element {
width:200px;
height:200px;
background-color:#f00;
}
#inner {
width:100px;
height:100px;
background-color:#0ff;
}
#overlay
{
background-color:#000;
opacity:0.3;
width:200px;
height:200px;
}
http://jsfiddle.net/5aw0wsy4/
CLICK FOR FIDDLE
Below is a fully functional full page touch slider I have created using hammer.js
You can drag, swipe or pan to navigate between pages.
The slider works as expected but I am now trying to create fallback navigation by adding two buttons so paging left and right can occur on click also.
QUESTION
How can the hammer swipe left or right be called on click? (Javascript or jQuery).
CURRENT ATTEMPT
$('#Left').on('click', function() {
HammerCarousel(document.querySelector('.Swiper'), 'Left');
});
FULL CODE
function swipe() {
var reqAnimationFrame = (function () {
return window[Hammer.prefixed(window, "requestAnimationFrame")] || function (callback) {
setTimeout(callback, 1000 / 60);
}
})();
function dirProp(direction, hProp, vProp) {
return (direction & Hammer.DIRECTION_HORIZONTAL) ? hProp : vProp
}
function HammerCarousel(container, direction) {
this.container = container;
this.direction = direction;
this.panes = Array.prototype.slice.call(this.container.children, 0);
this.containerSize = this.container[dirProp(direction, 'offsetWidth', 'offsetHeight')];
this.currentIndex = 0;
this.hammer = new Hammer.Manager(this.container);
this.hammer.add(new Hammer.Pan({ direction: this.direction, threshold: 10 }));
this.hammer.on("panstart panmove panend pancancel", Hammer.bindFn(this.onPan, this));
this.show(this.currentIndex);
}
HammerCarousel.prototype = {
show: function (showIndex, percent, animate) {
showIndex = Math.max(0, Math.min(showIndex, this.panes.length - 1));
percent = percent || 0;
var className = this.container.className;
if (animate) {
if (className.indexOf('animate') === -1) {
this.container.className += ' animate';
}
} else {
if (className.indexOf('animate') !== -1) {
this.container.className = className.replace('animate', '').trim();
}
}
var paneIndex, pos, translate;
for (paneIndex = 0; paneIndex < this.panes.length; paneIndex++) {
pos = (this.containerSize / 100) * (((paneIndex - showIndex) * 100) + percent);
translate = 'translate3d(' + pos + 'px, 0, 0)';
this.panes[paneIndex].style.transform = translate;
this.panes[paneIndex].style.mozTransform = translate;
this.panes[paneIndex].style.webkitTransform = translate;
}
this.currentIndex = showIndex;
},
onPan: function (ev) {
var delta = dirProp(this.direction, ev.deltaX, ev.deltaY),
percent = (100 / this.containerSize) * delta,
animate = false;
if (ev.type == 'panend' || ev.type == 'pancancel') {
if (Math.abs(percent) > 20 && ev.type == 'panend') {
this.currentIndex += (percent < 0) ? 1 : -1;
}
percent = 0;
animate = true;
}
this.show(this.currentIndex, percent, animate);
}
};
var outer = new HammerCarousel(document.querySelector('.Swiper'), Hammer.DIRECTION_HORIZONTAL);
};
$(swipe);
html,
body,
.Page,
.Swiper{
position:relative;
height:100%;
}
.Swiper{
background:#666;
overflow:hidden;
}
.Swiper.animate > .Page{
transition:all .3s;
-webkit-transition:all .3s;
}
.Page{
position:absolute;
top:0;
left:0;
height:100%;
width:100%;
padding:0 10px;
font:42px Arial;
color:#fff;
padding-top:10%;
text-align:center;
}
.Page:nth-child(odd) {
background:#b00;
}
.Page:nth-child(even) {
background:#58c;
}
#Left,
#Right{
position:absolute;
top:0;
height:50px;
width:50px;
background:#fff;
text-align:center;
font:16px/3em Arial;
cursor:pointer;
}
#Left{
left:0;
}
#Right{
right:0;
}
<script src="http://hammerjs.github.io/dist/hammer.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="Swiper">
<div class="Page">PAGE 1<br/>DRAG LEFT</div>
<div class="Page">PAGE 2<br/>SWIPE ME</div>
<div class="Page">PAGE 3<br/>HOLD TO PAN</div>
<div class="Page">PAGE 4<br/>FLICK TO GO BACK</div>
</div>
<div id="Left">Left</div>
<div id="Right">Right</div>
I have crafted a jQuery solution for this that should satisfy the fallback you are looking for.
Some things to consider, though. In your example as well, page re-size is not accounted for. I have not done so in this either to remain consistent and solve the immediate issue, but you will notice I am grabbing the $('.Page').width(); as a variable in this solution. I would recommend re-assigning this value if you do account for re-sizing. Also, a mix of swiping/clicking will throw this off. I assume since you indicated this will be a fallback, the user will receive one of the two experiences. If not, we'll need a way to update tracker on swipe events as well.
You'll notice var tracker = { 'R': 0 }. While naming may not be the best, 'R' will account for how many right "swipes" (navigation clicks) the user has performed in a plus/minus 1 manner
<div id="Left" direction="L">Left</div>
<div id="Right" direction="R">Right</div>
$(function() {
var width = $('.Page').width();
var pages = $('.Page').length;
var tracker = { 'R': 0 }
$('#Right, #Left').click(function() {
$(this).attr('direction') === 'R' ?
((tracker.R < (pages - 1) ? tracker.R += 1 : pages)) :
(tracker.R > 0) ? (tracker.R -= 1) : 0;
$('.Swiper').animate({ 'scrollLeft': $('.Page').width() * tracker.R }, 250)
});
});
JSFiddle Link
I'm having a horizontal scrolling page where arrows are indicated to scroll. I'm using the following code which works fine.
HTML:
<div id="container">
<div id="parent">
<div class="contentBlock">1</div>
<div class="contentBlock">2</div>
<div class="contentBlock">3</div>
<div class="contentBlock">4</div>
<div class="contentBlock">5</div>
</div>
<span id="panLeft" class="panner" data-scroll-modifier='-1'>Left</span>
<span id="panRight" class="panner" data-scroll-modifier='1'>Right</span>
CSS:
#container{
width:600px;
overflow-x:hidden;
}
#parent {
width:6000px;
}
.contentBlock {
font-size:10em;
text-align:center;
line-height:400px;
height:400px;
width:500px;
margin:10px;
border:1px solid black;
float:left;
}
.panner {
border:1px solid black;
display:block;
position:fixed;
width:50px;
height:50px;
top:45%;
}
.active {
color:red;
}
#panLeft {
left:0px;
}
#panRight {
right:0px;
}
Javascript:
(function () {
var scrollHandle = 0,
scrollStep = 5,
parent = $("#container");
//Start the scrolling process
$(".panner").on("mouseenter", function () {
var data = $(this).data('scrollModifier'),
direction = parseInt(data, 10);
$(this).addClass('active');
startScrolling(direction, scrollStep);
});
//Kill the scrolling
$(".panner").on("mouseleave", function () {
stopScrolling();
$(this).removeClass('active');
});
//Actual handling of the scrolling
function startScrolling(modifier, step) {
if (scrollHandle === 0) {
scrollHandle = setInterval(function () {
var newOffset = parent.scrollLeft() + (scrollStep * modifier);
parent.scrollLeft(newOffset);
}, 10);
}
}
function stopScrolling() {
clearInterval(scrollHandle);
scrollHandle = 0;
}
}());
You can also view the code in a WordPress-Installation right here: http://ustria-steila.ch/test
The arrows and the scroll works really well - but I have different sites with different amounts of text and images. So some pages need a horizontal scroll and some not. How can I add some kind of if-condition to display the arrows only if there is a horizontal overflow?
Your JavaScript code should go like this:
(function () {
var scrollHandle = 0,
scrollStep = 5,
parent = $("#container");
if(checkOverflow()){
$(".panner").show();
}
else
$(".panner").hide();
//Start the scrolling process
$(".panner").on("mouseenter", function () {
var data = $(this).data('scrollModifier'),
direction = parseInt(data, 10);
$(this).addClass('active');
startScrolling(direction, scrollStep);
});
//Kill the scrolling
$(".panner").on("mouseleave", function () {
stopScrolling();
$(this).removeClass('active');
});
//Actual handling of the scrolling
function startScrolling(modifier, step) {
if (scrollHandle === 0) {
scrollHandle = setInterval(function () {
var newOffset = parent.scrollLeft() + (scrollStep * modifier);
parent.scrollLeft(newOffset);
}, 10);
}
}
function stopScrolling() {
clearInterval(scrollHandle);
scrollHandle = 0;
}
function checkOverflow()
{
var el=document.getElementById('container');
var curOverflow = el.style.overflowX;
if ( !curOverflow || curOverflow === "visible" )
el.style.overflowX = "hidden";
var isOverflowing = el.clientWidth < el.scrollWidth;
el.style.overflowX = curOverflow;
return isOverflowing;
}
}());