I want my page to show 3 divs at a time, and when I click next I would like it to show the next 3 divs. Then when I click previous, I would like to display the previous 3.
$("#container .result").slice(0, 3).show();
$("#right").click(function () {
var items = $('#container .result:visible').hide().last();
var nextItems = items.nextAll().slice(0, 3);
if (nextItems.length === 0) {
nextItems = $("#container .result").slice(0, 3);
}
nextItems.show();
});
$("#left").click(function () {
var items = $('#container .result:visible').hide().last();
var nextItems = items.prevAll().slice(0, 3);
if (nextItems.length === 0) {
nextItems = $("#container .result").slice(0, 3);
}
nextItems.show();
});
The problem is that when I click previous, and it comes to last 3 divs and when I click again it shows 2 than 1. How can i fix that? I want it to stop when it comes to first 3.
You were very much on the right track, I was impressed by the ingenuity of your code.
Your main problem is solved with a very simple fix; in the #left click-handler, replace .last() with .first():
var items = $('#container .result:visible').hide().first();
And to loop around to the last 3 when you click previous on the first 3, change this line to the next:
nextItems = $("#container .result").slice(0, 3);
nextItems = $("#container .result").slice($("#container .result").length-3, $("#container .result").length);
But I thought the situation might occur, now or in the future, that the number of .results aren't a multitude of 3, let's say 7 or 11 for example.
I created a script that will handle that, and also loop around in both directions:
$("#container .result").first().show(); //initialize divs at pageload
$(".nav").click(function() {
var start=0, step=3;
var currentItems = $("#container .result:visible").hide();
var currentLast = (this.id==="prev" ? currentItems.first() : currentItems.last());
var nextItems = (this.id==="prev" ? currentLast.prevAll() : currentLast.nextAll());
if (nextItems.length === 0) { //if the last set of divs has been reached, loop around
var itemsLength = $("#container .result").length;
if (this.id==="prev") {start=itemsLength-step; step=itemsLength;} //determine wich way to loop around
nextItems = $("#container .result").slice(start,step); //loop around
} else if (nextItems.length < step) { //if the next divs aren't a full set, keep some divs from the current set visible
if (this.id==="prev") {step-=nextItems.length;} else {start=nextItems.length;} //determine which current items should remain visible
currentItems.slice(start,step).each(function(){nextItems.push(this);}); //add selected current items to nextItems-array
} else {nextItems=nextItems.slice(start,step);} //if the next divs are a full set, simply select the next set
nextItems.show(); //show the next set
}).click(); //initialize divs at pageload
In HTML, I gave the two buttons both a class "nav" (see code snippet below), so that I could combine their click-handlers into one.
I changed your first line to this: $("#container .result").first().show();. That line - in combination with the .click() chained to the click-handler - replaces your line: $("#container .result").slice(0, 3).show(); (at the top of your script).
This gives you much more flexibility to change the amount of divs you want to show on the page at once. At the start of the click-handler I declare var step=3;, which is the only place that number is hard-coded, so if you ever want to change the amount you only have to change that number (and maybe adjust some styling).
The rest of the explanation is in the comments in the code.
See the code snippet below for a demo:
$("#container .result").first().show(); //initialize divs at pageload
$(".nav").click(function() {
var start=0, step=3;
var currentItems = $("#container .result:visible").hide();
var currentLast = (this.id==="prev" ? currentItems.first() : currentItems.last());
var nextItems = (this.id==="prev" ? currentLast.prevAll() : currentLast.nextAll());
if (nextItems.length === 0) { //if the last set of divs has been reached, loop around
var itemsLength = $("#container .result").length;
if (this.id==="prev") {start=itemsLength-step; step=itemsLength;} //determine wich way to loop around
nextItems = $("#container .result").slice(start,step); //loop around
} else if (nextItems.length < step) { //if the next divs aren't a full set, keep some divs from the current set visible
if (this.id==="prev") {step-=nextItems.length;} else {start=nextItems.length;} //determine which current items should remain visible
currentItems.slice(start,step).each(function(){nextItems.push(this);}); //add selected current items to nextItems-array
} else {nextItems=nextItems.slice(start,step);} //if the next divs are a full set, simply select the next set
nextItems.show(); //show the next set
}).click(); //initialize divs at pageload
html,body {width:98%; height:90%;}
#container {width:100%; height:90%; background:lightgrey;}
#container .result {display:none; float:left; width:30%; height:100%; margin:0 1.66%; background:lightgreen;}
#container .result > div {display:table; width:100%; height:100%;}
#container .result > div > div {display:table-cell; width:100%; height:100%; text-align:center; vertical-align:middle; font:bolder 2em sans-serif;}
.nav {margin-top:2%; cursor:pointer;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="result"><div><div>1</div></div></div>
<div class="result"><div><div>2</div></div></div>
<div class="result"><div><div>3</div></div></div>
<div class="result"><div><div>4</div></div></div>
<div class="result"><div><div>5</div></div></div>
<div class="result"><div><div>6</div></div></div>
<div class="result"><div><div>7</div></div></div>
</div>
<button type="button" class="nav" id="prev">PREVIOUS</button>
<button type="button" class="nav" id="next">NEXT</button>
codepen: https://codepen.io/anon/pen/YQoJzd?editors=1010
jsfiddle: https://jsfiddle.net/k8ysj6gq/1/
You can ignore the CSS and HTML (except for the class="nav" on the buttons), that's all just so we can see it. All the relevant code is in the JS.
Basically you can do something like below.
On Next or Previous click set margin-left of container to position or loop through all div.
$(document).ready(function() {
$('.next-button').on('click', function() {
if (parseInt($('.carousel-item').css("margin-left").slice(0, -2)) < -2000) {
$('.carousel-item').animate({
"margin-left": "0px"
}, 200)
} else {
$('.carousel-item').animate({
"margin-left": "-=600px"
}, 200);
}
});
$('.prev-button').on('click', function() {
if (parseInt($('.carousel-item').css("margin-left").slice(0, -2)) > 0) {
$('.carousel-item').animate({
"margin-left": "-2000px"
}, 200)
} else {
$('.carousel-item').animate({
"margin-left": "+=600px"
}, 200);
}
});
});
.carousel-container {
height: 500px;
display: flex;
margin: 40px 20px;
position: relative;
overflow: hidden;
width: 720px;
padding: 0;
border: 1px solid red;
align-items: center;
}
.carousel-item {
height: 100%;
margin: 5px;
margin-left: 60px;
padding: 0;
-moz-box-orient: horizontal;
-ms-box-orient: horizontal;
-webkit-box-orient: horizontal;
-o-box-orient: horizontal;
box-orient: horizontal;
display: -moz-box;
display: -ms-box;
display: -webkit-box;
display: -o-box;
display: box;
list-style-type: none;
}
.item {
border: solid 1px #333;
margin-right: 10px;
width: 200px;
display: flex;
align-items: center;
}
.item>a {
width: 100%;
display: flex;
justify-content: center;
align-items: flex-end;
}
.prev-button,
.next-button {
border: 1px solid green;
background-color: gray;
}
.navigation {
width: 60px;
margin: 0;
position: absolute;
top: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
}
.next-button:hover,
.prev-button:hover {
background-color: red;
}
.navigation:active {
color: white;
}
.next-button {
right: 0;
}
.prev-button {
left: 0;
}
/* .carousel-item li:nth-child(1) {
background-image: url('http://urbanphenomena.net/imgs/cover/bq2.jpg');
background-size: cover;
} */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="carousel-container">
<a class="prev-button navigation" href="#">
<</a>
<div class="carousel-item">
<li class="item"> 1 </li>
<li class="item"> 2 </li>
<li class="item"> 3 </li>
<li class="item"> 4 </li>
<li class="item"> 5 </li>
<li class="item"> 6 </li>
<li class="item"> 7 </li>
<li class="item"> 8 </li>
<li class="item"> 9 </li>
<li class="item">
</li>
</div>
<a class="next-button navigation" href="#">></a>
</div>
Run co
Ok so your first mistake was that when trying to code back 3 you were getting the previous 3 items from the first of the 3 not the last. So i changed .last() to .first(). Then to loop back when previous = 0 all you did was slice from the current 3, instead of slicing at the end of the entire array of elements.
Here's a link to a codepen that has the working code(you'll obviously have to change the variables to fit your project): https://codepen.io/anon/pen/qjzxee?editors=1010
changed var items = $('#container .result:visible').hide().last(); to var items = $('#container .result:visible').hide().first();
and
if (nextItems.length === 0) {
nextItems = $("#container .result").slice(0, 3);
}
to
if (nextItems.length === 0) {
var allItems = $("#container .result");
nextItems = $("li").slice(allItems.length - 3,allItems.length);
}
this also only works if the number elements is a multiple of the number you are skipping each time, but i can fix that if you'd like
Related
The goal is to do this:
The problem is that at the end of the row 2 I need to add two "harcoded" things:
The "# more" button (only when is needed)
The "face-plus" button (always)
This is the "ellipsis" effect I am asking about.
I have tried the following:
// HTML
<div class="container">
<div class="children">
Hola1
</div>
<div class="children">
Hola2
</div>
<div class="children">
Hola3
</div>
<div class="children">
Hola4
</div>
<div class="children">
Hola5
</div>
<div class="children">
Hola6
</div>
</div>
// css
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
width: 150px;
border: 1px solid black;
padding: 5px;
height: 80px; // this makes the trick of having 2 rows
overflow: hidden; // this makes the trick of having 2 rows
}
.children {
border: 1px solid black;
margin: 5px;
padding: 5px;
}
and I get this result:
but I am not being able to add the "fixed" elements at the end of the line 2 because I have more hidden elements on the list.
Some key points:
width of elements is dynamic
I want a maximum of 2 rows.
at the end of the row 2 I need to have the "# more" button (only when needed) and the face icon.
Thanks in advance
To avoid having to do fiddly bits of arithmetic you could clear the container, and add the elements one at a time, seeing if the one you have just added (plus its associated 'more' element and icon) go outside the bottom of the container.
If it has gone outside the bottom then go back one, so the more statement is correct.
I do not know whether you intended to put the more statement and icon into the DOM (or whether perhaps through a pseudo element having left space for them). This snippet has them in the DOM so you can click on the more element and do whatever you want to do then.
And you will have to run this code on each load and resize.
const container = document.querySelector('.container');
container.style.visibility = 'hidden'; //just in case there's a little flash as we add the elements
const cbottom = container.getBoundingClientRect().bottom;
const children = document.querySelectorAll('.children');
const num = children.length;
container.innerHTML = '<div class="moreEl"><span class="remainder">xxx</span> MORE</div><img src="youricon.jpg" style="width: 20px; aspect-ratio: 1 / 1;">';
const moreEl = container.querySelector('.moreEl');
const remainder = moreEl.querySelector('span');
// now add each child one at a time, with either the 'nn more' plus icon or just the icon in front of it until the child is outside the container when step back one
let i = 0;
for (i; i < children.length; i++) {
remainder.innerHTML = num - i - 1;
container.insertBefore(children[i], moreEl);
if ((children[i].getBoundingClientRect().top > cbottom) || (moreEl.getBoundingClientRect().top >= cbottom)) {
// can't get this element in, let alone with any associated more element, so go back one
children[i].parentElement.removeChild(children[i]);
remainder.innerHTML = num - i;
break;
}
}
if (i >= (num - 1)) {
moreEl.parentElement.removeChild(moreEl);
} else {
for (let j = i; j < num; j++) {
container.append(children[j]);
}
}
container.style.visibility = 'visible';
* {
box-sizing: border-box;
}
.container {
visibility: hidden;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
width: 150px;
border: 1px solid black;
padding: 5px;
height: 80px;
/* this makes the trick of having 2 rows */
overflow: hidden;
/* this makes the trick of having 2 rows */
}
.children {
border: 1px solid black;
margin: 5px;
padding: 5px;
}
.moreEl {
padding: 10px;
}
<div class="container">
<div class="children">
Hola1
</div>
<div class="children">
Hola2
</div>
<div class="children">
Hola3
</div>
<div class="children">
Hola4
</div>
<div class="children">
Hola5
</div>
<div class="children">
Hola6
</div>
<div class="children">
Hola7
</div>
<div class="children">
Hola8
</div>
<div class="children">
Hola9
</div>
<div class="children">
Hola10
</div>
</div>
Note: this snippet has more 'Hola' elements so it's easier to test out different container widths.
So I am trying to sort an array of numbers when a user clicks on the button sort or reverse and my buttons names are #sort-cards and #reverse-cards. I feel like this is something very simple I am missing but I just cannot figure out what exactly.
(function () {
var cardElements, cardValues; // Do not declare more variables here.
// WRITE CODE HERE TO MAKE THE #cards ELEMENT WORK
//Get an array of all div elements inside the #cards element.
cardElements = Array.from(document.querySelectorAll('#cards div'));
//Initialize the cardValues variable as an empty array.
cardValues = [];
//Use a forEach loop to iterate through each of the div elements (the cards) one by one.
cardElements.forEach(function (cardElements) {
//Generate a card value, a random integer between 1 and 99.
cardElements.textContent = Math.floor(Math.random() * 99) + 1;
//Push it onto the end of the cardValues array and put it in the current div element.
cardValues.push(cardElements);
//Create an event handler that moves the card to the right end whenever it is clicked, leaving the other cards in the same order, and outputs all the new card values to the card divs.
//cardElements.addEventListener('click', function() {
//}
//Do things when the sort button is clicked
document.querySelector('#sort-cards').addEventListener('click', function () {
cardElements.sort(function (a, b){
return a - b;
});
});
//Do things when the reverse button is clicked.
document.querySelector('#reverse-cards').addEventListener('click', function () {
cardElements.reverse();
});
});
}());
You are shadowing cardElements variable in the forEach callback. Also, add the event listeners once, not for every card.
document.querySelectorAll('#cards div') returns a NodeList. If you want to change the DOM, you need to manipulate it, not the JS Array you made out of it.
You can iterate over NodeLists with for ... of.
In order to be DRY, I've added the renderCards function that mutates the DOM.
(function () {
var cardElements, cardValues;
cardElements = document.querySelectorAll('#cards div');
cardValues = [];
function renderCards(newCards) {
for (let i = 0, max = cardElements.length; i < max; i++ ) {
cardElements[i].textContent = newCards[i]
}
}
for (let cardElement of cardElements){
cardElement.textContent = Math.floor(Math.random() * 99) + 1;
cardValues.push(cardElement.textContent);
};
document.querySelector('#sort-cards').addEventListener('click', function () {
cardValues.sort(function (a, b){
return a - b;
});
renderCards(cardValues);
});
document.querySelector('#reverse-cards').addEventListener('click', function () {
cardValues.reverse();
renderCards(cardValues);
});
}());
#cards {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-items: center;
width: 100%;
}
.card {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
margin: 1em;
padding: 1em;
border: 1px solid #ccc;
width: 2em;
height: 2em;
}
#btns {
margin: 1.6em;
}
.btn {
cursor: pointer;
background-color: lightgreen;
padding: 1em;
margin: 0 1.6em;
}
<div id="btns">
<a class="btn" role="btn" id="sort-cards">Sort cards</a>
<a class="btn" role="btn" id="reverse-cards">Reverse cards</a>
</div>
<div id="cards">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
<div class="card">5</div>
<div class="card">6</div>
<div class="card">7</div>
<div class="card">8</div>
<div class="card">9</div>
<div class="card">10</div>
<div class="card">11</div>
<div class="card">12</div>
</div>
I have a contenteditable div and I want the site to count each row of text the user has in the div similar to many coding IDEs. (Example image below to show what I mean:)
How would I go about doing this?
You can accomplish this with two container elements and a little bit of scripting:
$(document).ready(function(){
$('#edit').css('min-height', $('#edit').height());
$('#edit').html('');
var currentHeight = $('#edit').height();
var lineHeight = currentHeight;
$('#edit').keyup(function(){
if($(this).height()!=currentHeight){
currentHeight = $(this).height();
var lines = currentHeight/lineHeight;
$('#nums').html('')
for (i = 1; i < lines+1; i++) {
$('#nums').append('<span>'+i+'</span>')
}
}
});
});
#container{
border: 2px solid gray;
display: flex;
width: 200px;
}
#nums{
width: 25px;
background-color: lightgrey;
}
#nums span{
width: 100%;
display: block;
text-align: center;
}
#edit{
display: inline-block;
width: 100%;
}
#editwrapper{
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="nums">
<span>1</span>
</div>
<div id="editwrapper">
<div id="edit" contenteditable="true">
filler
</div>
</div>
</div>
That's not so simple, actually. If a user typed in your div and the text wrapped, JavaScript doesn't know that it wrapped; there's no row to count!
This solution is super specific, and I'll leave showing the line numbers to you:
<div contenteditable="true" id="myDiv" style="width:300px;font-family:monospace" onchange="myHandler()"></div>
<script>
const limit = 40 // number of monospace chars to fill a row
let count = 0
function myHandler (e) {
let lines = Math.ceil(e.target.value.length / limit)
if (lines !== count) {
showlines(lines) // your function to display the line #s
count = lines
}
}
</script>
Takeaway: your div should be a fixed width and you should count how many monospace chars fit within that width. Then display those lines.
I'm using owl carousel on a menu.
when I scroll to the div the owl carousel auto slide to the right slides.
now when I arrived in the specific div I add class to the slide (active) but for some reason, I can't remove the active class from the other slides (his siblings).
I think it will be best to check the jsfiddle to understand the problem...
<div class="body">
<div class="menu">
<ul class="owl-carousel owl-theme">
Review
a
b
c
d
e
f
</ul>
</div>
JS file
$('.owl-carousel').owlCarousel({
nav: false,
dots: false,
singleItem: true,
})
var owl = $('.owl-carousel');
owl.owlCarousel();
$( window ).scroll(function() {
let scrollbarLocation = $(this).scrollTop();
let scrollLinks = $('.item');
scrollLinks.each(function(){
let sectionOffset = $(this.hash).offset().top;
if (sectionOffset <= scrollbarLocation){
$(this).siblings().removeClass('active-link');
$(this).addClass('active-link');
let goToSlide = $(this).attr('data-num')
owl.trigger('to.owl.carousel', goToSlide);
}
})
if( scrollbarLocation === 0){
scrollLinks.removeClass('active-link');
owl.trigger('to.owl.carousel', 0);
}
});
check https://jsfiddle.net/jt31h4pr/132/
The problem is that you remove/add active-link class on the same element ( this ). You need to removeClass only on the the element that already has class active-link.
The class active is controlled by the plugin and all the elements that are visible have the active class
See below
$('.owl-carousel').owlCarousel({
nav: false,
dots: false,
singleItem: true,
})
var owl = $('.owl-carousel');
owl.owlCarousel();
$( window ).scroll(function() {
let scrollbarLocation = $(this).scrollTop();
let scrollLinks = $('.item');
scrollLinks.each(function(){
let sectionOffset = $(this.hash).offset().top;
if (sectionOffset <= scrollbarLocation){
$('.active-link').removeClass('active-link'); // added
$(this).addClass('active-link');
let goToSlide = $(this).attr('data-num')
owl.trigger('to.owl.carousel', goToSlide);
}
})
if( scrollbarLocation === 0){
scrollLinks.removeClass('active-link');
owl.trigger('to.owl.carousel', 0);
}
});
.body {
height: 5000px;
}
ul {
padding: 0;
margin: 0;
list-style-type: none;
}
.item {
width: 200px;
height: 70px;
background: red;
margin: 0 15px;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-bottom: 4px solid transparent;
}
.active-link {
border-bottom: 4px solid #000;
}
.menu {
position: fixed;
top: 0;
}
section {
width: 100%;
height: 600px;
background: #f8f9fb;
}
#a {
background: lightblue;
margin-top: 200px;
}
#b {
background: lightgreen;
}
#c {
background: tomato;
}
#d {
background: lightpink;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.css">
<div class="body">
<div class="menu">
<ul class="owl-carousel owl-theme">
Review
a
b
c
d
e
f
</ul>
</div>
<section id="a"></section>
<section id="b"></section>
<section id="c"></section>
<section id="d"></section>
</div>
Look into this fiddle
https://jsfiddle.net/09sLpuwd/1/
What are you doing wrong is trying to remove active class from this and then add active class to the same this, which actualy do nothing.
Insted what I propose is to remove active class from all '.item' emelements and than add it to active one.
As alternative aproach you can store previous item and remove class from it, but I think first way is better.
Hi the problem is with below line
$(this).siblings().removeClass('active-link');
replace it with
$("div.active a").removeClass('active-link');
This was removing and adding class on same time on all so what i did is once i am removing the class from all i am adding it on present elemnt
I have a group of elements which fade in and out, (one after another), within a containing div (.info). Some of the elements stay within the container when they appear, while others overflow the container, which is not preferred.
When such a circumstance occurs, I would like for some kind of horizontal/auto-scroll effect to be applied, so it can reveal the beginning to the end of the overflowing text element, while still remaining on a single line. Is there any way to accomplish this with JQuery?
Here is a snippet of the progress I have made so far:
(function() {
var tab = $(".info .tab");
var tabIndex = -1;
function showNextTab() {
++tabIndex;
tab
.eq(tabIndex % tab.length)
.fadeIn(2000)
.delay(2000)
.fadeOut(2000, showNextTab);
}
showNextTab();
})();
.info {
background: skyblue;
display: inline-block;
line-height: 1;
width: 500px;
padding: 20px;
box-sizing: border-box;
}
.info .tab {
display: none;
}
h2.tab {
margin: 0;
padding: 0;
border: 0;
white-space: nowrap;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="info">
<h2 class="tab">This is the first line.</h2>
<h2 class="tab">This is the second line.</h2>
<h2 class="tab">This is the third line (which is longer than the first and second line.)</h2>
<h2 class="tab">This is the fourth line (which is longer than the first, second, and third line.)</h2>
</div>
UPDATE: Scroll Effect Added/Still Troubleshooting
Here is an updated snippet, with recent recommendations applied:
var myVar = "";
(function() {
var tab = $(".info .tab");
var tabIndex = -1;
function showNextTab() {
++tabIndex;
myVar = setInterval(myTimer, 1000);
tab
.eq(tabIndex % tab.length)
.fadeIn(2000)
.delay(2000)
.fadeOut(2000, showNextTab);
}
showNextTab();
})();
function myTimer() {
var leftPos = $(".info").scrollLeft();
$(".info").animate({
scrollLeft: leftPos + 200
}, 800);
myStopFunction();
}
function myStopFunction() {
clearInterval(myVar);
}
.info-wrap {
background: skyblue;
display: inline-block;
line-height: 1;
width: 500px;
padding: 20px;
}
.info {
display: inline-block;
line-height: 1;
width: 500px;
overflow: hidden;
}
.info .tab {
display: none;
}
h2.tab {
margin: 0;
padding: 0;
border: 0;
line-height: 1;
white-space: nowrap;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<duv class="info-wrap">
<div class="info">
<h2 class="tab">This is the first line.</h2>
<h2 class="tab">This is the second line.</h2>
<h2 class="tab">This is the third line (which is longer than the first and second line.)</h2>
<h2 class="tab">This is the fourth line (which is longer than the first, second, and third line.)</h2>
</div>
</div>
Question 1: Why is the fourth <h2 class="tab"> element not scrolling from the beginning? It seems to be starting from a halfway point, to the right.
Question 2: How can the speed of the slide-left animation be modified? I am trying to understand what the myVar = setInterval(myTimer, 1000); is targeting, and also scrollLeft: leftPos + 200}, 800);.
EXPLANATION:
Question1 : Because the width of scroll maximum is relative based on how many characters are created to make the width of scroll size. Right when the function is initialed, the variable $('.info').scrollLeft() seems save the previous point. Therefore, I re-initial that code by adding this code:
$(".info").animate({scrollLeft: 0}, 0); //$(.info) point = 0
Question2 : The left side animation can be speed up by increasing the value of leftPos. And this myVar = setInterval(myTimer, 1000); is to determine the start point. It means the function will begin at 1 sec.
Anyway here is the example below
var myVar = "";
(function() {
var tab = $(".info .tab");
var tabIndex = -1;
function showNextTab() {
++tabIndex;
myVar = setInterval(myTimer, 1000);
tab
.eq(tabIndex % tab.length)
.fadeIn(2000)
.delay(1000)
.fadeOut(2000, showNextTab);
$(".info").animate({scrollLeft: 0}, 0);
}
showNextTab();
})();
function myTimer() {
var leftPos = $('.info').scrollLeft();
$(".info").animate({scrollLeft: leftPos + 1500}, 800);
myStopFunction();
}
function myStopFunction() {
clearInterval(myVar);
}
.info {
background: skyblue;
display: inline-block;
line-height: 1;
width: 500px;
padding: 20px;
box-sizing: border-box;
overflow:scroll;
}
.info .tab {
display: none;
}
h2.tab {
margin: 0;
padding: 0;
border: 0;
white-space: nowrap;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="info">
<h2 class="tab">This is the first line. testtesttesttesttesttesttttttttttt</h2>
<h2 class="tab">This is the second line.</h2>
<h2 class="tab">This is the third line (which is longer than the first and second line.)</h2>
<h2 class="tab">This is the fourth line (which is longer than the first, second, and third line.)</h2>
</div>