I have small problem with code i have to do small animation when displaying element in javascript something like a delay After that function.
function OpenPanelEdit() {
const element = document.getElementsByClassName("menu-on-center-edit");
for(const i=0; i < element.length; i++) {
element[i].style.display = 'flex';
}
};
Somebody have any idea ?
Just set the element's animation via el.style.animation.
function OpenPanelEdit() {
const element = document.getElementsByClassName("menu-on-center-edit");
for(const i=0; i < element.length; i++) {
element[i].style.display = 'flex';
element[i].style.animation = 'someAnimation 1s';
}
};
And the CSS: (This can be any animation)
#keyframes someAnimation {
from {
transform: scale(0.5);
opacity: 0;
}
}
If you want to run a function when the animation ends, use setTimeout:
function OpenPanelEdit() {
const element = document.getElementsByClassName("menu-on-center-edit");
for(const i=0; i < element.length; i++) {
element[i].style.display = 'flex';
element[i].style.animation = 'someAnimation 1s';
window.setTimeout(() => {
runSomeFunction();
}, 1000);
}
};
Related
When I'm linking Bootstrap 5 its just fading out the text instead of fading in.
When I remove the link everything just work fine.
const animatedText = document.querySelector(".fancy");
const strText = animatedText.textContent;
const splitText = strText.split("");
animatedText.textContent = "";
for (let i = 0; i < splitText.length; i++) {
animatedText.innerHTML += "<animated>" + splitText[i] + "</animated>";
}
let char = 0;
let timer = setInterval(onTick, 50);
function onTick() {
const animated = animatedText.querySelectorAll('animated')[char];
animated.classList.add('fade');
char++
if (char === splitText.length) {
complete();
return;
}
}
function complete() {
clearInterval(timer);
timer = null;
}
animated {
opacity: 0;
transition: all 0.4s ease;
}
animated.fade {
opacity: 1;
}
<h2 class="fancy">WELCOME TO MY WORLD</h2>
Bootstrap have .fade class in CSS which is responsible for "fade out" alert boxes.
Change your "fade" class to "text-fade" or something else and everything will be okay.
I am working on a basic sorting visualizer with using only HTML, CSS, and JS, and I've run into a problem with the animation aspect. To initialize the array, I generate random numbers within some specified range and push them on to the array. Then based on the webpage dimensions, I create divs for each element and give each one height and width dimensions accordingly, and append each to my "bar-container" div currently in the dom.
function renderVisualizer() {
var barContainer = document.getElementById("bar-container");
//Empties bar-container div
while (barContainer.hasChildNodes()) {
barContainer.removeChild(barContainer.lastChild);
}
var heightMult = barContainer.offsetHeight / max_element;
var temp = barContainer.offsetWidth / array.length;
var barWidth = temp * 0.9;
var margin = temp * 0.05;
//Creating array element bars
for (var i = 0; i < array.length; i++) {
var arrayBar = document.createElement("div");
arrayBar.className = "array-bar"
if (barWidth > 30)
arrayBar.textContent = array[i];
//Style
arrayBar.style.textAlign = "center";
arrayBar.style.height = array[i] * heightMult + "px";
arrayBar.style.width = barWidth;
arrayBar.style.margin = margin;
barContainer.appendChild(arrayBar);
}
}
I wrote the following animated selection sort and it works well, but the only "animated" portion is in the outer for-loop, and I am not highlighting bars as I traverse through them.
function selectionSortAnimated() {
var barContainer = document.getElementById("bar-container");
var barArr = barContainer.childNodes;
for (let i = 0; i < barArr.length - 1; i++) {
let min_idx = i;
let minNum = parseInt(barArr[i].textContent);
for (let j = i + 1; j < barArr.length; j++) {
let jNum = parseInt(barArr[j].textContent, 10);
if (jNum < minNum) {
min_idx = j;
minNum = jNum;
}
}
//setTimeout(() => {
barContainer.insertBefore(barArr[i], barArr[min_idx])
barContainer.insertBefore(barArr[min_idx], barArr[i]);
//}, i * 500);
}
}
I am trying to use nested setTimeout calls to highlight each bar as I traverse through it, then swap the bars, but I'm running into an issue. I'm using idxContainer object to store my minimum index, but after each run of innerLoopHelper, it ends up being equal to i and thus there is no swap. I have been stuck here for a few hours and am utterly confused.
function selectionSortTest() {
var barContainer = document.getElementById("bar-container");
var barArr = barContainer.childNodes;
outerLoopHelper(0, barArr, barContainer);
console.log(array);
}
function outerLoopHelper(i, barArr, barContainer) {
if (i < array.length - 1) {
setTimeout(() => {
var idxContainer = {
idx: i
};
innerLoopHelper(i + 1, idxContainer, barArr);
console.log(idxContainer);
let minIdx = idxContainer.idx;
let temp = array[minIdx];
array[minIdx] = array[i];
array[i] = temp;
barContainer.insertBefore(barArr[i], barArr[minIdx])
barContainer.insertBefore(barArr[minIdx], barArr[i]);
//console.log("Swapping indices: " + i + " and " + minIdx);
outerLoopHelper(++i, barArr, barContainer);
}, 100);
}
}
function innerLoopHelper(j, idxContainer, barArr) {
if (j < array.length) {
setTimeout(() => {
if (j - 1 >= 0)
barArr[j - 1].style.backgroundColor = "gray";
barArr[j].style.backgroundColor = "red";
if (array[j] < array[idxContainer.idx])
idxContainer.idx = j;
innerLoopHelper(++j, idxContainer, barArr);
}, 100);
}
}
I know this is a long post, but I just wanted to be as specific as possible. Thank you so much for reading, and any guidance will be appreciated!
Convert your sorting function to a generator function*, this way, you can yield it the time you update your rendering:
const sorter = selectionSortAnimated();
const array = Array.from( { length: 100 }, ()=> Math.round(Math.random()*50));
const max_element = 50;
renderVisualizer();
anim();
// The animation loop
// simply calls itself until our generator function is done
function anim() {
if( !sorter.next().done ) {
// schedules callback to before the next screen refresh
// usually 60FPS, it may vary from one monitor to an other
requestAnimationFrame( anim );
// you could also very well use setTimeout( anim, t );
}
}
// Converted to a generator function
function* selectionSortAnimated() {
const barContainer = document.getElementById("bar-container");
const barArr = barContainer.children;
for (let i = 0; i < barArr.length - 1; i++) {
let min_idx = i;
let minNum = parseInt(barArr[i].textContent);
for (let j = i + 1; j < barArr.length; j++) {
let jNum = parseInt(barArr[j].textContent, 10);
if (jNum < minNum) {
barArr[min_idx].classList.remove( 'selected' );
min_idx = j;
minNum = jNum;
barArr[min_idx].classList.add( 'selected' );
}
// highlight
barArr[j].classList.add( 'checking' );
yield; // tell the outer world we are paused
// once we start again
barArr[j].classList.remove( 'checking' );
}
barArr[min_idx].classList.remove( 'selected' );
barContainer.insertBefore(barArr[i], barArr[min_idx])
barContainer.insertBefore(barArr[min_idx], barArr[i]);
// pause here too?
yield;
}
}
// same as OP
function renderVisualizer() {
const barContainer = document.getElementById("bar-container");
//Empties bar-container div
while (barContainer.hasChildNodes()) {
barContainer.removeChild(barContainer.lastChild);
}
var heightMult = barContainer.offsetHeight / max_element;
var temp = barContainer.offsetWidth / array.length;
var barWidth = temp * 0.9;
var margin = temp * 0.05;
//Creating array element bars
for (var i = 0; i < array.length; i++) {
var arrayBar = document.createElement("div");
arrayBar.className = "array-bar"
if (barWidth > 30)
arrayBar.textContent = array[i];
//Style
arrayBar.style.textAlign = "center";
arrayBar.style.height = array[i] * heightMult + "px";
arrayBar.style.width = barWidth;
arrayBar.style.margin = margin;
barContainer.appendChild(arrayBar);
}
}
#bar-container {
height: 250px;
white-space: nowrap;
width: 3500px;
}
.array-bar {
border: 1px solid;
width: 30px;
display: inline-block;
background-color: #00000022;
}
.checking {
background-color: green;
}
.selected, .checking.selected {
background-color: red;
}
<div id="bar-container"></div>
So I thought about this, and it's a little tricky, what I would do is just store the indexes of each swap as you do the sort, and then do all of the animation seperately, something like this:
// how many elements we want to sort
const SIZE = 24;
// helper function to get a random number
function getRandomInt() {
return Math.floor(Math.random() * Math.floor(100));
}
// this will hold all of the swaps of the sort.
let steps = [];
// the data we are going to sort
let data = new Array(SIZE).fill(null).map(getRandomInt);
// and a copy that we'll use for animating, this will simplify
// things since we can just run the sort to get the steps and
// not have to worry about timing yet.
let copy = [...data];
let selectionSort = (arr) => {
let len = arr.length;
for (let i = 0; i < len; i++) {
let min = i;
for (let j = i + 1; j < len; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if (min !== i) {
let tmp = arr[i];
// save the indexes to swap
steps.push({i1: i, i2: min});
arr[i] = arr[min];
arr[min] = tmp;
}
}
return arr;
}
// sort the data
selectionSort(data);
const container = document.getElementById('container');
let render = (data) => {
// initial render...
data.forEach((el, index) => {
const div = document.createElement('div');
div.classList.add('item');
div.id=`i${index}`;
div.style.left = `${2 + (index * 4)}%`;
div.style.top = `${(98 - (el * .8))}%`
div.style.height = `${el * .8}%`
container.appendChild(div);
});
}
render(copy);
let el1, el2;
const interval = setInterval(() => {
// get the next step
const {i1, i2} = steps.shift();
if (el1) el1.classList.remove('active');
if (el2) el2.classList.remove('active');
el1 = document.getElementById(`i${i1}`);
el2 = document.getElementById(`i${i2}`);
el1.classList.add('active');
el2.classList.add('active');
[el1.id, el2.id] = [el2.id, el1.id];
[el1.style.left, el2.style.left] = [el2.style.left, el1.style.left]
if (!steps.length) {
clearInterval(interval);
document.querySelectorAll('.item').forEach((el) => el.classList.add('active'));
}
}, 1000);
#container {
border: solid 1px black;
box-sizing: border-box;
padding: 20px;
height: 200px;
width: 100%;
background: #EEE;
position: relative;
}
#container .item {
position: absolute;
display: inline-block;
padding: 0;
margin: 0;
width: 3%;
height: 80%;
background: #cafdac;
border: solid 1px black;
transition: 1s;
}
#container .item.active {
background: green;
}
<div id="container"></div>
The pictures change themselves every 3 seconds.
I would like to add simple animation to the photo during the change.
Preferably in vaniilla js.
let index = 1;
const changeImg = () => {
index++;
img.setAttribute('src', `img/img${index}.png`);
if (index === 3) {
index = 0;
}
};
setInterval(changeImg, 3000);
If you use something like animate.css, or create your own animation class you could do it like this:
(Im assuming you're getting the image by a query selector/getElementById)
let index = 1;
const changeImg = () => {
index++;
img.classList.add('animate__animated');
img.classList.add('animate__bounce');
setTimeout(() => {
img.setAttribute('src', `img/img${index}.png`);
img.classList.remove('animate__animated');
img.classList.remove('animate__bounce');
}, 300); // This delay is assuming the animation duration is 300ms, you need to change this to the length of the animation
if (index === 3) {
index = 0;
}
};
setInterval(changeImg, 3000);
As you suggested an example in vanilla JavaScript (no libraries), here you go.
(function slideShow() {
let imgs = [
"https://picsum.photos/id/237/200/300",
"https://picsum.photos/id/238/200/300",
"https://picsum.photos/id/239/200/300"
];
let index = 0;
const frontImg = document.getElementById("slideshow__img--front");
const backImg = document.getElementById("slideshow__img--back");
frontImg.src = imgs[index];
const changeSlideShowImg = () => {
const currImgSrc = imgs[index];
index++;
if (index >= imgs.length) index = 0;
const newImgSrc = imgs[index];
backImg.src = newImgSrc;
frontImg.classList.add("slideshow__img--fadeout");
setTimeout(() => {
frontImg.src = newImgSrc;
frontImg.classList.remove("slideshow__img--fadeout");
}, 500);
};
setInterval(changeSlideShowImg, 3000);
})()
.slideshow {
width: 200px;
height: 300px;
position: relative;
}
.slideshow__img {
position: absolute;
left: 0;
top: 0;
opacity: 1;
}
#slideshow__img--front {
z-index: 2;
}
.slideshow__img.slideshow__img--fadeout {
transition: opacity 0.5s ease-in;
opacity: 0;
}
<div class="slideshow">
<img id="slideshow__img--front" class="slideshow__img" />
<img id="slideshow__img--back" class="slideshow__img" />
</div>
im trying to create a automatic image slider which also responds to an onclick function, for some odd reason the onclick event is pretty much doing nothinig i suspect its cause of the settime out as javascript is single threaded but im no master at javascript! could someone please tell me what i'm doing wrong stuck with this for the past two days! thank you!
var i = 0;
var starterimages= [];
var time = 3000;
var eventaction=0;
var timeoutId;
starterimages[0] = "https://i.pinimg.com/236x/f4/92/39/f492399e154bd9f564d7fc5299c19911--purple-rain-deep-purple.jpg";
starterimages[1] = "https://image.shutterstock.com/image-photo/purple-butterfly-isolated-on-white-260nw-44004850.jpg";
starterimages[2] = "https://www.birdscanada.org/images/inbu_norm_q_townsend.jpg";
var nextbutton=document.querySelector("#rightbutton");
nextbutton.addEventListener("click",rightbuttonclick);
var prevbutton=document.querySelector("#leftbutton");
nextbutton.addEventListener("click",leftbuttonclick);
function rightbuttonclick()
{
eventaction=1;
clearTimeout(timeoutId);
}
function leftbuttonclick()
{
eventaction=2;
clearTimeout(timeoutId);
}
function changeImg(){
document.getElementById('startersliders').src = starterimages[i];
if(eventaction==1)
{
i++;
if(i < starterimages.length - 1)
{document.getElementById('startersliders').src = starterimages[i];
eventaction=0;}
else
{
i=0;
document.getElementById('startersliders').src = starterimages[i];
eventaction=0;
}
}
else if(eventaction==2)
{
i--;
if(i== - 1)
{
i=3;
document.getElementById('startersliders').src = starterimages[i];
eventaction=0;
}
else
{
document.getElementById('startersliders').src = starterimages[i];
eventaction=0;
}
}
else if(eventaction==0){
if(i < starterimages.length - 1){
i++;
}
else {
i = 0;
}
}
// Run function every x seconds
timeoutId = setTimeout("changeImg()", time);
}
// Run function when page loads
window.onload=changeImg;
#staratersliders {
width: 10%;
height: 10%;
position: relative;
margin: 0% 0% 0% 0%;
}
<button class="button button3" id="leftbutton"> previous</button>
<img id="startersliders" />
<button class="button button3" id="rightbutton">next</button>
I got it all working in Firefox 51, buttons included. Just paste the whole thing in a blank page and save it with an .htm or .html extension.
<!DOCTYPE=HTML><html><meta charset="UTF-8">
<script>
var i = 0;
var starterimages= [];
var time = 3000;
var eventaction=0;
var timeoutId;
starterimages[0] = "https://i.pinimg.com/236x/f4/92/39/f492399e154bd9f564d7fc5299c19911--purple-rain-deep-purple.jpg";
starterimages[1] = "https://image.shutterstock.com/image-photo/purple-butterfly-isolated-on-white-260nw-44004850.jpg";
starterimages[2] = "https://www.birdscanada.org/images/inbu_norm_q_townsend.jpg";
function rightbuttonclick() {
eventaction = 1;
clearTimeout(timeoutId);
changeImg();
}
function leftbuttonclick() {
eventaction = 2;
clearTimeout(timeoutId);
changeImg();
}
function changeImg() {
if (eventaction == 1) {
if (i < starterimages.length - 1) {
i++;
document.getElementById('startersliders').src=starterimages[i];
eventaction = 0;
} else {
i = 0;
document.getElementById('startersliders').src=starterimages[i];
eventaction = 0;
}
} else if (eventaction == 2) {
i--;
if (i < 0) {
i = 2;
document.getElementById('startersliders').src=starterimages[i];
eventaction = 0;
} else {
document.getElementById('startersliders').src=starterimages[i];
eventaction = 0;
}
} else {
if (i < starterimages.length - 1) {
i++;
} else {
i = 0;
};
document.getElementById('startersliders').src=starterimages[i];
eventaction = 0;
}
timeoutId=setTimeout("changeImg()", time);
}
</script>
<style>
#startersliders {width: 10%;height: 10%;position: relative;margin: 0% 0% 0% 0%;}
</style>
<body onload="changeImg();">
<button class="button button3" id="leftbutton">previous</button>
<img id="startersliders">
<button class="button button3" id="rightbutton">next</button>
<script>
var nextbutton=document.querySelector("#rightbutton");
nextbutton.addEventListener("click",rightbuttonclick);
var prevbutton=document.querySelector("#leftbutton");
prevbutton.addEventListener("click",leftbuttonclick);
</script>
</body>
</html>
It won't work because this:
setTimeout("changeImg()", time);
Is invalid syntax for setTimeout. To fix it, just do this:
setTimeout(changeImg, time);
var nextbutton=document.querySelector("#rightbutton");
nextbutton.addEventListener("click",rightbuttonclick);
var prevbutton=document.querySelector("#leftbutton");
nextbutton.addEventListener("click",leftbuttonclick);
I copy/pasted the code into my machine and the above came up null because they need to be between script tags at the bottom of the body of the doc.
When the parser sees those at the top, it doesn't know what #rightbutton and #leftbutton are because it hasn't parsed the html in the body section yet so it comes back as a null element
just move them to the bottom of the body section after the html and put script /script tags around them and see what happens
You need to do both of the above, what Matthew Herbst said is correct and what Jack Bashford said is correct. Create a variable for the setTimeout
var mytimeinverval;
var mytimer;
mytimer=setTimeout(myfunctionname,mytimeinterval);
The function name inside the setTimeout doesn't get quotes or parenthesis.
If you put parenthesis in, it might fire instantly or who knows?
It still recognizes myfunctionname as a function without the parenthesis.
Putting quotes around it makes it a string-won't work in my experience.
I don't want credit, they answered it, just letting you know to do both.
I am trying to make my selector so when it gets the class of transform with the tagname with p, it will do some event in my case it is mouse hovering but i am having trouble with it.
I know there are jquery solutions but i am doing it with pure javascript. here is the code below currently
var hoverEvent = document.getElementsByTagName("p").getElementsByClassName("transform");
for (let i = 0; i < hoverEvent .length; i++) {
hoverEvent [i].onmouseover=function() {
this.style.color = "yellow";
// changes paragraph with class of transform to yellow during hover
}
} // end for
for (let i = 0; i < hoverEvent .length; i++) {
hoverEvent [i].onmouseout=function() {
this.style.color = "black";
// changes it back to black
}
}
You can use a CSS selector in querySelectorAll to find all paragraphs with that classname:
var hoverEvent = document.querySelectorAll("p.transform");
var transformPs = document.querySelectorAll("p.transform");
for (let i = 0; i < transformPs .length; i++) {
// on mouse over
transformPs[i].onmouseover = function () {
this.style.color = "yellow";
// changes paragraph with class of transform to yellow during hover
};
// on mouse out
transformPs[i].onmouseout = function () {
this.style.color = "black";
// changes it back to black
};
}
you can use classList to check class of element
var p = document.getElementsByTagName("p");
if (p.classList.contains('transform')){
// do whatever you want to do
}
The vanilla JavaScript equivalent would be using document.querySelectorAll:
function turnYellow (e) { e.target.style.color = 'yellow' }
function turnBlack (e) { e.target.style.color = '' }
document.querySelectorAll('p.transform').forEach(function (p) {
p.addEventListener('mouseover', turnYellow)
p.addEventListener('mouseout', turnBlack)
})
body { background: #ccc; }
<p class="transform">Example Paragraph</p>
However, I think the best approach would be to forego the JavaScript altogether and instead rely on the CSS pseudo-selector :hover:
body { background: #ccc; }
p.transform:hover {
color: yellow;
}
<p class="transform">Example Paragraph</p>