I have this javascript that outputs an action to the elements on class="link_mainhub"
<script>
const el = document.querySelector('.link_mainhub')
const fx = new TextScramble(el)
let counter = 0
const next = () => {
fx.setText(phrases[counter]).then(() => {
setTimeout(next, 800)
})
counter = (counter + 1) % phrases.length
}
next()
</script>
However, I just want to run the script whenever class="link_mainhub" is hovered.
I tried changing the const el = document.querySelector('.link_mainhub') to const el = document.querySelector('.link_mainhub:hover') but it didn't work.
How can I reproduce the script only when my class is being hovered?
Thanks.
Why not add eventListener of Mouseover to the element.
el.addEventListener('mouseOver', next)
Related
hi everyone!
i have a map with dots MAP which every 3 seconds shows a block with info
a function that is already in progress, and I want the function to stop when clicking on a point and display an infoblock for me(and i did it).
sorry in advance below is my code
// map with dots
var isActive = 0;
var isLoading = 1;
const count = document.querySelectorAll("[data-id]");//circle svg around dot
function removeClass() {
let infoCards = document.querySelectorAll("[data-info-id]");// info page name of the project
infoCards.forEach((el) => {
el.classList.remove("show");
});
}
function removeCircle() {
count.forEach((el) => {
el.style.display = "none";
});
}
function ready() {
function setAround(percent, idx) {
removeCircle();
let beforeElemIdx = idx === 0 ? count.length - 1 : idx - 1;
let beforeElem = document.querySelector(
'[data-id="' + beforeElemIdx + '"]'
);
let elem = document.querySelector('[data-id="' + idx + '"]');
elem.style.display = "block";
elem.classList.remove('active-circle');
beforeElem.style.display = "block";
const math = 2 * Math.PI * elem.r.baseVal.value;
elem.style.strokeDasharray = `${math} 1000`;
let a = math * (1 - percent / 100);
elem.style.strokeDashoffset = a;
if (percent >= 99.5) {
removeClass();
let infoShow = document.querySelector(`[data-info-id="${idx}"]`);
infoShow.classList.add("show");
isLoading++;
if (isLoading === count.length) {
isLoading = 0;
}
}
}
requestAnimationFrame(draw);
function draw(t) {
let idx = isLoading;
requestAnimationFrame(draw);
setAround((t / 30) % 100, idx);//timer 3sec
}
}
document.addEventListener("DOMContentLoaded", ready);
and i did this
var dots = document.querySelectorAll(".dota");
var infoCards = document.querySelectorAll("[data-info-id]");
let circle = document.querySelectorAll('[data-id]');
dots.forEach((el) => {
el.addEventListener('click', () => {
let idx = el.dataset.dota;
let circle = el.dataset.dota;
showInfo(idx);
addCircle(idx);
});
});
function showInfo(idx) {
removeClass();
let elem = document.querySelector(`[data-info-id='${idx}']`);
elem.classList.add('show');
}
function addCircle(idx) {
let circle = document.querySelector(`[data-id='${idx}']`);
circle.classList.add('active-circle');
}
and if u want my site pls dm me i'll send my github page
PUG CODE
TY ALL!
Have you tried making a condition into the drawing function that pauses it?
If it's paused you can call another function that will draw the info of the specific dot only once and then create a condition in which it will resume the drawing normally.
When I used drawing function I've simply added a bool variable that stored if paused or not in the recursive function.
I want to make the links in my navbar have an active class when you scroll into the corresponding section.
The code below was working just fine until I implemented a smooth scroll/parallax library which removes the scroll event.
I tried making the code work using the wheel event, tried seeing if there was anything similar to scrollY for wheel events but I couldn't find anything.
Any ideas on how I could implement this feature? It can be different from the implementation I had before
EDIT: Here's a codepen. If you uncomment the locomotive portion, the code no longer works. How can I make it work?
const sections = document.querySelectorAll("section");
const navLinks = document.querySelectorAll("nav a");
window.addEventListener("scroll", function () {
let navbar = document.querySelector("nav");
let current = "";
sections.forEach(function (section) {
const sectionTop = section.offsetTop;
const sectionHeight = section.clientHeight;
if (scrollY >= sectionTop - sectionHeight / 3) {
current = `#${section.getAttribute("id")}`;
}
navLinks.forEach(function (each) {
// add/remove active class
each.classList.remove("nav-active");
if (each.getAttribute("href") == current) {
each.classList.add("nav-active");
}
});
});
});
Try using an IntersectionObserver instead:
const navLinks = document.querySelectorAll("nav a");
const updateNav = (entries, observer) => {
const matchingIds = entries.filter(e => e.isIntersecting).map(e => `#${e.target.id}`);
if (matchingIds.length !== 0) {
const current = matchingIds[0];
navLinks.forEach(function(link) {
link.classList.remove("nav-active");
if (link.getAttribute("href") == current) {
link.classList.add("nav-active");
}
});
}
};
const options = {
root: null,
rootMargin: "0px",
threshold: 0.66
}
const observer = new IntersectionObserver(updateNav, options);
document.querySelectorAll("*[data-scroll-section]").forEach(el => observer.observe(el));
Intersection Observer API
Demo
According to the HTML Standart in the event loop during updateing the rendering 2 things happen sequentially:
For each fully active Document in docs, run the scroll steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
For each fully active Document in docs, run the animation frame callbacks for that Document, passing in now as the timestamp.
Therefore I suppose that IF before the event loop run both
a scroll happens (via scrollTop or scrollLeft property of a scrollable element change or scrollTo execution)
a callback scheduled via requestAnimationFrame
THEN there should be at least one scroll event for each scrolled element in any event loop run,and callbacks execution always happens after scroll event listeners.
I wrote a function that checks this proposition and tried it in Chrome and FireFox:
function Test(iterations, stepTimeout) {
let xOuter = document.createElement("div");
xOuter.style.width = "100px";
xOuter.style.height = "100px";
xOuter.style.overflow = "scroll";
//xOuter.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
xOuter.style.zIndex = "10000";
xOuter.style.position = "absolute";
xOuter.style.top = "0";
xOuter.style.left = "0";
xOuter.style.scrollBehavior = "auto";
let xInner = document.createElement("div");
xInner.style.width = "200%";
xInner.style.height = "200%";
xOuter.appendChild(xInner);
let xState = "What happens during each interation of Step:\n";
let xStepIndex = 0,
xScrollUpdateIndex = 0,
xLastExecutedScrollUpdate = -1;
xOuter.addEventListener("scroll", () => {
xState += `scroll-${xScrollUpdateIndex} `;
xLastExecutedScrollUpdate = xScrollUpdateIndex;
});
document.body.appendChild(xOuter);
function Step() {
if (xStepIndex > iterations) {
xOuter && xOuter.parentNode && xOuter.parentNode.removeChild(xOuter);
console.log(xState);
return;
}
let xScrollProp = Math.random() > 0.5 ? "scrollLeft" : "scrollTop";
let xOldScrollPos = xOuter[xScrollProp],
xNewScrollPos;
do {
xNewScrollPos = Math.round(Math.random() * 200);
} while (xOldScrollPos == xNewScrollPos);
xState += `\n ${xStepIndex++} : [${xNewScrollPos}] `;
xOuter[xScrollProp] = xNewScrollPos; // scroll event scheduled
xScrollUpdateIndex++;
let xCurrentScrollUpdateIndex = xScrollUpdateIndex;
requestAnimationFrame(() => {
if (xCurrentScrollUpdateIndex > xLastExecutedScrollUpdate)
console.log("Scroll failed to fire before rAF");
xState += `rAF-${xCurrentScrollUpdateIndex} `;
});
new Promise((resolve) => setTimeout(() => resolve(), stepTimeout)).then(Step);
}
Step();
}
Test(200, 10);
However it looks like in some event loop runs scroll event doesn't fire.
Is this an expected behavior?
I'm creating a product hover effect where I used mouseover and mouseleave functions. However, I'm currently having problems with the clearInterval function on Javascript.
Do I miss on something? The structure is also aligned.
Here's my code:
<script>
document.addEventListener("DOMContentLoaded", ()=>{
// //get img url from span
// const src = spanElem.attr('data-original');
// //change span to img using the value from data-original
// spanElem.replaceWith('<img class="product-img-toadd w3-animate-fading" src="' + src + '"/>');
const imgGallery = document.querySelectorAll('.product-img-gallery');
const imageDiv = document.querySelectorAll('.product-tile__image');
let interval
imageDiv.forEach(el=>{
//img
const imgGalleryItem = el.querySelectorAll('.product-img-gallery__item')
el.addEventListener("mouseenter", ()=>{
imgGalleryItem.forEach(item=>{
const src = item.getAttribute('data-original')
const img = `<img class="product-img-toadd w3-animate-fading" src="${src}"/>`
item.insertAdjacentHTML('beforeend',img)
//slider
const imgSlides = el.querySelectorAll('.product-img-toadd');
let currentIndex = 0
interval = setInterval(() => {
imgSlides.forEach((item) => {
item.style.opacity = 0;
});
imgSlides[currentIndex].style.opacity = 1;
if (currentIndex === imgSlides.length - 1) {
currentIndex = 0;
} else {
currentIndex = currentIndex + 1;
}
console.log("tick")
}, 750);
})
})
el.addEventListener("mouseleave", ()=>{
const imgSlides = el.querySelectorAll('.product-img-toadd');
imgSlides.forEach((item) => {
item.style.opacity = 0;
});
clearInterval(interval);
})
})
})
You're assiging interval in a loop, overriding each previous element with the next.
A possible solution would be to push each interval to a array, then iterate through all elements and clear it's elements.
let intervals = [];
intervals.push( setInterval(() => { ... });
...
intervals.forEach((iv) => clearInterval(iv));
I am just playing around with the setInterval function in JavaScript.
I am wondering if there is a way to toggle the setInterval with an HTML button
This is my code.
let x = 0;
const listener = document.getElementById('listener');
const numberPlace = document.getElementById('numberPlace');
const numberCounter = setInterval(() => {
x++;
numberPlace.innerHTML = x;
}, 100);
listener.addEventListener('click', numberCounter);
The problem is that the number starts counting when the page loads and not on a button click.
Please help
const numberCounter = () => setInterval(() => {
x++;
numberPlace.innerHTML = x;
}, 100);
setInterval can be cancelled using clearInterval and the integer identifier returned when setInterval was called.
To toggle a setInterval-based counter, you simply need to toggle on the presence (or absence) of this identifier.
let counter = 0;
let intervalId = null;
const btn = document.getElementById('btn');
const numberPlace = document.getElementById('numberPlace');
const numberCounter = () => intervalId === null
? intervalId = setInterval(() => numberPlace.innerHTML = ++counter, 100)
: (clearInterval(intervalId), intervalId = null)
btn.addEventListener('click', numberCounter);
<button id="btn">toggle</button>
<div id="numberPlace"></div>