Add and remove classes depending on scroll event - javascript

I want to add and remove classes depending on whether the user scrolls down or up. So far I tried this with wheelDelta event. There is no scrollbar, the page uses 100vw and 100vw with overflow hidden. I want to achieve something similar to this: http://www.sound-of-change.com/#/intro/.
HTML
<div id="wrapper">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
<div class="item-4"></div>
</div>
CSS
#wrapper {
width:100vw;
height:100vh;
overflow:hidden;
}
So whenever a user scrolls I want to be able to add and remove classes for each time someone scrolls down or up.
For example, the user is able to scroll down or up 4 times. And actually goes up or down (depending on the scroll direction) in the actions list.
Default: Situation 0
Scroll down once -> Situation 1
Scroll down again -> Situation 2
But if the users scrolls up now -> Situation 1 will be triggered
Scroll down again -> Back to situation 2
Scroll down again -> Situation 3
So far I only managed to trigger an event on scroll up and down, but that's it. Example:
$('body').bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta /120 > 0) {
$(".cd-background-wrapper").css({'-webkit-filter': "grayscale(0%)"});
$(".logo-text").removeClass("hide-logo");
$(".logo-img").removeClass("come-closer");
}
else{
$(".cd-background-wrapper").css({'-webkit-filter': "grayscale(100%)"});
$(".logo-text").addClass("hide-logo");
$(".logo-img").addClass("come-closer");
}
});

Use a counter to know which situation you are, something like this:
var count = 1;
$("body").on('mousewheel', function(e) {
if (e.originalEvent.wheelDelta / 120 > 0) {
count -= 1;
} else {
count += 1;
}
if (count < 1) count = 1;
if (count > 4) count = 4;
switch (count) {
case 1:
// do something
break;
case 2:
// do something
break;
case 3:
// do something
break;
case 4:
// do something
break;
}
// Just a example that it works
$("#wrapper").attr("data-slide", count);
});
body {
margin: 0;
}
[data-slide="1"] {
background-color: red;
}
[data-slide="2"] {
background-color: green;
}
[data-slide="3"] {
background-color: blue;
}
[data-slide="4"] {
background-color: orange;
}
#wrapper {
width: 100vw;
height: 100vh;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper" data-slide="1"></div>

Related

Trigger multiple click events while a button or anchor is pressed using JQuery

