I'm doing simple ID validating html page with javascript. My idea is, whenever user enters a valid ID number, the text field of form changes its colour for few seconds and then revert back to normal.
the code
<script>
var abcArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var IDweights = [7,3,1,0,7,3,1,7,3];
var valuesMap = new Map();
for(var i=0;i<26;i++){
valuesMap.set(abcArray[i],i+10);
}
validateID();
function validateID(){
var idNumber = document.forms.form.idnum.value.toUpperCase();
var sumOfValues = 0;
for(var x = 0; x < idNumber.length; x++){
if(x < 3){
sumOfValues += (valuesMap.get(idNumber.charAt(x))*IDweights[x]);
}
if(x > 3){
sumOfValues += (parseInt(idNumber.charAt(x))*IDweights[x]);
}
}
if(sumOfValues % 10 == idNumber[3]){
var y = document.getElementById("idnum");
y.style.animation = "anim 5s"; // when true change to green
} else {
var y = document.getElementById("idnum");
y.style.animation = "anim1 5s"; //change to red
}
}
the css part
#-webkit-keyframes anim {
0% {background:white;}
20% {background:green;}
100% {background:white;}
}
#-moz-keyframes anim {
0% {background:white;}
20% {background:green;}
100% {background:white;}
}
#-webkit-keyframes anim1 {
0% {background:white;}
20% {background:red;}
100% {background:white;}
}
#-moz-keyframes anim1 {
0% {background:white;}
20% {background:red;}
100% {background:white;}
}
It works but only once. When I click validate button again, then nothing happens. Only when I change ID number for the wrong one, then it works but only once as well, and then again to make it work you need to put the correct one... I am aware it's probably because I'm setting css properties once and thats it, the browser will not change them again if they're the same. But I can't think of proper solution because I'm new to JS and css. I searched for quite long and still didn't find any solution for my problem, partly because I don't really know how to specify it. I'll be grateful for your help.
PS. please only pure js and css - I'am not familiar with jquery yet
the problem is, if the element already has the style="anim1 5s" for example - setting it to that same value again will do nothing. You would need to remove that style, and then add it again.
Better still, when you add the style, add an animationend event listener to that element to remove that animation when the animation completes
function validateID() {
var doneAnimating = function(e) {
// remove the listener
this.removeEventListener('animationend', doneAnimating);
// remove the animate style
this.style.animate = '';
}
var idNumber = document.forms.form.idnum.value.toUpperCase();
var sumOfValues = 0;
for (var x = 0; x < idNumber.length; x++) {
if (x < 3) {
sumOfValues += (valuesMap.get(idNumber.charAt(x)) * IDweights[x]);
}
if (x > 3) {
sumOfValues += (parseInt(idNumber.charAt(x)) * IDweights[x]);
}
}
// moved outside of if/then to tidy up code
var y = document.getElementById("idnum");
// add the listener to the element
y.addEventListener('animationend', doneAnimating);
if (sumOfValues % 10 == idNumber[3]) {
y.style.animation = "anim 5s"; // when true change to green
} else {
y.style.animation = "anim1 5s"; //change to red
}
}
Alternatively, you could simply (outside of this code) add the animationend event listener once, and the doneAnimating can simply remove the animate style and not worry about removing the event listener - in fact you can put the event handler inline to make it very simple
// this is done once only - not sure where in your code you'd put it
document.getElementById("idnum").addEventListener('animationend', function(e) {
this.style.animate = '';
});
function validateID() {
var idNumber = document.forms.form.idnum.value.toUpperCase();
var sumOfValues = 0;
for (var x = 0; x < idNumber.length; x++) {
if (x < 3) {
sumOfValues += (valuesMap.get(idNumber.charAt(x)) * IDweights[x]);
}
if (x > 3) {
sumOfValues += (parseInt(idNumber.charAt(x)) * IDweights[x]);
}
}
// moved outside of if/then to tidy up code
var y = document.getElementById("idnum");
if (sumOfValues % 10 == idNumber[3]) {
y.style.animation = "anim 5s"; // when true change to green
} else {
y.style.animation = "anim1 5s"; //change to red
}
}
Related
"I want disable fade-in and fade-out animation after one time its apply on whole web page"
I need a pure JavaScript code which disable fade-in and fade-out animation after it apply one time
.fade {
/* transition: opacity 0.9s ease-in;*/
opacity: 0;
}
.fade.visible {
transition: opacity 1s ease-in;
opacity: 1;
}
window.addEventListener('scroll', fade);
function fade()
{
let animation=document.querySelectorAll('.fade');
for (let i=0; i<animation.length; i++)
{
let windowheight=window.innerHeight;
let top=animation[i].getBoundingClientRect().top;
if (top < windowheight)
{
animation[i].classList.add('visible');
}
else
{
animation[i].classList.remove('visible');
}
}
}
Use a count variable. When the function that involves the fade-in and fade-out is triggered, add to the count variable. After it is increased, make it so these changes do not occur any more.
let count = 0;
count++;
If you want to have more code in the answer, post some more from your specific example.
This creates a count variable. If you want the animation to occur exactly once, then this should work as the count is increased by one after the animation occurs, making sure it will not happen again.
let count = 0;
window.addEventListener('scroll', fade);
function fade()
{
if (count < 1)
{
let animation=document.querySelectorAll('.fade');
for (let i=0; i<animation.length; i++)
{
let windowheight=window.innerHeight;
let top=animation[i].getBoundingClientRect().top;
if (top < windowheight)
{
animation[i].classList.add('visible');
}
else
{
animation[i].classList.remove('visible');
}
}
}
else
{
return;
}
count++;
}
I have some code that detects if the cursor is being dragged left or right which upon doing so, cycles through an image sequence (similar to that of the Hyundai genesis website and its rotating car).
However, evertime the function is called, it creates white space at the bottom of the html page.
Any idea what might be causing this?
Here's the Javascript for loading the image sequence into the array:
var cache = [];
function imgList(base,firstNum,lastNum) {
var imageFunction;
for(var i = firstNum;i <= lastNum; i++) {
imageFunction = new Image();
if(i <=9){ var EXT = '000'}
else if(i <= 99){var EXT = '00'}
else if(i <= 999){var EXT = '0'}
else{var EXT = ''}
imageFunction.src = base + "." + EXT + i + ".png";
cache.push(imageFunction);
console.log(cache.length);
}
}
Here is the Javascript function that is called when the drag event occurs:
var prevX = -1;
var i = 0;
var drgleft = 0;
var drgright = 0;
function sequence(event){
if(prevX == -1){
prevX = event.pageX;
return false;
}
//drag left
if(prevX > event.pageX){
console.log('dragged left');
drgleft++;
if(drgleft == 2){
drgleft = 0;
i--;
if(i < 0){
i = 30; //for optimization reasons, input the cache.length value manually (this avoids unnecessary errors in the console and laggy framerate as a result).
}
document.getElementById("TheBigOne").src = cache[i].src; //use console.log(i); as a method of verifying that the code is executing correctly
}
}
else if(prevX < event.pageX){
console.log('dragged right');
drgright++;
if(drgright == 2){
drgright = 0;
i++;
if(i > 30){ //for optimization reasons, input the cache.length value manually (this avoids unnecessary errors in the console and laggy framerate as a result).
i=0;
}
document.getElementById("TheBigOne").src = cache[i].src;
}
}
else{}
prevX = event.pageX
}
Here is the html:
<div class="The_main_event" ondrag="sequence(event)" id="PlaneTime">
<br/>
<img src="file:///C:/Users/Foo/Desktop/Website/Web_aeroplane/Web%20Test.0031.png" id="TheBigOne" class="planepic">
<br/>
</div>
If there is white space around an image, a small gap will appear underneath it as long as it is an inline element. There are a few ways to fix it, but the easiest is changing it to a block level element.
Try this:
.planepic {
display: block;
}
Here's a demo
div {
background: red;
display: inline-block;
border: 1px solid black;
}
img {
max-width: 100px;
}
.block {
display: block;
}
<div><img src="https://3.bp.blogspot.com/-W__wiaHUjwI/Vt3Grd8df0I/AAAAAAAAA78/7xqUNj8ujtY/s1600/image02.png"></div>
<div><img src="https://3.bp.blogspot.com/-W__wiaHUjwI/Vt3Grd8df0I/AAAAAAAAA78/7xqUNj8ujtY/s1600/image02.png" class="block"></div>
Alright I found the solution to the issue was something completely unrelated. There was a bit of javascript which was used to remove the issue of the image ghosting when the image was dragged:
document.getElementById("TheBigOne").addEventListener("dragstart", function(event) {
var crt = this.cloneNode(true);
crt.style.backgroundColor = "";
crt.style.opacity = "0"; /* or visibility: hidden, or any of the above */
document.body.appendChild(crt);
event.dataTransfer.setDragImage(crt, 0, 0);
}, false);
Once I removed this code, the issue ceased to occur...
looking at this code now, I can understand why, I guess I shouldn't stay up so late and code rubbish like this.
I'm trying to write my own animations using JavaScript.
I wrote a function for fadeIn() as below, it changes the display property followed by a change in value of opacity. But it doesn't seem to be working.
What am I doing wrong?
function fadeIn(obj, defDisp) {
obj.style.opacity = 0;
obj.style.display = defDisp;
var opVal = 0;
while (opVal < 1) {
obj.style.opacity = opVal;
opVal += 0.1;
}
}
defDisp = Default value for display property
Without a timing interval, this will likely execute too fast for you to see it. The while loop, without a timeout feature, will execute in far less than a second, and you won't see it happen. It's like asking a computer to count to 10, it will do it in less than a millisecond.
Try using a setTimeout
http://www.w3schools.com/jsref/met_win_settimeout.asp
while(opVal < 1) {
setTimeout(function(){
obj.style.opacity = opVal;
opVal += 0.1;
}, 3000);
}
Alter the timer (3000 in this case) to something that makes your fade work for you. Every 1000 is a one second and your loop runs 10 times, so in this case it would be 30 seconds, likely too slow.
I would probably stick with a CSS transition however, as they tend to render better on all browsers.
var el = document.getElementById('fadein');
fadeIn(el);
function fadeIn(ele, defDisp) {
ele.style.opacity = 0;
ele.style.display = defDisp;
var opVal = 0;
var t = setInterval(function(){
if(opVal >= 1){
clearInterval(t);
}
ele.style.opacity = opVal;
opVal += 0.1;
}, 100);
}
#fadein{ background: #ccc; border:1px solid #ddd; padding: 10px }
<div id="fadein">Hello</div>
Use a function that calls itself after a delay.
function fadeIn(obj, defDisp) {
obj.style.opacity = 0;
obj.style.display = defDisp;
var last = +new Date(); // Keep track of the time to calculate the opacity
var fadeStep = function () {
obj.style.opacity = +obj.style.opacity + (new Date() - last) / 800;
last = +new Date();
if (+obj.style.opacity < 1) {
setTimeout(fadeStep, 16);
}
};
fadeStep();
}
var el = document.getElementById('box');
fadeIn(el, 'block');
#box{ padding: 1em; background: #009afd; color: #ffffff; display: none; }
<div id="box">Hello</div>
If you want the fade to be faster, replace 800 by anything lower and vice-versa.
Because html render and for loop use the same thread, so when you doing the for-loop,you can't see any changes until the function complete. You have to use a setTimeout or setInterval (or requestAnimationFrame which is introduced from html5) so you browser can have the control to change the properties on the page:
You can see a example from the snippet, although the second that use a setTimeout is faster than the first one, which use for loop, the first one will not change its color as browser not able to change color during for-loop.
And if you choose to use requestAnimationFrame like I do in the snippets, you can have a smooth animation while the time can also be controlled precisely.
function fadeIn() {
this.style.opacity = 0;
this.style.display = 'block';
var opVal = 0;
console.time("count");
while(opVal < 1) {
this.style.opacity = opVal;
opVal += 0.000001;
}
console.timeEnd("count");
}
// Accept target as the target to apply anim, time is total anim time in ms.
function fadeInAlt(target, time) {
var opacity = 0;
var last = window.performance.now();
console.time("count2");
target.style.opacity = opacity;
target.style.display = 'block';
var fadeInFunc = function(timeStamp) {
if (opacity < 1) {
// Define the change by passed time.
var timePassed = timeStamp - last;
opacity += timePassed / time;
target.style.opacity = opacity;
last = timeStamp;
requestAnimationFrame(fadeInFunc);
} else {
console.timeEnd("count2");
return;
}
};
requestAnimationFrame(fadeInFunc);
}
var div = document.getElementById('test');
div.onclick = fadeIn;
var div2 = document.getElementById('test2');
div2.onclick = function() {
fadeInAlt(this, 3000);
};
#test {
background-color: red;
width: 30px;
height:30px;
}
#test2 {
background-color: blue;
width: 30px;
height:30px;
}
<div id="test"></div>
<div id="test2"></div>
I have a div item in table, i am rotating the div in JS and i am calling the function repeatedly, but the flip happens only for first time when the function is executed and again when function is called it just shows the div, without flipping the div.
The thing what i need is, when each time i call the function the div should flip the div.
How can i do that?
Css:
.box-1{
transform: rotateY(180deg);
display:none;
}
JQuery:
function startSlidecat1(started) {
for (var i = 0; i < footwear.length; i++) {
var image = footwear[i][0];
imgslidercat1(image, i * 2100, i == footwear.length - 1);
}
};
function imgslidercat1(image, timeout, last) {
window.setTimeout(function() {
document.getElementById('flip-1').style.display = 'none';
document.getElementById('category-1').style.display = 'block';
document.getElementById('category-1').innerHTML = "";
var product = document.getElementById('category-1');
var elem = document.createElement("img");
product.appendChild(elem);
elem.src = image;
if (last) {
flip();
}
}, timeout);
}
startSlidecat1();
function flip(){
$('#category-1').delay(100).css('display', 'none');
$('.box-1').delay(100).css('display', 'block');
$('.box-1').transition({
perspective: '100px',
rotateY: '360deg'
},200)
setTimeout(startSlidecat1, 2000);
}
The first time when div is flipping, its rotateY value changes from 180deg to 360deg, that is visible. But from second time onward, its value remains at 360deg so nothing happens. You just need to reset the value each time you call the function like this,
$('.box-1').css({transform:'perspective(100px) rotateY(180deg)'});
You can include this inside the startSlidecat1 function like this,
function startSlidecat1(started) {
$('.box-1').css({transform:'perspective(100px) rotateY(180deg)'});
for (var i = 0; i < footwear.length; i++) {
var image = footwear[i][0];
imgslidercat1(image, i * 2100, i == footwear.length - 1);
}
};
var bubble = [$('#bubble1'), $('#bubble2'), $('#bubble3'), $('#bubble4'), $('#bubble5'), $('#bubble6')];
var bubbleFirst = 0;
var visibleBubbles = 3;
var bubbleHeight = 200;
var bubbleTimeDelay = 5000;
var bubbleTimer = setTimeout(function(){animateBubbles();}, bubbleTimeDelay/2);
function animateBubbles(){
clearTimeout(bubbleTimer);//stop from looping before this is finished
for(var i = 0; i < visibleBubbles + 1; i++){
count = i + bubbleFirst;
if ( count >= bubble.length ) count = count - bubble.length;//keep index inside array
bubble[count].animate({top:'-=' + bubbleHeight}, 2000);
}
bubble[bubbleFirst].css('top', '600px');//put elements moving off top to bottom
//resetBubbles();
bubbleFirst++;
if(bubbleFirst >= bubble.length) bubbleFirst = 0;//bubbles have looped
bubbleTimer = setTimeout(function(){animateBubbles();}, bubbleTimeDelay);//start looping again
}
bubble1 starts with top: 0px;
bubble2 starts with top: 200px;
bubble3 starts with top: 400px;
bubble4-6 start with top: 600px;
all are position: absolute in a wrapper div
Apologies for the code dump. My problems are all centered around line 16:
bubble[bubbleFirst].css('top', '600px');
This code is seemingly never executed, there is no error in my console and I have verified that bubble[bubbleFirst] is returning the correct element using console.log. (It's a div)
I'm currently using a workaround, but it is not dynamic:
function resetBubbles(){
/*bubble[bubbleFirst].css('top', '600px');//put elements moving off top to bottom*/
if(bubble[0].css('top') == '-200px') bubble[0].css('top', '600px');
if(bubble[1].css('top') == '-200px') bubble[1].css('top', '600px');
if(bubble[2].css('top') == '-200px') bubble[2].css('top', '600px');
if(bubble[3].css('top') == '-200px') bubble[3].css('top', '600px');
if(bubble[4].css('top') == '-200px') bubble[4].css('top', '600px');
if(bubble[5].css('top') == '-200px') bubble[5].css('top', '600px');
}
I have no idea why this isn't working, it's probably a logical error on my part. But I can't for the life of me find it. Any help would be appreciated. Thanks for your time.
Is it possible that the call to animate conflicts with you custom settings the top property? ie. you set it, but top is immediately altered again by animate. You can pass a callback to animate that will run when the animation has finished. That's when you should reset your bubble position.
function animate_bubble(index) {
bubble[index].animate({ top: "0px" }, 2000 /* 2 seconds */, function () {
bubble[index].css({ top: "600px" });
animate_bubble(index);
}
}
animate_bubble(0);
animate_bubble(1);
// etc .. probably do this in a for-loop
You'll need to find some way to cancel the animation though, shouldn't be too hard.
The problem was that bubbleFirst was incremented before the animation was finished. I changed my function to the following:
function animateBubbles(){
clearTimeout(bubbleTimer);//stop from looping before this is finished
for(var i = 0; i < visibleBubbles + 1; i++){
count = i + bubbleFirst;
if ( count >= bubble.length ) count = count - bubble.length;//keep index inside array
if (count == bubbleFirst)
{
bubble[count].animate({top:'-=' + bubbleHeight, opacity: 0}, bubbleAnimationSpeed, function(){
bubble[bubbleFirst].css('top', displayHeight+'px');
bubble[bubbleFirst].css('opacity', '1');
});
}
else if(i == visibleBubbles)
{
bubble[count].animate({top:'-=' + bubbleHeight}, bubbleAnimationSpeed, function(){
bubbleFirst++;
if(bubbleFirst >= bubble.length) bubbleFirst = 0;//bubbles have looped
bubbleTimer = setTimeout(function(){animateBubbles();}, bubbleTimeDelay);/*start looping again*/
});
}
else bubble[count].animate({top:'-=' + bubbleHeight}, bubbleAnimationSpeed);
}
}
Thanks for your input guys!