I am trying to animate 4 icons to simulate wifi signals with Javascript, hower after the last signal is reached
the animation does not restart again.
Here is what i have tried.
I would appreciate any help and idea how to achieve this either with
CSS or Javascript.
function makeSignal(){
let wifi_icon = document.getElementById("wifi-signal");
wifi_icon.classList.add('ri-signal-wifi-line');
setTimeout(function() {
wifi_icon.classList.remove('ri-signal-wifi-line');
wifi_icon.classList.add('ri-signal-wifi-1-line');
}, 500);
setTimeout(function() {
wifi_icon.classList.remove('ri-signal-wifi-1-line');
wifi_icon.classList.add('ri-signal-wifi-2-line');
}, 1000);
setTimeout(function(){
wifi_icon.classList.remove('ri-signal-wifi-2-line');
wifi_icon.classList.add('ri-signal-wifi-3-line');
}, 1500);
}
makeSignal();
setInterval(makeSignal, 2000);
#signal {
display: block;
width: 100px;
height: 100px;
margin: 5px auto;
}
<link href="https://cdn.jsdelivr.net/npm/remixicon#2.5.0/fonts/remixicon.css" rel="stylesheet">
<div id="signal">
<i id="wifi-signal" class="ri-5x"></i>
</div>
Well, I have no idea if this works, but it seems that in the last setTimeout, you use wifi_icon.classList.add('ri-signal-wifi-3-line') and then, at the start of the function (next loop), you never remove that class. So add something like:
let wifi_icon = document.getElementById("wifi-signal");
wifi_icon.classList.remove('ri-signal-wifi-3-line');
wifi_icon.classList.add('ri-signal-wifi-line');
Related
I'm trying to accomplish a "reveal" effect where I show items from a grid when hovering them.
Everything's OK here but once revealed I want to make them disappear again after X seconds – so it's not that when you move the mouse from the item they disappear inmediately.
That's what I tried so far but the items are not going back to their "unrevealed" state after I leave the mouse from the item.
var timeout;
$(".home-box").hover(function () {
clearTimeout(timeout);
$(this).css("opacity", 1);
}, function () {
timeout = setTimeout(function(){
$(this).css("opacity", 0);
},500);
});
Does anyone have any idea about how to solve it?
Thanks in advance.
You should use mouseenter and mouseleave events and add separate functionalities in each.
The reference to this might be lost in the callback function passed to setTimeout.
$(".home-box").mouseenter(function() {
clearTimeout(timeout);
$(this).css("opacity", 1);
});
$(".home-box").mouseleave(function() {
var $element = $(this)
timeout = setTimeout(function(){
$element.css("opacity", 0);
},500);
});
Was it necessary? I used the event mouseover instead of the hover, as the hover will always fire when the mouse moves, even if you try to move the cursor away from the object.
$(".home-box").mouseover(function () {
$('img').css("opacity", 1);
setTimeout(function(){
$('img').css("opacity", 0);
}, 2000);
});
.home-box {
display: flex;
justify-content: center;
align-items: center;
width: 300px;
height: 300px;
border: 1px solid green;
position: relative;
}
img {
opacity: 0;
position: absolute;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="home-box">
hover me pls and wait...
<img src="https://im0-tub-ru.yandex.net/i?id=1a59e5c138260403e2230f0d2b264513&n=13">
</div>
The issue is that this has a different meaning within the setTimeout - you can store the box (this) and reuse it.
var timeout;
$(".home-box").hover(function() {
clearTimeout(timeout);
$(this).css("opacity", 1);
}, function() {
var box = this;
timeout = setTimeout(function() {
$(box).css("opacity", 0);
}, 500);
});
I have three images in a banner all set with position: absolute; and layered on top of one another. What I was hoping to do was use the setTimeout() and fadeOut() and fadeIn() methods to alternate between the three different images being displayed. Something is happening, but not really what I wanted. Instead of a smooth transition between each image, there is simply a choppy toggle back and forth between the last image and the second, the first never appearing at all. Here is the code I am using:
setInterval(function()
{
setTimeout($("#banner_city").fadeOut(), 5000);
setTimeout($("#banner_dispatch").fadeOut(), 5000);
setTimeout($("#banner_vehicles").fadeOut(), 5000);
setTimeout($("#banner_city").fadeIn(), 5000);
setTimeout($("#banner_dispatch").fadeIn(), 5000);
setTimeout($("#banner_vehicles").fadeIn(), 5000);
}, 32401);
I'm not sure if it's relevant but just in case here is the html and the css as well. HTML:
<div id="banner">
<img src="images/banner/city.jpg" id="banner_city" />
<img src="images/banner/dispatch.jpg" id="banner_dispatch" />
<img src="images/banner/vehicles.jpg" id="banner_vehicles" />
</div>
Css:
#banner {
margin-top: 12px;
position: relative;
width: 833px;
height: 237px;
}
#banner_city {
position: absolute;
right: 0;
top: 0;
width: 833px;
height: 237px;
}
#banner_dispatch {
position: absolute;
right: 0;
top: 0;
width: 833px;
height: 237px;
}
#banner_vehicles {
position: absolute;
right: 0;
top: 0;
width: 833px;
height: 237px;
}
Would anyone be able to shed some light on why this is behaving in such a buggy way? Thanks very much in advance.
Your setInterval is basically telling everything to fade-out and fade-in at the same time, which isn't what you want.
There's two approaches here: have 3 separate intervals for fading each "step", or have 1 interval with some internal counter for keeping track of what to show.
Here's the first approach:
function fadeOne() {
$("#banner_city").fadeOut();
$("#banner_dispatch").fadeIn();
};
function fadeTwo() {
$("#banner_dispatch").fadeOut();
$("#banner_vehicles").fadeIn();
}
function fadeThree() {
$("#banner_vehicles").fadeOut();
$("#banner_city").fadeIn();
}
fadeOne();
setInterval(fadeOne, 15000);
setTimeout(() => {
fadeTwo();
setInterval(fadeTwo, 15000);
}, 5000);
setTimeout(() => {
fadeThree();
setInterval(fadeThree, 15000);
}, 10000);
This is effectively three functions, each being called 15 seconds apart, with a 5/10 second delay on the second and third functions.
The second approach, which combines them together:
let count = 0;
function fade() {
switch (count++ % 3) {
case 0:
fadeOne();
return;
case 1:
fadeTwo();
return;
case 2:
fadeThree();
return;
}
}
fade();
setInterval(fade, 5000);
Your code starts all the timeouts at the same time, so they all complete at the same time. You'd have to nest them to make them to execute after each other, like this:
setTimeout(function() {
// Do something
// ...
setTimeout(function() {
// Do something else
// ...
setTimeout(...)
}, 1000)
}, 1000)
This is pretty messy, so here's another approach that should do what you need:
// Get all the image elements
var images = $(".banner-image");
// Hide all the images
images.hide();
// Start the cycle
cycle();
setInterval(cycle, 1000);
var index = 0;
function cycle() {
// Fade out all images
images.fadeOut();
// Fade in the next image
images.eq(index).fadeIn();
// Increment the index
index++;
// Reset index after cycling through all images
if ((index % images.length) === 0) index = 0;
}
This code will adapt to however many image elements you include in your HTML. Here it is running on a live demo.
PS: You can use CSS Classes to apply the same styles to multiple HTML elements.
I'm trying to make a header that appears at a certain place of the page.
So what I'm doing is checking the scroll to top of the page and the top offset of the element after which the header should appear. If the scrollTop is greater than offset the header is shown, otherwise it disappears.
But! When I scroll to the place, the header position is constantly switching between top: -13% and top: -12.999998%. After some time it finally shows the header but it never disappears.
What am I doing wrong?!
JSFiddle: https://jsfiddle.net/5k5s016f/
Well, i think the problem is that the .animate() functions are running constantly, causing the animations to "restart" before its ends.
It is not the most beautiful solution, but just adding a flag that controls the execution of the functions and a timeout to run the handler less frequently solves the problem.
https://jsfiddle.net/5k5s016f/2/
var visible = false;
$(window).scroll(function() {
setTimeout(function(){
var height = $(window).scrollTop();
var $page2 = $("#page2");
var offset = $page2.offset().top;
if (height > offset) {
if (visible) {
return;
}
visible = true;
$(".floating-header").show().animate({
top: 0
});
} else {
if (!visible) {
return;
}
visible = false;
$(".floating-header").animate({
top: "-13%"
});
}
}, 200)
});
The issue you are seeing is because each time a scroll event gets called animation queues up. If you wait long enough, you can see that the animation to set top to 0 actually works.
You can use the stop() function to stop all animation before attempting to run another one.
Something like this
if (height > offset) {
$(".floating-header").stop().show().animate({
top: "0"
}, 700);
} else {
$(".floating-header").stop().animate({
top: "-13%"
}, 700);
}
A couple of improvements I can suggest are
Debounce the scroll event handler
Check the current state of the header before queuing animation. i.e. do not try to hide it if it is already hidden and vice versa
Your logic is all messed up. Basically, you want to make sure that you are only animating when you absolutely need to - no more, no less. And since scroll events happen hundreds of times... constantly rapid firing as the user scrolls... you want to make sure you are doing the least amount of work possible during each scroll event. This especially means that you don't want to be querying the DOM on every scroll event if you don't have to (ps. $('selector') is a dom query). Take a look at this fiddle:
https://jsfiddle.net/5k5s016f/6/
Looks like I'm last to the party due to interruptions, but since I wrote it up I'll post the answer FWIW.
jsFiddle Demo
You need to debounce your code. Here is a simple system, but studing Ben Alman's explanation/examples is also recommended.
var $m1 = $('#m1'), $m2 = $('#m2'); //TESTING ONLY
var $win = $(window), $page2 = $("#page2"), $hdr=$(".floating-header");
var $offset = $page2.offset().top;
var hvis = false, curpos;
$win.scroll(function() {
curpos = $win.scrollTop();
$m1.html(curpos); //TESTING ONLY
$m2.html($offset);//TESTING ONLY
if ( curpos > $offset ) {
if ( !hvis ){
hvis = true;
//$m1.html(curpos);
$hdr.finish().animate({
top: "0"
}, 700);
}
} else {
if ( hvis ){
$hdr.finish().animate({
top: "-60px"
}, 700);
hvis = false;
}
}
});
html,
body {
height: 100vh;
width: 100vw;
}
#page1,
#page2,
#page3 {
height: 100%;
width: 100%;
background-color: #fff;
}
.floating-header {
position: fixed;
top: -60px;
background-color: #000;
width: 100%;
height: 60px;
}
.msg{position:fixed;bottom:10px;height:30px;width:80px;text-align:center;}
.msg{padding-top:10px;}
#m1 {left:3px; border:1px solid orange;background:wheat;}
#m2 {right:3px;border:1px solid green; background:palegreen;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<header class="floating-header">Header</header>
<div id="page1">
<p>Page1</p>
</div>
<div id="page2">
<p>Page2</p>
</div>
<div id="page3">
<p>Page3</p>
</div>
<div id="m1" class="msg"></div>
<div id="m2" class="msg"></div>
I've inherited a bug to look at consisting of two images that "flip" and use set interval to time when this happens.
From what I believe the initial change should happen after 4 seconds, then for each image change every 12 seconds (obviously this isn't important at the minute).
At the moment the first image changes at 4 seconds and the second one at around 8.
I'm also open to any improvements that can be made to this code as well.
//SPINNING LOGO
if ($("#flipLogo").length) {
function spinLogo() {
$('#flipLogo').addClass("active");
$('#flipLogo2').addClass("active");
// console.log("yup yup");
setTimeout(function () {
$('#flipLogo').removeClass("active");
$('#flipLogo2').removeClass("active");
}, 4000);
clearInterval();
}
setInterval(function () {
spinLogo();
clearInterval();
}, 12000);
}
I believe you are looking for $.toggleClass to switch between the active states.
Additionally, as Hacketo said you are calling clearInterval wrong - it should be called with the return value of setInterval if you want to stop the interval (I don't think you want to do this?)
Try this:
//SPINNING LOGO
function spinLogo() {
// Flip the active classes on or off
$('#flipLogo').toggleClass("active");
$('#flipLogo2').toggleClass("active");
}
if ($("#flipLogo").length) {
// after 4 seconds
setTimeout(function() {
// flip the logo
spinLogo();
// Set a timer to flip it again every 12 seconds
setInterval(spinLogo, 12000);
}, 4000);
}
Here it is in action:
//SPINNING LOGO
function spinLogo() {
// Flip the active classes on or off
$('#flipLogo').toggleClass("active");
$('#flipLogo2').toggleClass("active");
}
if ($("#flipLogo").length) {
// after 4 seconds
setTimeout(function() {
// flip the logo
spinLogo();
// Set a timer to flip it again every 12 seconds
setInterval(spinLogo, 12000);
}, 4000);
}
.flippable {
width: 100px;
height: 100px;
border: 1px solid black;
text-align: center;
display: none;
color: white;
}
.flippable.active {
display: block;
}
#flipLogo {
background: blue;
}
#flipLogo2 {
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="flipLogo" class="flippable active">Logo 1</div>
<div id="flipLogo2" class="flippable">Logo 2</div>
(ps it is bad form to define functions inside if statements, as hoisting will move them them to a place you might not expect)
I'd like to create an animation on a website to mimic a scrolling log file or tail -f. I'd feed it a list of fake log messages and they would be written to the bottom of the div and scroll up and off the top as new messages are displayed and then loop around. It needs to look authentic, white on black using a fixed width font etc.
Does anyone know of any javascript or jQuery libraries which could help me with this? I'm a beginner with javascript, so any advice on how to approach this would be much appreciated.
I've made a simple example for you
http://jsfiddle.net/manuel/zejCD/1/
// some demo data
for(var i=0; i<100; i++) {
$("<div />").text("log line " + i).appendTo("#tail")
}
// scroll to bottom on init
tailScroll();
// add button click
$("button").click(function(e) {
e.preventDefault();
$("<div />").text("new line").appendTo("#tail");
tailScroll();
});
// tail effect
function tailScroll() {
var height = $("#tail").get(0).scrollHeight;
$("#tail").animate({
scrollTop: height
}, 500);
}
#tail {
border: 1px solid blue;
height: 500px;
width: 500px;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="tail">
<div>some line of text</div>
</div>
<button>Add Line</button>
Here is a great solution
This uses an ajax request, and the HTTP Range: header to request only the last ~30KB of a log file. It then polls for data appended to that file, and only ever retrieves new data (no refreshing the whole file, or even the last 30KB). Handles file truncation too.
https://github.com/ukhas/js-logtail#readme
I've updated Manuel van Rijn's script to include a timer and a toggle switch, along with some minor changes to the log lines. hope this helps.
http://jsfiddle.net/5rLw3LoL/
html:
<div id="tail">
<div>some line of text</div>
</div>
<button>Add Line</button>
js:
var tailcounter = 100;
var tailswitch = false;
// scroll to bottom on init
tailScroll();
// add line to log
function tailappend() {
$("<div />").text("log line " + tailcounter).appendTo("#tail");
tailcounter++;
tailScroll();
}
// auto update every second
var t = setInterval(tailappend, 1000);
// toggle updates button click
$("button").click(function (e) {
e.preventDefault();
switch (tailswitch) {
case false:
clearInterval(t); // turns off auto update
tailswitch = true;
alert("auto update off");
break;
case true:
t = setInterval(tailappend, 1000); // restarts auto update
tailswitch = false;
alert("auto update on");
break;
}
});
// tail effect
function tailScroll() {
var height = $("#tail").get(0).scrollHeight;
$("#tail").animate({
scrollTop: height
}, 500);
}
css: (important for formatting)
#tail {
border: 1px solid blue;
height: 400px;
width: 500px;
overflow: hidden;
}
This can be achieved with CSS by simply flipping the outer and inner container using transform: rotateX(180deg); https://jsfiddle.net/tnrn6h59/2/
Only issue here is that the scroll is also reversed, not an issue for mobile.