I have a situation in which I click the button, and it does some action like the following:
var pos = 1;
$('.right').click(function(){
$('.box').css({'left': pos++ });
});
$('.left').click(function(){
$('.box').css({'left': pos-- });
});
.box{
background-color: gray;
height:20px;
width: 20px;
left: 0;
position: relative;
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button class="left" button-held>Left</button>
<button class="right" button-held>Right</button>
<div class="box"></div>
What I need is that when the user clicks on the button and leave it pressed, that it do this action multiple times until the button is released.
Any ideas on how to do this? I have already search the internet for a while but it's quite difficult to find an answer as there are lots of questions about events, also I found an Angular solution if someone wants to check it out (Angular solution).
Thanks in advance.
Instead of listening for click, do this:
Listen for mousedown and mouseup.
On mousedown, perform the action and set a timer to perform it again in a moment via setTimeout. Remember the timer handle (the return value).
When the timer goes off and you do the action again, schedule it to happen again in a moment, again via setTimeout, again remembering the handle.
When you see mouseup, cancel the outstanding timer using the handle with clearTimeout.
Example:
var pos = 1;
var handle = 0;
function move(delta) {
$('.box').css({'left': pos += delta });
}
function moveRight() {
move(1);
clearTimeout(handle); // Just in case
handle = setTimeout(moveRight, 50);
}
function moveLeft() {
move(-1);
clearTimeout(handle); // Just in case
handle = setTimeout(moveLeft, 50);
}
$('.right').on("mousedown", moveRight);
$('.left').on("mousedown", moveLeft);
$('.left, .right').on("mouseup", function() {
clearTimeout(handle);
handle = 0;
});
.box{
background-color: gray;
height:20px;
width: 20px;
left: 0;
position: relative;
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button class="left" button-held>Left</button>
<button class="right" button-held>Right</button>
<div class="box"></div>
In a comment you've said:
I just noticed a bug within this, if I leave one of the buttons pressed, and then slide out of it while still keeping it pressed and then releasing it, it move the box indefinitely until you press again one of the buttons, do you maybe know why this is happening?
It's because we're only listening for mouseup on the button, so when you release it, we don't get that event. Silly mistake on my part. :-)
Two solutions:
Either listen for mouseup on document, or
Listen for mouseleave on the button as well as mouseup.
I think #1 is probably best, especially since when I just tried it on Chrome, it even gracefully handled the case where I pressed the mouse down over the button, then slid it right out of the browser window entirely (!) and released it. Chrome still gave us the mouseup on `document. :-)
Implementing #1 is just a matter of hooking mouseup on document instead of .left, .right:
var pos = 1;
var handle = 0;
function move(delta) {
$('.box').css({'left': pos += delta });
}
function moveRight() {
move(1);
clearTimeout(handle); // Just in case
handle = setTimeout(moveRight, 50);
}
function moveLeft() {
move(-1);
clearTimeout(handle); // Just in case
handle = setTimeout(moveLeft, 50);
}
$('.right').on("mousedown", moveRight);
$('.left').on("mousedown", moveLeft);
// ONLY CHANGE is on the next line
$(document).on("mouseup", function() {
clearTimeout(handle);
handle = 0;
});
.box{
background-color: gray;
height:20px;
width: 20px;
left: 0;
position: relative;
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button class="left" button-held>Left</button>
<button class="right" button-held>Right</button>
<div class="box"></div>
Implementing #2 is just a matter of adding mouseleave to the mouseout handler; but note that the button retains its "pushed" appearance even though we stop doing the movement as soon as the mouse leaves the button:
var pos = 1;
var handle = 0;
function move(delta) {
$('.box').css({'left': pos += delta });
}
function moveRight() {
move(1);
clearTimeout(handle); // Just in case
handle = setTimeout(moveRight, 50);
}
function moveLeft() {
move(-1);
clearTimeout(handle); // Just in case
handle = setTimeout(moveLeft, 50);
}
$('.right').on("mousedown", moveRight);
$('.left').on("mousedown", moveLeft);
// ONLY CHANGE is on the next line
$('.left, .right').on("mouseup mouseleave", function() {
clearTimeout(handle);
handle = 0;
});
.box{
background-color: gray;
height:20px;
width: 20px;
left: 0;
position: relative;
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button class="left" button-held>Left</button>
<button class="right" button-held>Right</button>
<div class="box"></div>
Something like this? Here you go
var pos = 1;
$('.right').mousedown(function(){
myVar = setInterval(function(){ $('.box').css({'left': pos++ }); }, 100);
});
$('.right').mouseup(function(){
clearInterval(myVar);
});
$('.left').mousedown(function(){
myVar = setInterval(function(){ $('.box').css({'left': pos-- }); }, 100);
});
$('.left').mouseup(function(){
clearInterval(myVar);
});

Bootstrap- Automatically adjust the font inside a div

I have a div in which I can write any text up to 20 characters. But the text is getting out of the div.
I am setting it by decreasing font-size property on character count but it is not applicable on all cases.
Is there any way to do it by applying any twitter bootstrap rule?
<div id="overlay_image_text"></div>
if(cs < 6)
{
if(this.engravingFontCaseSenstiveOptions(cText) == "Lower")
{
$('#overlay_image_text').css({'margin-top':'-170px'});
$('#overlay_image_text').css({'font-size':68+'px'});
}
else if(this.engravingFontCaseSenstiveOptions(cText) == "Upper"){
$('#overlay_image_text').css({'margin-top':'-154px'});
$('#overlay_image_text').css({'font-size':48+'px'});
}
else{
$('#overlay_image_text').css({'margin-top':'-170px'});
$('#overlay_image_text').css({'font-size':64+'px'});
}
}
else if(cs > 5 && cs <= 7)
{
if(this.engravingFontCaseSenstiveOptions(cText) == "Lower")
{
$('#overlay_image_text').css({'margin-top':'-152px'});
$('#overlay_image_text').css({'font-size':47+'px'});
}
else if(this.engravingFontCaseSenstiveOptions(cText) == "Upper")
{
$('#overlay_image_text').css({'margin-top':'-140px'});
$('#overlay_image_text').css({'font-size':35+'px'});
}
else
{
$('#overlay_image_text').css({'margin-top':'-152px'});
$('#overlay_image_text').css({'font-size':47+'px'});
}
}
CSS for parent element
element.style {
display: block;
font-family: Cherokee;
}
Would need to see the CSS code of the parent element containing it but try
#overlay_image_text {
width:100%;
font-size: auto;
}
Hope you get the idea. Also, apply padding/margin in % as needed.
Are you looking for this?
Basically, I take advantage of the scale() in CSS and make the text fit in its parents. Please comment if you need further explanation ;)
$(function(){
$("#text").on("input", function(){
var thisWidth = $(this).width();
var parentWidth = $(this).parent().width();
var scalingFactor = parentWidth/thisWidth;
if (thisWidth > parentWidth) {
$(this).css("transform", "scale("+scalingFactor+")");
} else {
$(this).css("transform", "scale(1)");
}
});
})
#box {
width:400px;
background:#D8557F;
border:10px solid #D8557F;
height:100px;
}
#text {
font-size:54px;
white-space: nowrap;
float:left;
transform-origin:left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="box">
<div id="text" contenteditable="true">
Edit me!
</div>
</div>

jQuery - prev/next navigation between non-siblings

I have a bunch of elements of the same type that have different parents, but I would like to be able to seamlessly navigate/cycle through all of them as if they were together.
<div>
<a href="#" class="open></a>
</div>
<div>
</div>
<div>
</div>
‹
›
I've managed to get this far: https://jsfiddle.net/pj0ecxge/
Currently it doesn't function as intended, as prev() and next() are only meant to target sibling elements, so the arrows don't work if the previous or next element is in another parent.
A single element will always be open by default, but it won't always be the same element as shown in the example. Also, only one element can be open at the same time.
If it makes a difference, I can add a single class to all children elements, but I can't change the HTML structure i.e put them all inside the same parent.
It would be nice if the navigation is infinite - i.e clicking next while the last element is open will show the first element and vice versa, but this is not required if it's too complex to do.
Thanks in advance and any help will be very appreciated!
You can check whether there are next/previous elements, if not then you can move a layer up/down like
$('.prev').click(function(e) {
e.preventDefault();
var current = $('.open');
var prev = current.prev();
if (!prev.length) {
prev = current.parent().prev('div').children('a:last-child')
}
if (prev.length) {
current.removeClass('open');
prev.addClass('open');
}
});
$('.next').click(function(e) {
e.preventDefault();
var current = $('.open');
var next = current.next();
if (!next.length) {
next = current.parent().next('div').children('a:first-child')
}
if (next.length) {
current.removeClass('open');
next.addClass('open');
}
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
text-align: center;
}
div {
font-size: 0;
}
div a {
width: 150px;
height: 150px;
border: 2px solid black;
}
a {
display: inline-block;
}
.open {
background: red;
}
.prev,
.next {
font-size: 100px;
text-decoration: none;
margin: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
</div>
<div>
</div>
<div>
</div>
‹
›
Find the next set when the current set has reached either end. And the if the set is the last one then go back to the first one (and vice-versa).
$('.prev').click(function(e) {
e.preventDefault();
var current = $('.open');
var prev = current.prev();
if (!prev.length) {
prev = current.parent().prev('div').children('a:last-of-type');
if (!prev.length) {
prev = $('div:last-of-type').children('a:last-of-type');
}
}
current.removeClass('open');
prev.addClass('open');
});
$('.next').click(function(e) {
e.preventDefault();
var current = $('.open');
var next = current.next();
if (!next.length) {
next = current.parent().next('div').children('a:first-of-type');
if (!next.length) {
next = $('div:first-of-type').children('a:first-of-type');
}
}
current.removeClass('open');
next.addClass('open');
});

jQuery, multiple content sliders in single page

I want to make a lot of slides in a one-page scrolling site. A neat way to do this was with a code from Stano. My problem is that this code was only meant to occur once per page. In order to make it fit my needs I made it into this fiddle. I realized that this would accumulate very fast into some rather messy coding if I had 20+ of these:
$(document).ready(function() {
var divs = $('.divs>div');
var now = 0; // currently shown div
divs.hide().first().show(); // hide all divs except first
$(".next").click(function() {
divs.eq(now).hide();
now = (now + 1 < divs.length) ? now + 1 : 0;
divs.eq(now).show(); // show next
});
$(".prev").click(function() {
divs.eq(now).hide();
now = (now > 0) ? now - 1 : divs.length - 1;
divs.eq(now).show(); // show previous
});
});
Is there any way to create a common ID/class for the divs and clickers (previous, next) or a container that ensures that the slider functions by itself without interrupting other sliders?
For example creating a variable with the ID of the container
var test = $('.container').attr('id') )
Implementing the ID in the divs
var divs = $(test).attr( 'id',$(test).attr('id') );
Implementing the ID in the next (and prev), so that when they are being clicked they will only affect the divs with the same ID
$(".next",test).click(function () {...
Maybe have a wrapper with a specific ID where the 3 divs (divs, prev and next) are includes and tell the script that they need to be in the same wrapper in order to affect each other.
<div ID="wrap1">
<div class="prev"></div>
<div class="next"></div>
<div class="divs"></div>
</div>
I do not know how the script will change. Maybe including .child() or .parent()?
I am very new at java scripting and hope that my question is understood properly. Please let me know if there is anything that needs to be clarified.
Check my code, each slider has now a function at document ready, not mixing thing around, and a jquery higher version was used.
$(document).ready(function () {
function FirstSlider(){
var divs = $('.div1>div');
var now = 0; // currently shown div
console.log(divs);
divs.hide().first().show(); // hide all divs except first
$(".nex1").click(function () {
divs.eq(now).hide();
now = (now + 1 < divs.length) ? now + 1 : 0;
divs.eq(now).show(); // show next
});
$(".pre1").click(function () {
divs.eq(now).hide();
now = (now > 0) ? now - 1 : divs.length - 1;
divs.eq(now).show(); // show previous
});
}
function SecondSlider(){
var divs = $('.div2>div');
var now = 0; // currently shown div
divs.hide().first().show(); // hide all divs except first
$(".nex2").click(function () {
divs.eq(now).hide();
now = (now + 1 < divs.length) ? now + 1 : 0;
divs.eq(now).show(); // show next
});
$(".pre2").click(function () {
divs.eq(now).hide();
now = (now > 0) ? now - 1 : divs.length - 1;
divs.eq(now).show(); // show previous
});
}
FirstSlider();
SecondSlider();
});
.body {
margin: 0 0;
}
.prenex {
position: fixed;
top:15vh;
display: block;
background-color: #aaa;
cursor: pointer;
width: auto;
height: auto;
font-size: 10vh;
padding: 2vh 4vh;
text-align: center;
opacity: .5;
-webkit-user-select: none;
/* Chrome/Safari */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* IE10+ */
}
.prev, .pre1, .pre2 {
left:5vh;
float:left;
}
.next, .nex1, .nex2 {
right: 5vh;
float:right;
}
.pre1, .nex1 {
top:20vh;
}
.pre2, .nex2 {
top:70vh;
}
.divs, .div1, .div2 {
width:70vw;
height:40vh;
margin: 0 auto;
display:block;
background-color:#aaa;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="prenex nex1">></div>
<div class="prenex pre1">
<</div>
<div class="div1">
<div>Hello World,</div>
<div>I</div>
<div>Am</div>
<div>The</div>
<div>Test</div>
</div>
<br>
<hr>
<br>
<div class="prenex nex2">></div>
<div class="prenex pre2">
<</div>
<div class="div2">
<div>Hello World,</div>
<div>why do I</div>
<div>follow</div>
<div>the steps of</div>
<div>my evil twin?</div>
</div>

Synchronizing span and textarea scrollbars - scrollbar slightly off and pasting issue

I have a table set up in the following way, with each cell containing a span and a textarea:
<table>
<tr><td class="title">Original File</td></tr>
<tr><td><span id='ogline' onscroll="og.scrollTop=scrollTop"></span><span><textarea onscroll="ogline.scrollTop=scrollTop" onkeyup="linenumber()" id='og' onfocusout="linenumber()"></textarea></span></td></tr>
</table>
Along with that I have the following CSS:
<style>
span {
width:93%;
height: 100%;
}
textarea {
width:92%;
height: 100%;
border-style:solid;
border-color:black;
border-width:2px;
font-size:13px;
}
table {
width:100%;
height:100%;
}
.title {
height:5%;
text-align:center;
background-color:#009;
color:white;
}
#ogline {
padding-top:4px;
overflow:auto;
font-size:12px;
line-height:14.99px;
width:6%;
}
</style>
What I am trying to do is have the scroll bar of the span and the scroll bar of the textarea synch up. I've somewhat accomplished this using the onscroll event listener with the following code:
onscroll="og.scrollTop=scrollTop"
onscroll="ogline.scrollTop = scrollTop
This has somewhat accomplished what I want it to, with the span being about a line off of where it should be. The greatest problem I am having though is when I paste a large amount of text into the textarea. This almost completely doesn't work, with both scrollbars being completely off until I hold one of the scrollbars down for a significant amount of time before the other scrollbar will try to play catch up with the other.
Any suggestions? Is there maybe a better approach to this issue that I should try? Any help would be appreciated.
This could work:
var scrolling=false;
function og_scroll(el)
{
if (scrolling && el!=scrolling) {
return;
}
scrolling = el;
var textareas = document.getElementsByTagName('textarea');
for (var i=0; i<textareas.length; i++) {
if (textareas[i].id.indexOf('og')==0) { // searching for id==og*
textareas[i].scrollTop=el.scrollTop;
}
}
scrolling = false;
}
function up(num)
{
var area = document.getElementById('og'+num);
if (area.scrollTop > 0) {
area.scrollTop -= 15;
}
}
function down(num)
{
var area = document.getElementById('og'+num);
if (area.scrollTop < area.scrollHeight) {
area.scrollTop += 15;
}
}
function fix_mouse_scroll() {
var textareas = document.getElementsByTagName('textarea');
for (var i=0; i<textareas.length; i++) {
if (textareas[i].id.indexOf('og')==0) {
if ("onmousewheel" in document) {
textareas[i].onmousewheel = fixscroll;
} else {
textareas[i].addEventListener('DOMMouseScroll', fixscroll, false);
}
}
}
}
function fixscroll(event){
var delta=event.detail? event.detail : event.wheelDelta; // positive or negative number
delta = delta>0 ? 15 : -15;
event.target.scrollTop += delta;
//console.log(delta, ' with ',event.target.scrollTop);
}
Html part:
<tr><td> <span onmousedown='up(1)'>[UP]</span> <span onmousedown='down(1)'>[DOWN]</span> <textarea id='og1' onscroll="og_scroll(this);"></textarea></td></tr>
<tr><td> <span onmousedown='up(2)'>[UP]</span> <span onmousedown='down(2)'>[DOWN]</span> <textarea id='og2' onscroll="og_scroll(this);"></textarea></td></tr>
<tr><td> <span onmousedown='up(3)'>[UP]</span> <span onmousedown='down(3)'>[DOWN]</span> <textarea id='og3' onscroll="og_scroll(this);"></textarea></td></tr>
The full html code is here.

Categories