I'm creating a simple chat in Javascript/PHP. I would like to flash/blink tab when new message is coming like on Facebook for example. How can I do that?
Here is example code:
(function () {
var original = document.title;
var timeout;
window.coders = function (newMsg, howManyTimes) {
function step() {
document.title = (document.title == original) ? newMsg : original;
if (--howManyTimes > 0) {
timeout = setTimeout(step, 1000);
};
};
howManyTimes = parseInt(howManyTimes);
if (isNaN(howManyTimes)) {
howManyTimes = 5;
};
cancelcoders(timeout);
step();
};
window.cancelcoders = function () {
clearTimeout(timeout);
document.title = original;
};
}());
You can use this code something like :
coders("New Message from Bhavin Solanki");
... or...
coders("New Message from Bhavin Solanki", 20); // toggles it 20 times.
You're better off doing the animation in css, and just using javascript to start and stop the animation. You got downvoted because you did not show your attempt at a solution.
(function(){
var message = document.querySelector('.message'),
button = document.querySelector('#button');
button.addEventListener('click', blink, false);
// this is where you toggle the class
function blink(e){
message.classList.toggle('blink');
}
})();
#keyframes blink {
from {
background-color: red;
color: white;
}
to {
background-color: white;
color: red;
}
}
.message {
text-align: center;
}
/* run the animation on .message when it also has the class .blink */
.message.blink {
animation: blink 1s linear infinite alternate;
}
<div class="message">You've got a message</div>
<button id="button">blink</button>
Related
How can I have text fade in on each click and not just the first time using css transition and JavaScript?
Here is what I have so far
<style>
#data {
transition: .7s;
}
</style>
<h1 id="data"></h1>
click 1
document.getElementById('data').style.opacity = 0;
function go(event){
event.preventDefault();
document.getElementById('data').style.opacity = 1;
document.getElementById('data').innerHTML = 'test';
}
document.getElementById('clicker').addEventListener('click', go);
It can also be done using Element.animate():
const dataElement = document.getElementById('data')
dataElement.style.opacity = 0
function go(event) {
event.preventDefault()
dataElement.animate({
opacity: [0, 1]
}, 700).onfinish = () => dataElement.style.opacity = 1
}
document.getElementById('clicker').addEventListener('click', go)
<h1 class="fade-in" id="data">test</h1>
click 1
EDIT:
In the above snippet onfinish event handler was used to maintain the final opacity value since it was being set back to 0 after the animation ends. But I found that this can also be achieved by setting fill: 'forwards' in the keyframe options:
const dataElement = document.getElementById('data')
dataElement.style.opacity = 0
function go(event) {
event.preventDefault()
dataElement.animate({
opacity: [0, 1]
}, {
duration: 700,
fill: 'forwards'
})
}
document.getElementById('clicker').addEventListener('click', go)
<h1 class="fade-in" id="data">test</h1>
click 1
Also you might want to check browser compatibility before implementing those approaches
And if you want a safer approach you may use css animations:
const data = document.getElementById('data')
data.style.opacity = 0
const clicker = document.getElementById('clicker')
clicker.addEventListener('click', () => {
data.classList.remove('fade-in')
data.offsetWidth // required to trigger a reflow and restart the animation
data.classList.add('fade-in')
})
.fade-in {
animation-name: fadein-animation;
animation-duration: 700ms;
animation-fill-mode: forwards;
}
#keyframes fadein-animation {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<h1 id="data">test</h1>
click 1
setTimeout might work for you. On click set it invisible immediately and use setTimeout to have a delay then show it again.
document.getElementById('data').style.opacity = 0;
document.getElementById('data').innerHTML = 'test';
function go(event){
event.preventDefault();
document.getElementById('data').style.opacity = 0;
setTimeout(() => {
document.getElementById('data').style.opacity = 1;
}, 1000);
}
document.getElementById('clicker').addEventListener('click', go);
#data {
transition: .7s;
}
<h1 id="data"></h1>
click 1
<h1 id="data" style="opacity:0"> </h1>
<button type="button" id="clicker">Fade In</button>
<script>
var data = document.getElementById('data');
function fadeIn(){
data.innerHTML = 'Data entered successfully.';
data.animate({opacity:[0,1]},{duration:400,fill:'forwards'});
}
document.getElementById('clicker').addEventListener('click',fadeIn);
</script>
I have a div which is displayed with onclick then which disappear with setTimeout:
css
#light {
position:absolute;
left:40px;
top:45px;
border-left:50px solid transparent;
border-right:50px solid transparent;
border-bottom:20px solid red;
opacity:0;
}
js (don't know if the syntax is correct but it works)
function change() {
var element = document.getElementById("light");
element.style.opacity = "1";
element.style.transitionDelay = "4s", // only the 1stime with onclick
setTimeout(() => {
element.style.opacity = "0";
}, 5000)
}
html
<button onclick="change()">light</button>
<div id="light"></div>
What I would like is that this action repeats then by itself every 2 minutes:
- after 2min, #light is displayed again for 5s (opacity="1")
- then hidden again (opacity="0")and so on, and so every 2 min.I know about the setInterval() method but it's too difficult for me to use it correctly - the script doesn't work at regular interval (every 2 min).ps: I've looked similar questions but all this is beyond my competence (ie, 0).
I'm not sure why you can't use timeouts?
Wouldn't something like this work?
( you can adjust the timers... I didn't want to wait minutes to see the light blink so I set it to few seconds)
let timer;
let started = false;
let delayTimer;
const lightOn = (clicked) => {
// do nothing if clicked for the second time
if (clicked && started) {return;}
const fn = () => {
const element = document.getElementById("light");
element.classList.add('light-on');
timer = setTimeout(lightOff, 1000);
};
if (clicked) {
delayTimer = setTimeout(fn, 3000);
} else {
fn();
}
started = true;
}
const lightOff = () => {
const element = document.getElementById("light");
element.classList.remove('light-on');
timer = setTimeout(lightOn, 2000);
}
const stop = () => {
clearTimeout(timer);
clearTimeout(delayTimer);
timer = undefined;
delayTimer = undefined;
started = false;
}
.light {
background-color: gray;
opacity: 0.1;
width: 2em;
height: 2em;
display: inline-block;
border: 1px solid black;
border-radius: 2em;
}
.light-on {
background-color: yellow;
opacity: 1;
}
<div id="light" class="light"></div>
<button onclick="lightOn(true)" style="display: block;">start</button>
<button onclick="stop()" style="display: block;">stop</button>
var span = document.getElementById('loading_dots');
var int = setInterval(function() {
if ((span.innerHTML += '●').length == 4)
span.innerHTML = '';
}, 400);
(function(){
var loading_dots = document.getElementById("loading_dots"),
show = function(){
loading_dots.style.display = "block";
setTimeout(hide, 5000); // 5 seconds
},
hide = function(){
loading_dots.style.display = "none";
};
show();
})();
How can I make it so loading_dots start on the click of a button, and re-activates everytime I click the button? the bottom function is to stop it after 5 seconds, maybe could merge it into one function?
Needs to work for 3 seperate buttons and relaunch on click of each, also needs to display inside of <span class="loading_dots" id="loading_dots"></span> any method is fine, css, jquery, or javascript
here is a jQuery version:
(function ( $ ) {
$.fn.loader = function( options ) {
var settings = $.extend({
text:"●",
spn: undefined
}, options );
$.each(this, function(){
var btn = this;
var int;
var spn;
if (settings.spn === undefined) {
spn = $("<span/>" , { "class":"loading_dots" });
$(btn).append(spn);
} else {
spn= $(settings.spn);
}
var show = function(){
btn.setAttribute("disabled", "disabled")
clearInterval(int);
spn.show();
int = setInterval(function() {
if ((spn[0].innerHTML += settings.text).length == 4)
spn.html("");
}, 400);
setTimeout(hide, 5000); // 5 seconds
}
var hide = function (){
spn.hide();
btn.removeAttribute("disabled", "disabled")
clearInterval(int);
}
btn.addEventListener("click", show);
});
};
}( jQuery ));
// now bind it by its class, this only need to be run once every time new button is added to the html
$(".btn").loader({spn:".loading_dots"});
// and you could also specify the text by
// $(".btn").loader({text: "*"});
.loading_dots {
color:red;
display:none;
width:100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<span class="loading_dots"></span>
<button class="btn" type="button" >
submit
</button>
<button class="btn" type="button" >
submit
</button>
</div>
If you want to add an event listener for a button click, just select the buttons, and add the listeners in a loop:
document.querySelectorAll("button").forEach(e => e.addEventListener("click", myFunc));
Alternatively, listen for any click, then check if the event's target is a button:
document.addEventListener("click", (e) => if (e.target.tagName == "BUTTON") myFunc());
You could use CSS for the most part of your code, and than simply toggle a show class on the parent #loading element:
const Loading = () => {
let tOut = null;
const el = document.querySelector("#loading");
const show = () => {
el.classList.add('show');
tOut = setTimeout(hide, 5000);
};
const hide = () => {
el.classList.remove('show');
clearTimeout(tOut);
};
return {
show,
hide
};
};
const loadingDots = Loading();
const loadBtns = document.querySelectorAll('.load');
[...loadBtns].forEach(el => el.addEventListener('click', loadingDots.show));
// you can always use loadingDots.hide() to hide when needed (before the 5sec ticks out)
#loading {
position: fixed;
z-index: 100;
top:0;
left: 0;
width:100vw;
height:100vh;
display:flex;
background: rgba(0,0,0,0.5);
color: #fff;
font-size: 3em;
align-items: center;
justify-content:center;
visibility: hidden;
opacity: 0;
transition: 0.4s;
}
#loading.show {
opacity: 1;
visibility: visible;
}
#keyframes blink {
50% {opacity: 1;}
}
#loading i:after {content: "\25cf";}
#loading i { opacity: 0; animation: blink 1.2s infinite; }
#loading i:nth-child(2) { animation-delay: .2s; }
#loading i:nth-child(3) { animation-delay: .4s; }
<div id="loading"><i></i><i></i><i></i></div>
<button class="load">LOAD</button>
<button class="load">LOAD</button>
<button class="load">LOAD</button>
A plain javascript version with the option to programmatically/manually stop displaying the loading dots. Just pass the id of the parent element you want the loading to be attached to. By default the loading will be appended to the parent but you can optionally pass an object as the last parameter with a position property.
function removeLoading(id) {
var parent = document.getElementById(id);
var spans = parent.getElementsByClassName("loading_dots");
while (spans.length > 0) {
var span = spans[0];
if (span.dataset.timerId) {
clearTimeout(span.dataset.timerId);
}
span.remove();
}
}
function addLoading(id, options) {
options = options || {};
var parent = document.getElementById(id);
var existingSpans = parent.getElementsByClassName("loading_dots");
if (existingSpans.length > 0) {
removeLoading(id);
}
var span = document.createElement("span");
span.setAttribute("class", "loading_dots");
if (options.timerId) {
span.dataset.timerId = options.timerId;
}
parent.insertAdjacentElement(options.position || "beforeend", span);
setInterval(function () {
if ((span.innerHTML += '●').length == 4)
span.innerHTML = '';
}, 400)
}
function addLoadingWithTimeout(id, ms, options) {
options = options || {};
var timerId = setTimeout(function () { removeLoading(id) }, ms);
options.timerId = timerId;
addLoading(id, options);
}
<p id="load1">Load 1 - Will stop automatically in 3 seconds after starting. </p>
<button onclick="addLoadingWithTimeout('load1', 3000)">Start Load 1</button>
<button onclick="removeLoading('load1')">Stop Load 1</button>
<p id="load2">Load 2 - Only manual Stop </p>
<button onclick="addLoading('load2')">Start Load 2</button>
<button onclick="removeLoading('load2')">Stop Load 2</button>
Here you go. on the HTML side, you just pass the event to the button that you want and then the id, as a string, of the span/div where you want the load icons to appear.
HTML:
<button id="btn" onclick="load(event, 'loadDiv')">Load</button>
<div>
<span id="loadDiv"></span>
</div>
Below, we are getting the btn id from event so you don't have to manually pass it everytime. Then we are defining function for the innerhtml icons. Lastly, we are running the showIcon function every .4s and then clearing the interval after 5 seconds.
JS:
function load(e, location) {
var btn = document.getElementById(e.srcElement.id)
var loadDiv = document.getElementById(location)
function showLoad() {
if (loadDiv.innerHTML.length < 3) {
return loadDiv.innerHTML += '●'
}
loadDiv.innerHTML = ''
}
(function() {
var loadIcons = setInterval(function() {
showLoad()
}, 400)
var clear = setTimeout(function() {
clearInterval(loadIcons)
}, 5000)
})()
}
Hope this helps!
You can define your code in a function and add click handler to the button.
function myFunc() {
var span = document.getElementById('loading_dots');
var int = setInterval(function() {
if ((span.innerHTML += '●').length == 4)
span.innerHTML = '';
}, 400);
(function(){
var loading_dots = document.getElementById("loading_dots"),
show = function(){
loading_dots.style.display = "block";
setTimeout(hide, 5000); // 5 seconds
},
hide = function(){
loading_dots.style.display = "none";
};
show();
})();
}
document.getElementById("myBtn1").addEventListener("click", myFunc);
document.getElementById("myBtn2").addEventListener("click", myFunc);
I created an animation with CSS that changes the background-position of an element over time, to create a sort of scrolling effect with the background.
#keyframes stars-animate {
0% {
background-position: 0 -500px;
}
100% {
background-position: 2000px -500px;
}
}
This works perfectly. However, I also want to start to rewind the animation and create a reverse scrolling event. This is triggered by some irrelevant action.
function triggerReverse(element) {
element.style.animationDirection = 'reverse';
}
However, when I set the animation-direction to reverse, it does work, but not before it flips the entire background.
Am I doing it wrong, or is that the wrong way to do it, and if so, what is the right way?
Edit: I need to be able to reverse the animation while it is playing
UPDATE
The renewed sample code below provide the effect that enables a user to interrupt/pause the animation (during the first iteration) and immediately start to reverse the animation.
Here it is using time to control. Record the elapsed time from the beginning of animation, and calculate how to start the reverse animation. There are 2 iterations defined in css to make a whole loop. Without user intervention, the animation pauses/stops after the first iteration. But if there is, pause the iteration and immediately re-start it with a calculated animation-delay time. This will looks like an immediate reverse, however actually it is a new start.
There is also a trick on how to re-start the animation. Please refer to the code comment.
I searched around but found nobody has mentioned a similar scenario so far, nor a similar solution. Instead of to use time to control, I would like to see other better approaches.
My test also proves that different running environments render slightly different smoothness. Fortunately, here in SO is the best.
Try the solution to see if it can works well in your own scenario.
const span = document.querySelector('span'),
button = document.querySelector('button'),
duration = 10; // animation-during
let startTime;
span.addEventListener('animationstart', () => {
startTime = Date.now();
button.style.visibility = 'visible';
});
span.addEventListener('animationiteration', () => span.style.animationPlayState = 'paused');
span.addEventListener('animationend', () => {
button.style.visibility = 'hidden';
});
button.addEventListener('click', () => {
span.classList.remove('my_anim');
void span.offsetWidth; // safely apply changes
span.classList.add('my_anim');
const elapsed = Date.now() - startTime;
const delay = (elapsed < duration * 1000) ? (elapsed / 1000 - duration * 2) : -duration;
span.style.animationDelay = `${delay}s`;
span.style.animationPlayState = 'running';
});
span.my_anim {
animation: 10s 2 alternate my_move;
}
#keyframes my_move {
from {
margin-left: 0;
}
to {
margin-left: 50%;
}
}
button {
visibility: hidden;
}
<div>
<span class="my_anim">#</span>
</div>
<button>reverse</button>
This example does not use background-position for animation but a plain character.
const span = document.querySelector("span"),
button = document.querySelector("button");
span.addEventListener(
"animationiteration",
function() {
this.classList.add("paused");
button.style.visibility = "visible";
}
);
button.addEventListener(
"click",
function() {
this.style.visibility = "hidden";
span.classList.remove("paused");
}
);
span {
animation: 3s 2 alternate my_move;
}
span.paused {
animation-play-state: paused;
}
#keyframes my_move {
from {
margin-left: 0;
}
to {
margin-left: 50%;
}
}
button {
visibility: hidden;
}
<div>
<span>#</span>
</div>
<button>reverse</button>
NB: Use -webkit- prefix for css animation when necessary.
building off of #themefield's answer above - thanks, #themefield! - this way works the 'best', not perfect. (Sometimes the letter isn't in exactly the right spot when it reverses.)
The approach that worked was
a) reset animation to forward / reverse at the end
b) replace the animation with its opposite on toggling, setting a - start time to try to position it where it was.
Often it works pretty good, sometimes a lot off.
span = document.querySelector('span')
button = document.querySelector('button')
timerElement = document.querySelector('#timerId')
duration = 3; // animation-during
let startTime = Date.now();
toSec = (msec) => msec / 1000
elapsedTimeMsec = () => Date.now() - startTime
elapsedTimeSec = () => toSec(elapsedTimeMsec())
updateTimer = () => timerElement.innerHTML = `${elapsedTimeSec().toPrecision(2)}s`
let intervalHandle;
startTimer = () => {
intervalHandle = window.setInterval(() => {
updateTimer()
}, 500)
}
endTimer = () => {
window.clearInterval(intervalHandle)
intervalHandle = null
}
span.addEventListener('animationstart', () => {
startTime = Date.now();
startTimer()
});
span.addEventListener('animationiteration', () => span.style.animationPlayState = 'paused');
toggleAnimation = (shouldDelay) => {
span.classList.remove('my_anim');
void span.offsetWidth;
span.classList.add('my_anim');
if(span.style.animationDirection !== 'reverse')
span.style.animationDirection = 'reverse';
else
span.style.animationDirection = 'normal';
if(shouldDelay !== null && shouldDelay) {
span.style.animationDelay = `-${elapsedTimeSec()}s`;
} else {
span.style.animationDelay = `0s`;
}
span.style.animationPlayState = 'running';
}
span.addEventListener('animationend', () => {
endTimer()
updateTimer()
toggleAnimation();
});
button.addEventListener('click', () => {
endTimer()
updateTimer()
toggleAnimation(true) // todo pass in delay!
});
span.my_anim {
font-size: 54px;
animation: 3s 1 normal both my_move;
}
#keyframes my_move {
from {
margin-left: 0;
}
to {
margin-left: 50%;
}
}
button {
/*visibility: hidden;*/
}
#timerId {
font-size: 24px;
color: darkturquoise;
position: fixed;
bottom: 0;
left: 50%;
}
<div>
<span class="my_anim">#</span>
</div>
<button>reverse</button>
<span id="timerId"></span>
I'm looking for a good way to display some punctuation loading "animation".
What I want is something like this:
This will display at second 1: "Waiting for your input."
This will display at second 2: "Waiting for your input.."
This will display at second 3: "Waiting for your input..."
This will display at second 4: "Waiting for your input...."
This will display at second 5: "Waiting for your input."
This will display at second 6: "Waiting for your input.."
This will display at second 7: "Waiting for your input..."
This will display at second 8: "Waiting for your input...."
And so on.
I started by surrounding the dots in spans and thought I could loop through them with jquery and display one more, one more, one more, then reset to 1. But the code got very clumsy, so I wonder how you would do this?
Pure CSS solution
Demo: jsfiddle.net/feklee/D59P9
HTML:
Waiting<span class="dots"><span>.</span><span>.</span><span>.</span></span> for more.
CSS:
#keyframes dots-1 { from { opacity: 0; } 25% { opacity: 1; } }
#keyframes dots-2 { from { opacity: 0; } 50% { opacity: 1; } }
#keyframes dots-3 { from { opacity: 0; } 75% { opacity: 1; } }
#-webkit-keyframes dots-1 { from { opacity: 0; } 25% { opacity: 1; } }
#-webkit-keyframes dots-2 { from { opacity: 0; } 50% { opacity: 1; } }
#-webkit-keyframes dots-3 { from { opacity: 0; } 75% { opacity: 1; } }
.dots span {
animation: dots-1 1s infinite steps(1);
-webkit-animation: dots-1 1s infinite steps(1);
}
.dots span:first-child + span {
animation-name: dots-2;
-webkit-animation-name: dots-2;
}
.dots span:first-child + span + span {
animation-name: dots-3;
-webkit-animation-name: dots-3;
}
WebKit-only alternative
Advantage: No nested tags. This means that the ellipsis could be put as content
into an ::after pseudo element.
Demo: jsfiddle.net/feklee/vFT7W
HTML:
Waiting<span>...</span> for more.
CSS:
body {
font-family: 'Roboto', sans-serif;
font-size: 50px;
}
#-webkit-keyframes dots {
0% { background-position: 0px; }
100% { background-position: 50px; }
}
span {
background: linear-gradient(to right, white 50%, black 50%);
color: transparent;
-webkit-background-clip: text;
-webkit-animation: dots 1s infinite steps(4);
padding-right: 40px;
margin-right: -40px;
}
The trick to making a string of dots is to make a sparse Array and then join all the elements with the desired character.
var count = 0;
setInterval(function(){
count++;
var dots = new Array(count % 10).join('.');
document.getElementById('loadingtext').innerHTML = "Waiting for your input." + dots;
}, 1000);
Here is a Live demo.
This can be very easy:
HTML
<span class="dots"></span>
JQuery
setInterval(function() {
var th = $('.dots');
if(th.text().length < 5){
th.text(th.text()+".");
}else{
th.text("");
}
}, 500);
Demo
Now sure how the code got out of hand, you could just do:
setInterval(function () {
var span = $("#text-loader").children("span:eq(0)");
var ellipsis = span.html();
ellipsis = ellipsis + ".";
if (ellipsis.length > 5) {
ellipsis = ".";
}
span.html(ellipsis);
}, 1000);
<div id="text-loader">
This will display at second 1: "Waiting for your input<span>.</span>
</div>
And as for the 1, you can swap that out with the number of periods.
try this function: i'v put an example here http://jsfiddle.net/XFd39/
var i=0;
function f() {
if(i<=4)
$('#a').append(".");
i++;
if(i==4){
$('#a').html("");
i=0;
}
setTimeout(f,500);
}
f();
Here is a pretty simple variant: http://jsfiddle.net/psycketom/FusdC/
Read the comments below to understand what everything is doing there.
var span = $('.dots'); // take the element where you have the maximum count of dots
var text = span.text(); // cahce it's text value
// we set up a function here, so we can loop it all the time
var loading = function()
{
$({
count : 1 // we start at one dot
}).animate({
count : text.length // together forming all of it
}, {
duration : 1000, // make the animation complete in one second
step : function() {
span.text( text.substring(0, Math.round(this.count)) ); // on each step, change the text accordingly to current iteration
},
complete : function() {
loading(); // once complete, start all over again
}
});
};
loading(); // start it up for the first time
Here you also gain the advantage of using easing if you wish, easily changing total duration and bunch of other benefits in case you're good with jQuery.
Dude, unless you want to display this animation forever you will need a way to stop the animation, or?
Don't even think about global variables, this is JavaScript and it's got closures for that :)
<p>please wait<span id="wait"></span></p>
<input type="submit" id="start" value="start">
<input type="submit" id="stop" value="stop">
<script type="text/javascript">
$(document).ready(function() {
var animator = function($el) {
var dotCount = 1;
var started = true;
return {
"start" : function step() {
dotCount = (dotCount + 1) % 10;
$el.text(new Array(dotCount).join('.'));
if (started) {
setTimeout(step, 100);
}
},
"stop" : function() {
started = false;
}
}
};
var animatedWait = animator($("#wait"));
$("#start").click(animatedWait.start);
$("#stop").click(animatedWait.stop);
});
</script>
Here is a modified version that will turn off the dots after a time.
var count = 0;
var dots = setInterval(function(){
count++;
document.getElementById('loadingtext').innerHTML = "Waiting for your input." + new Array(count % 5).join('.');
if (count == 10){ // show two iterations of the array.
clearInterval(dots); // stop the dots.
}
}, 100); // sets the speed
http://jsfiddle.net/Ty4gt/331/